2017-05-03 1 views
2

저는 독학 프로그래머입니다. 저는 최근에 파이썬을 배웠습니다. 이상한 문제가 발생했지만 파이썬 구문 및/또는 프로그램 흐름을 알지 못하는 결과라고 생각합니다.Python 클래스 인스턴스 변수 분리

TestClass.py 파일에 이라는 클래스가 있습니다. `

class Test: 

    __tags = {} 
    __fields = {} 

    def __init__(self, tags: dict={}, fields: dict={}): 
     self.__tags = tags 
     self.__fields = fields 

    def setTag(self, key, value): 
     self.__tags[key] = value 

    def getTag(self, key): 
     return self.__tags[key] 

    def setField(self, key, value): 
     self.__fields[key] = value 

    def getField(self, key): 
     return self.__fields[key] 


    def getAll(self): 
     return [ 
      { 
       'tags': self.__tags, 
       'fields': self.__fields 
      } 
     ] 

내가 절차 적 코드가 포함 된 파일이 클래스의 기능을 테스트하고, 상황이 이상한 얻을 곳

import TestClass 

t1 = TestClass.Test() 
t1.setTag('test1', 'value1') 
t1.setField('testfield', 'fieldvalue') 

t2 = TestClass.Test() 
t2.setTag('test2', 'value2') 

print(t1.getAll()) 
print(t2.getAll()) 

printtest.py이다.

[{'tags': {'test1': 'value1'}, 'fields': {'testfield': 'fieldvalue'}}] 
[{'tags': {'test2': 'value2'}, 'fields': {}}] 

그러나 실제 출력은 ... 왜 그러나

[{'tags': {'test2': 'value2', 'test1': 'value1'}, 'fields': {'testfield': 'fieldvalue'}}] 
[{'tags': {'test2': 'value2', 'test1': 'value1'}, 'fields': {'testfield': 'fieldvalue'}}] 

입니다 : 출력 가되어야 하는가?

편집 : 파이썬 3.5

답변

3

당신은 하나가 아닌었지만 두 파이썬은 잘 이민자를위한 "트랩"이라고도합니다.

이 동작이 예상되고, 그것을 해결하기 위해, 당신이 당신의 클래스 선언의 시작을 변경해야합니다 : 이제 "왜 그렇게?"이해

from typing import Optional 


class Test: 
    def __init__(self, tags: Optional(dict)=None, fields: Optional(dict)=None): 
     self.__tags = tags or {} 
     self.__fields = fields or {} 
     ... 
    ... 

:
파이썬 코드 - 포함 식을, 모듈 수준 또는 클래스 본문 내부에 있거나 함수 또는 메서드 선언에있는 경우 모듈이 처음로드 될 때 한 번만 처리됩니다.

클래스 본문에서 작성한 빈 사전과 현재 사전으로 작성된 __init__ 기본 매개 변수를 의미하며 클래스가 인스턴스화 될 때마다 다시 사용됩니다.

첫 번째 부분은 파이썬에서 클래스 본문에 직접 선언 된 속성은 클래스 속성입니다. 이는 해당 클래스의 모든 인스턴스에서 공유된다는 것을 의미합니다. 메소드 내에 self.attribute = XXX의 속성을 지정하면 인스턴스 속성을 작성합니다.

두 번째 문제는 함수/메서드 매개 변수의 기본값이 함수 코드와 함께 저장된다는 것입니다. 따라서 비어있는 것으로 선언 된 사전은 각 메서드 호출 후에 동일하게 나타나며 클래스의 모든 인스턴스에서 공유됩니다.

일반적인 피할 수있는 패턴은 기본 매개 변수를 None 또는 다른 센티넬 값을 선택하고 테스트 할 함수 본문 내에서 설정하는 것입니다. 매개 변수에 값이 보내지지 않으면 새로운 새 사전을 만들거나 변경 가능한 객체) 인스턴스. 이 함수는 실제로 함수가 실행될 때 만들어지며 실행시 고유합니다.나는 내 대답 self.__tags = tags or {}에서 제안 된 or 키워드로

(당신이 인스턴스에 할당한다면, 물론, 해당 인스턴스에, self.attr = {}와 독특한 속성) - 그것은 우리가 전에 (구 파이썬에서 일반적인 패턴에서 구걸 inine if)을 사용했지만 "or"연산자 바로 가기가 있고 과 같은 표현에서 이 유용하면 "trueish"값으로 평가되면 첫 번째 피연산자를 반환하고 그렇지 않으면 두 번째 특성을 반환합니다. , 중요하지 않습니다. 두 번째 매개 변수의 진리 값은 모두 중요합니다. 인라인 "if"표현식을 사용하는 동일한 표현식은 self.__tags = tags if tags else {}이됩니다.

또한 이전의 자습서에서 "개인"속성으로 언급 한 것을 갖기 위해 속성 이름 앞에 __ 두 개의 패턴이 붙어 있지만 좋은 프로그래밍 패턴이 아니므로 피해야합니다. 파이썬은 실제로 개인 또는 보호 된 속성 액세스를 구현하지 않습니다. 특정 속성, 메소드 또는 함수 이름이 _ (밑줄 하나)으로 시작하는 경우, 코드를 작성한 사람을 개인적으로 사용하기위한 것입니다. 코드를 변경하거나 호출하면 해당 특성을 제어하는 ​​코드의 향후 버전에서 실행되지 않은 동작이 발생할 수 있습니다. 그러나 코드의 아무 것도 실제로 그렇게하지 못하게합니다. 이중 밑줄 접두사를 들어

, 그러나, 실제로 사용 부작용이 : 에서 컴파일 시간, __로 시작 클래스 속성의 이름이 변경되고, __xxx_<classname>__xxx로 이름이 변경 - 이름이 변경되는 클래스 본문 내의 모든 발생 회수를 클래스 몸체 외부의 같은 유행과 코드는 정상적으로 액세스 할 수 있습니다. 전체 맹 글링 된 이름을 쓰면됩니다. 이 기능은 실수로 또는 속성 이름의 사용 용이성 ("보안"목적이 아님)으로 하위 클래스에서 재정의되지 않는 속성 및 메소드를 기본 클래스가 보유 할 수 있도록하기위한 것입니다.

오래된 언어 자습서와 텍스트는 대개 파이썬에서 "개인 속성"을 수행하는 방법으로이 기능을 설명합니다. 실제로는 잘못되었습니다.

+0

출력이 어떻게 바뀌는 지 묻고 싶습니다. 이전에 사용한 or 키워드를 본 적이 없습니까? –

+0

이것은 실제로 나를 위해 몇 가지를 지 웁니다. 첫째, " 'NoneType'객체가 항목 할당을 지원하지 않습니다"라는 문제가 발생했습니다 ('tags : dict = None' 설정). 둘째로, 나는 내 질문에 설명 된 문제를 만났습니다. 이것으로 양쪽 모두가 지워지고'또는'가 많은 의미를 갖습니다! 고맙습니다! 이것을 약 8 분 안에 대답으로 받아 들일 것입니다. – nwilging

+0

셋째, "사물이 비공식이어야 함을 포함하면 모든 곳에 두 배의 밑줄을 넣을 것입니다!" – jonrsharpe

관련 문제