programing

PyCharm이 가변 기본 인수에 대해 경고하는 이유는 무엇입니까?어떻게 하면 그들을 피할 수 있을까요?

cafebook 2023. 7. 22. 10:24
반응형

PyCharm이 가변 기본 인수에 대해 경고하는 이유는 무엇입니까?어떻게 하면 그들을 피할 수 있을까요?

3하고 있습니다.attachment={}.

def put_object(self, parent_object, connection_name, **data):
    ...

def put_wall_post(self, message, attachment={}, profile_id="me"):
    return self.put_object(profile_id, "feed", message=message, **attachment)

에서는 IDE 에서,attachment={}노란색입니다.마우스를 이동하면 경고가 표시됩니다.

기본 인수 값은 가변입니다.

이 검사는 목록 또는 사전과 같은 변수 값이 인수의 기본값에서 탐지되는 경우를 탐지합니다.

기본 인수 값은 함수 정의 시간에 한 번만 평가됩니다. 즉, 인수의 기본값을 수정하면 이후 함수의 모든 호출에 영향을 미칩니다.

이것은 무엇을 의미하며 어떻게 해결할 수 있습니까?

"mutable default 인수"를 변경하지 않거나 변경할 수 있는 위치에 전달할 경우 메시지를 무시하십시오. "수정"할 내용이 없기 때문입니다.

당신의 경우, 당신은 "변종 기본 인수"의 압축만 풀어서(암묵적으로 당신은 안전합니다.

그 경고 메시지를 제거, 은 " 당경메하제를거지있다"를 사용할 수 .None하고 이 합니다.{}None:

def put_wall_post(self,message,attachment=None,profile_id="me"):
    if attachment is None:
        attachment = {}

    return self.put_object(profile_id,"feed",message = message,**attachment)

하자면: 입니다(" 미를설명자면하의불변유: 파의일은형부이썬불▁just변(은유를형"▁imm일").int,str가능합니다.dict,set,list할 수 가 생성됩니다. 할 수 개체를

까다로운 부분은 함수가 로드될 때(그리고 한 번만) 클래스 변수와 기본 인수가 생성된다는 것입니다. 즉, "mutable default argument" 또는 "mutable class variable"에 대한 모든 변경이 영구적이라는 것을 의미합니다.

def func(key, value, a={}):
    a[key] = value
    return a

>>> print(func('a', 10))  # that's expected
{'a': 10}
>>> print(func('b', 20))  # that could be unexpected
{'b': 20, 'a': 10}

PyCharm은 실수로 잘못 이해하기 쉽기 때문에 이 경고를 표시할 수 있습니다(예: 함수 호출과 연결된 모든 질문 사이의 돌연변이를 왜 mutable default 인수가 기억하는가? 참조).그러나 의도적으로 한 경우(변량 함수 인수 기본값에 대한 유용한 사용?)경고는 성가실 수 있습니다.

를 변수기 본다바꿀수있습으로 대체할 수 .None그런 다음 함수 내부를 확인하고 기본값을 할당합니다.

def put_wall_post(self, message, attachment=None, profile_id="me"):
    attachment = attachment if attachment else {}

    return self.put_object(profile_id, "feed", message=message, **attachment)

이는 다음과 같은 이유로 작동합니다.None으로 됩니다.False그래서 우리는 빈 사전을 할당합니다.

일반적으로 다음을 명시적으로 확인할 수 있습니다.None도 른다가평수있할듯이가로 평가할 수 있기 에.False를 들어, 예를 들어, 기호입니다.0,'',set(),[]등이 전부입니다.False-y기값이않경이 아닌 .0그리고 지금은5예를 들어, 그러면 당신은 짓밟고 싶지 않을 것입니다.0유효한 매개 변수로 전달:

def function(param=None):
    param = 5 if param is None else param

이는 기본 인수가 가변적이기 때문에 내부에서 수정할 경우 기본값을 변경하게 되어 경우에 따라 예기치 않은 결과를 초래할 수 있다는 인터프리터의 경고입니다.기본 인수는 지정한 개체에 대한 참조일 뿐입니다. 예를 들어, 두 개의 다른 식별자에 목록의 별칭을 지정할 때와 같습니다.

>>> a={}
>>> b=a
>>> b['foo']='bar'
>>> a
{'foo': 'bar'}

함수에 대한 호출 중이든, 별도의 호출 중이든, 함수 외부의 호출 중이든 참조를 통해 객체가 변경되면 이후의 함수 호출에 영향을 미칩니다.런타임에 함수의 동작이 변경될 것으로 예상하지 않으면 버그가 발생할 수 있습니다.함수가 호출될 때마다 동일한 개체에 바인딩되는 동일한 이름입니다.(사실, 매번 전체 이름 바인딩 과정을 거치는지조차 잘 모르겠습니다.그냥 다른 참조를 얻는 것 같습니다.)

(원하지 않을 가능성이 높은) 동작

다음을 선언하고 몇 번 호출하면 이 결과를 확인할 수 있습니다.

>>> def mutable_default_arg (something = {'foo':1}):
    something['foo'] += 1
    print (something)


>>> mutable_default_arg()
{'foo': 2}
>>> mutable_default_arg()
{'foo': 3}

무엇이 기다리니?예, 인수에서 참조하는 개체는 호출 간에 변경되지 않으므로 해당 요소 중 하나를 변경하면 기본값이 변경됩니다.만약 여러분이 불변의 유형을 사용한다면, 표준적인 상황에서 불변의 데이터를 변경하는 것이 가능하지 않을 것이기 때문에 이것에 대해 걱정할 필요가 없습니다.이것이 사용자 정의 클래스에 적용되는지는 모르겠지만, 이것이 일반적으로 "없음"으로 처리되는 이유입니다(자리 표시자로만 필요하며 더 이상 필요하지 않습니다).추가 RAM을 더 복잡한 작업에 사용하는 이유는 무엇입니까?)

덕트 테이프 문제...

당신의 경우, 다른 답변이 지적한 것처럼 암묵적인 복사에 의해 당신은 구원을 받았지만, 암묵적인 행동, 특히 예상치 못한 암묵적인 행동에 의존하는 것은 결코 좋은 생각이 아닙니다. 왜냐하면 그것은 바뀔 수 있기 때문입니다.그것이 우리가 "묵시적인 것보다 명시적인 것이 낫다"고 말하는 이유입니다.게다가, 암묵적인 행동은 무슨 일이 일어나고 있는지 숨기는 경향이 있으며, 이것은 당신이나 다른 프로그래머가 덕트 테이프를 제거하도록 이끌 수 있습니다.

...단순한(영구적인) 솔루션으로

이 자석을 피하고 다른 사람들이 제안한 처럼 른다사람것다같불유음은변사형의과다용을이있니수와 같은 시킬 수 .None기능이 시작될 때 확인하고, 발견되면 기능이 시작되기 전에 즉시 교체합니다.

def put_wall_post(self, message, attachment=None, profile_id="me"):
    if attachment is None:
        attachment = {}
    return self.put_object(profile_id, "feed", message=message, **attachment)

변경할 수 없는 형식은 형식을 바꾸어야 하므로 기술적으로 새 개체를 동일한 이름으로 바인딩합니다.위에서 첨부 파일이 새 사전으로 되돌아갈 때 없음에 대한 참조는 업데이트하는 대신 덮어씁니다.attachment항상 다음과 같이 시작합니다.None호출 매개 변수에 지정되지 않은 경우 기본값이 예기치 않게 변경될 위험을 방지할 수 있습니다.

(따라서, 어떤 물체가 다른 물체와 동일한지 의심스러울 때, 그것들을 비교합니다.is 또는체를 확인합니다.id(object)전자는 두 참조가 동일한 개체를 참조하는지 여부를 확인할 수 있으며, 후자는 개체에 대한 고유 식별자(일반적으로 메모리 위치)를 인쇄하여 디버깅에 유용할 수 있습니다.

경고를 다시 설명하자면, 이 함수에 대한 모든 호출은 기본값을 사용하는 경우 동일한 개체를 사용합니다.당신이 그 물체를 절대 바꾸지 않는 한, 그것이 불변이라는 사실은 중요하지 않을 것입니다.그러나 이 값을 변경하면 다음 호출이 수정된 값으로 시작됩니다. 이 값은 사용자가 원하는 값이 아닐 수 있습니다.

한 을 "없음과 같은 변수를 " 이문제방기위한기해없본"로 설정하는 입니다.{}기본값을 사용하는 경우:

def put_wall_post(self,message,attachment=None,profile_id="me"):
    if attachment==None:
        attachment={}
    return self.put_object(profile_id,"feed",message = message,**attachment)
  • 목록은 가변적이며 컴파일 시 default 선언으로 기본값을 선언하면 특정 주소의 변수에 가변적 목록이 할당됩니다.

    def abc(a=[]):
        a.append(2)
        print(a)
    
    abc() #prints [2]
    abc() #prints [2, 2] as mutable thus changed the same assigned list at func delaration points to same address and append at the end
    abc([4]) #prints [4, 2] because new list is passed at a new address
    abc() #prints [2, 2, 2] took same assigned list and append at the end 
    

     

  • 이 문제 해결 방법:

    def abc(a=None):
         if not a:
             a=[]
         a.append(2)
         print(a)
    

     

    • 새 목록이 생성될 때마다 작동하며 이전 목록을 항상 null 값으로 참조하지 않으므로 새 주소에 새 목록을 할당합니다.

PyCharm은 기본 인수가 mutable이라고 경고합니다. 이는 둔해 보일 수 있지만 기본 인수를 사용하여 만든 개체는 모두 하나의 기본 인수에 대해 동일한 참조를 공유합니다.

다음은 이 문제를 보여주는 코드입니다.

class foo:
def __init__(self, key, stuff: list = []):
    self.key = key
    self.stuff = stuff

def __str__(self):
    return f"{self.key} :: {self.stuff}"

def add_item(self, item):
    self.stuff.append(item)

그런 다음 각 항목에 대한 새 목록을 제공하지 않고 foo 클래스의 몇 개 인스턴스를 만들면 각 인스턴스가 동일한 기본 목록에 대한 참조를 공유합니다!

a = foo('a')
b = foo('b')
print(a, b)
a.add_item(1)
a.add_item(2)
print(a, b)

>>> a :: [] b :: []
>>> a :: [1, 2] b :: [1, 2]

항목을 항목 목록에 추가한 것을 볼 수 있습니다.a 두 두 로 두 번째로 를 할 는 두째로두사진찍으을면로번째번,▁the▁but찍면으▁the▁instances▁i▁two▁when.b또한 두 개의 아이템이 들어 있습니다. 사실 그것은 같은 두 아이템입니다!

하고 이제문를해가좋방코조법드변은금기다것경입니제는을공하본값고하만를은장결을 제공하는 것입니다.None기본값으로 다음을 사용합니다.or생성자 내부의 새 목록과 결합하려면 다음과 같습니다.

class foo:
def __init__(self, key, stuff: list = None):
    self.key = key
    self.stuff = stuff or []  # this will be a new list[]

이제 우리가 a와 b의 구성을 반복하고 이전과 똑같이 a에 물건을 더하면, 우리는 다른 결과를 얻습니다.

>>> a :: [] b :: []     # before adding stuff
>>> a :: [1, 2] b :: [] # after adding stuff to a,  b is still empty!

그 이유는 그 인스턴스이기 때문입니다.a 그고그경우리.b 목록에 가 " " " (으)로 표시됨", "" "" ""일 때 된 새 합니다.init이알화된python은 포인터와 참조의 추악함의 대부분을 숨기고 있지만, 그들은 여전히 비밀리에 존재하고 때때로 우리는 여전히 그것들을 인식할 필요가 있습니다.기본값으로 값(예: stuff=[]이 아닌 stuff=1)을 제공하면 값 자체가 참조가 아닌 인스턴스에 배치되기 때문에 이러한 문제가 발생하지 않습니다.

언급URL : https://stackoverflow.com/questions/41686829/why-does-pycharm-warn-about-mutable-default-arguments-how-can-i-work-around-the

반응형