2010-07-30 1 views
2

중첩 클래스를 생성 할 때 예기치 않은 종료가 발생했습니다. 나는 이것이 메타 클래스, 수퍼 또는 둘다와 관련된 것이라고 생각합니다. 이것은 클로저가 어떻게 생성되는지와 분명히 관련이 있습니다. 나는 python2.7을 사용하고있다.(Python) 기대하지 않았을 때 Closure가 생성되었습니다.

예 1 :

class Metaclass(type): 
    def __init__(self, name, bases, dict): 
     self.CONST = 5 

class Base(object): 
    __metaclass__=Metaclass 
    def __init__(self): 
     "Set things up." 

class Subclass(Base): 
    def __init__(self, name): 
     super(Subclass, self).__init__(self) 
     self.name = name 
    def other(self, something): pass 

class Test(object): 
    def setup(self): 
     class Subclass(Base): 
      def __init__(self, name): 
       super(Subclass, self).__init__(self) 
       self.name = name 
      def other(self, something): pass 
     self.subclass = Subclass 
     class Subclass2(Base): 
      def __init__(self, name): 
       super(Subclass, self).__init__(self) 
     self.subclass2 = Subclass2 

"0x%x" % id(Metaclass) 
# '0x8257f74' 
"0x%x" % id(Base) 
# '0x825814c' 
t=Test() 
t.setup() 
"0x%x" % id(t.subclass) 
# '0x8258e8c' 
"0x%x" % id(t.subclass2) 
# '0x825907c' 
t.subclass.__init__.__func__.__closure__ 
# (<cell at 0xb7d33d4c: Metaclass object at 0x8258e8c>,) 
t.subclass.other.__func__.__closure__ 
# None 
t.subclass2.__init__.__func__.__closure__ 
# (<cell at 0xb7d33d4c: Metaclass object at 0x8258e8c>,) 
Subclass.__init__.__func__.__closure__ 
# None 

예 2 :

class Test2(object): 
    def setup(self): 
     class Subclass(Base): 
      def __init__(self, name): 
       self.name = name 
      def other(self, something): pass 
     self.subclass = Subclass 

t2=Test2() 
t2.setup() 
t2.subclass.__init__.__func__.__closure__ 
# None 

는 여기에 내가보고하고 같은 문제 (모두가 우선 구축)를 보여 다섯 가지 간단한 예입니다

실시 예 3 :

class Test3(object): 
    def setup(self): 
     class Other(object): 
      def __init__(self): 
       super(Other, self).__init__() 
     self.other = Other 
     class Other2(object): 
      def __init__(self): pass 
     self.other2 = Other2 

t3=Test3() 
t3.setup() 
"0x%x" % id(t3.other) 
# '0x8259734' 
t3.other.__init__.__func__.__closure__ 
# (<cell at 0xb7d33e54: type object at 0x8259734>,) 
t3.other2.__init__.__func__.__closure__ 
# None 

예 4 :

class Metaclass2(type): pass 

class Base2(object): 
    __metaclass__=Metaclass2 
    def __init__(self): 
     "Set things up." 

class Base3(object): 
    __metaclass__=Metaclass2 

class Test4(object): 
    def setup(self): 
     class Subclass2(Base2): 
      def __init__(self, name): 
       super(Subclass2, self).__init__(self) 
     self.subclass2 = Subclass2 
     class Subclass3(Base3): 
      def __init__(self, name): 
       super(Subclass3, self).__init__(self) 
     self.subclass3 = Subclass3 
     class Subclass4(Base3): 
      def __init__(self, name): 
       super(Subclass4, self).__init__(self) 
     self.subclass4 = Subclass4 

"0x%x" % id(Metaclass2) 
# '0x8259d9c' 
"0x%x" % id(Base2) 
# '0x825ac9c' 
"0x%x" % id(Base3) 
# '0x825affc' 
t4=Test4() 
t4.setup() 
"0x%x" % id(t4.subclass2) 
# '0x825b964' 
"0x%x" % id(t4.subclass3) 
# '0x825bcac' 
"0x%x" % id(t4.subclass4) 
# '0x825bff4' 
t4.subclass2.__init__.__func__.__closure__ 
# (<cell at 0xb7d33d04: Metaclass2 object at 0x825b964>,) 
t4.subclass3.__init__.__func__.__closure__ 
# (<cell at 0xb7d33e9c: Metaclass2 object at 0x825bcac>,) 
t4.subclass4.__init__.__func__.__closure__ 
# (<cell at 0xb7d33ddc: Metaclass2 object at 0x825bff4>,) 

예 5 :

  • 메타 클래스는 상속, 그래서 SubclassBase의 메타 클래스를 가져옵니다 여기

    class Test5(object): 
        def setup(self): 
         class Subclass(Base): 
          def __init__(self, name): 
           Base.__init__(self) 
         self.subclass = Subclass 
    
    t5=Test5() 
    t5.setup() 
    "0x%x" % id(t5.subclass) 
    # '0x8260374' 
    t5.subclass.__init__.__func__.__closure__ 
    # None 
    

    내가 (참조 예) 이해하는 것입니다.

  • __init__ 만 영향을받습니다. Subclass.other 방법은 (# 1)이 아닙니다.
  • Subclass.other을 제거해도 차이는 없습니다 (1 번).
  • Subclass.__init__에서 self.name=name을 제거해도 차이는 없습니다 (1 번).
  • 클로저 셀의 개체가 함수가 아닙니다.
  • 개체가 Metaclass 또는 Base이 아니지만 이 (# 1) 인 것처럼 Metaclass 유형의 개체가 있습니다.
  • 개체는 실제로 중첩 된 (# 1) 유형의 개체입니다.
  • t1.subclass.__init__t1.subclass2.__init__에 대한 폐쇄 셀은 두 개의 서로 다른 클래스 (# 1)에서 같지만 동일합니다.
  • Subclass (# 1)의 생성을 중첩하지 않으면 생성 된 클로저가 없습니다.
  • super(...).__init__Subclass.init__에 전화하지 않으면 폐쇄가 생성되지 않습니다 (# 2).
  • __metaclass__을 할당하지 않고 object에서 상속하는 경우 동일한 동작이 나타납니다 (# 3).
  • t3.other.__init__의 폐쇄 셀에있는 객체는 t3.other (# 3)입니다.
  • 메타 클래스에 __init__ (# 4)이없는 경우에도 동일한 문제가 발생합니다.
  • Base__init__ (# 4)이없는 경우에도 동일한 문제가 발생합니다.
  • 예제 4의 세 하위 클래스에 대한 클로저 셀은 모두 다르며 각각은 해당 클래스 (# 4)와 일치합니다.
  • super(...).__init__Base.__init__(self)으로 대체하면 클로저가 사라집니다 (# 5). 여기

내가 이해하지 못하는 것입니다 :

  • 은 왜 폐쇄는 __init__ 설정됩니까?
  • 다른 항목에 대해 클로저가 설정되지 않는 이유는 무엇입니까?
  • 클로저 셀의 객체가 __init__이 속한 클래스로 설정된 이유는 무엇입니까?
  • super(...).__init__을 호출 할 때만 이런 이유가 발생합니까?
  • Base.__init__(self)을 호출 할 때 왜 이런 일이 발생하지 않습니까?
  • 메타 클래스를 사용하는 것과 실제로 아무 관계가 없습니까 (기본 메타 클래스가 type이므로)?

도움을 주셔서 감사합니다! 여기에 (제이슨의 통찰력을 기반으로) 그때 발견 뭔가

-Eric

(업데이트) :

def something1(): 
    print "0x%x" % id(something1) 
    def something2(): 
     def something3(): 
      print "0x%x" % id(something1) 
      print "0x%x" % id(something2) 
      print "0x%x" % id(something3) 
     return something3 
    return something2 

something1.__closure__ 
# None 
something1().__closure__ 
# 0xb7d4056c 
# (<cell at 0xb7d33eb4: function object at 0xb7d40df4>,) 
something1()().__closure__ 
# 0xb7d4056c 
# (<cell at 0xb7d33fec: function object at 0xb7d40e64>, <cell at 0xb7d33efc: function object at 0xb7d40e2c>) 
something1()()() 
# 0xb7d4056c 
# 0xb7d4056c 
# 0xb7d40e9c 
# 0xb7d40ed4 

는 먼저, 함수의 이름은 자신의 몸에서 범위에있다. 둘째, 함수는 함수를 참조 할 경우 정의 된 함수에 대한 클로저를 얻습니다.

함수 이름이 그와 같은 범위에 있다는 것을 알지 못했습니다. 수업에도 마찬가지입니다. 클래스가 함수의 범위 내에서 정의 될 때, 클래스의 메소드 내부 클래스 이름에 대한 참조는과 같이, 그 방법의 기능에 폐쇄에 바운드로 클래스의 원인 :

def test(): 
    class Test(object): 
     def something(self): 
      print Test 
    return Test 

test() 
# <class '__main__.Test'> 
test().something.__func__.__closure__ 
# (<cell at 0xb7d33c2c: type object at 0x825e304>,) 

그러나 폐쇄를 생성 할 수 없기 때문에 기능이없는 경우 다음 오류가 발생합니다.

def test(): 
    class Test(object): 
     SELF=Test 
     def something(self): 
      print Test 
    return Test 

# Traceback (most recent call last): 
# File "<stdin>", line 1, in <module> 
# File "<stdin>", line 2, in test 
# File "<stdin>", line 3, in Test 
# NameError: free variable 'Test' referenced before assignment in enclosing scope 

좋은 물건!

답변

4

클로저가 __init__으로 설정되는 이유는 무엇입니까?

둘러싸는 기능 (즉, setup)의 지역 변수 (즉, Subclass)를 참조합니다.

클로저가 other으로 설정되지 않는 이유는 무엇입니까?

모든 둘러싸는 기능의 로컬 변수 (또는 매개 변수)를 나타내지 않으므로.

클로저 셀의 객체가 __init__이 속한 클래스로 설정된 이유는 무엇입니까?

이는 참조되는 둘러 쌀 변수의 값입니다.

super(...).__init__이 호출 될 때만 발생합니까?

Base.__init__(self)을 호출 할 때 왜 이런 일이 발생하지 않습니까?

Base은 모든 둘러보기 기능의 로컬 변수가 아니기 때문에.

이것은 실제로 메타 클래스 사용과 관련이 있습니까?

번호

+0

가 클래스 정의를 다음과 같이 작동 그것은 나에게 이상한. 예기치 않은. –

+0

"[...]베이스가 글로벌 이니?" 예. –

+0

흥미 롭습니다. 함수의 이름이 함수의 몸체의 범위에 있다는 것을 결코 깨닫지 못했을 것입니다. –