2008-10-15 9 views
18

다음은 이상하게 보입니다. 기본적으로 somedata 속성은 the_base_class에서 상속 된 모든 클래스간에 공유 된 것처럼 보입니다.속성 참조가 파이썬 상속과 함께 왜 이런 식으로 작동합니까?

class the_base_class: 
    somedata = {} 
    somedata['was_false_in_base'] = False 


class subclassthing(the_base_class): 
    def __init__(self): 
      print self.somedata 


first = subclassthing() 
{'was_false_in_base': False} 
first.somedata['was_false_in_base'] = True 
second = subclassthing() 
{'was_false_in_base': True} 
>>> del first 
>>> del second 
>>> third = subclassthing() 
{'was_false_in_base': True} 

분명히 __init__ 기능이 주위에 얻을 수있는 올바른 방법을 self.somedata입니다 정의 (각각의 클래스가 somedata DICT 자신의 가지고) -하지만 때 그런 행동이 바람직하다?

답변

23

맞습니다. somedata정의 시간에 생성되었으므로 클래스의 모든 인스턴스와 하위 클래스에서 공유됩니다. 인스턴스가 생성됩니다 하지 (자바에서 정적 초기화 블록을 생각) - 클래스를 정의 할 때의 선

somedata = {} 
somedata['was_false_in_base'] = False 

은 인터프리터가 class 문을 발견 한 경우 즉, 실행됩니다. 속성이 클래스 인스턴스에 없으면 클래스 객체가 속성을 검사합니다. 클래스 정의시

,이 같은 arbritrary 코드를 실행할 수 있습니다 : 리눅스 시스템에서

import sys 
class Test(object): 
    if sys.platform == "linux2": 
     def hello(self): 
       print "Hello Linux" 
    else: 
     def hello(self): 
       print "Hello ~Linux" 

, Test().hello() 다른 문자열이 인쇄됩니다 다른 모든 시스템에 Hello Linux을 인쇄 할 수 있습니다. constrast에서

, __init__의 개체 인스턴스에 시간을 만들어 만 (그들이 self에 할당 될 때) 인스턴스에 속한다 : 클래스 객체에 정의

class Test(object): 
    def __init__(self): 
     self.inst_var = [1, 2, 3] 

객체 대신 인스턴스보다 할 많은 경우에 유용합니다. 예를 들어, 당신은 (불변으로 그들이 해야하는 가정) 같은 멤버 값과 인스턴스를 공유 할 수 있도록, 클래스의 인스턴스를 캐시 할 수 있습니다 :

class SomeClass(object): 
    __instances__ = {} 

    def __new__(cls, v1, v2, v3): 
     try: 
      return cls.__insts__[(v1, v2, v3)] 
     except KeyError: 
      return cls.__insts__.setdefault(
       (v1, v2, v3), 
       object.__new__(cls, v1, v2, v3)) 

가 대부분, 내가 클래스 기관의 데이터를 사용 메타 클래스 또는 일반적인 공장 방법과 함께 사용합니다.

+1

그러면 인스턴스 var를 어떻게 선언합니까? – OscarRyz

+0

답안에 예제를 추가했습니다. –

+0

간단한 데이터와 복잡한 데이터 사이에 차이점이 있습니까? TimB가 말한대로? – OscarRyz

10

표시되는 동작의 일부는 bool과 같은 간단한 데이터 형식과 달리 somedatadict인데 따른 것입니다.

예를 들어, (매우 유사하지만) 다르게 동작이 다른 예 참조 :

class the_base_class: 
    somedata = False 

class subclassthing(the_base_class): 
    def __init__(self): 
     print self.somedata 


>>> first = subclassthing() 
False 
>>> first.somedata = True 
>>> print first.somedata 
True 
>>> second = subclassthing() 
False 
>>> print first.somedata 
True 
>>> del first 
>>> del second 
>>> third = subclassthing() 
False 

여기 first.somedata 새로운 값을 부여하고 있기 때문에,이 예는 질문에서 주어진 것과 다르게 동작하는 이유는 (객체 True), 첫 번째 예제에서는 으로 참조되는 dict 객체 (및 다른 하위 클래스 인스턴스에 의해)가 수정됩니다.

자세한 설명을 위해이 답변에 대한 Torsten Marek의 의견을 참조하십시오.

+0

단순한 데이터 형식은 복잡한 반면 공유되지 않는다는 말입니까? – OscarRyz

+0

아니요, 공유됩니다. 파이썬의 모든 데이터 유형은 참조 유형이며 심지어 정수 및 부울 등이 있습니다. first.somedata에 False/True 값이 없기 때문에 False/True를 참조합니다. 재 할당되면 다른 객체를 참조하기 만합니다. –

+0

@ 오스카, 나는 그 차이가 참고 문헌의 특성 때문이라고 생각합니다. somedata가 사전 일 때 1과 2는 자신의 참조를 가지지 만 각 참조는 메모리에있는 같은 사전을 가리 킵니다. 언젠가 언젠가 부울 (boolean) 일 때 그들은 여전히 ​​자신의 복사본을 얻습니다. 그러나 그들은 부울을 직접 수정합니다. –

2

당신이 행동을 예측할 수 있도록 이것을 이해하는 가장 쉬운 방법은 당신의 somedata이 그 클래스의 인스턴스가 아니라 그 클래스의 인스턴스라는 것을 깨닫는 것입니다.

귀하의 예제에서 당신은 그 이름을 할당하지 않았지만 그것을 사용하여 사전을 찾고 그 다음에 항목 (키, 값)을 할당하기 때문에 실제로는 하나만 존재합니다 (somedata). 그것은 파이썬 인터프리터가 어떻게 작동하고 처음에는 혼란 스러울 수 있는지에 대한 결과 인 잡았다.

관련 문제