gpt4 book ai didi

python - (Python) 意外创建的闭包

转载 作者:太空宇宙 更新时间:2023-11-03 23:48:59 25 4
gpt4 key购买 nike

我在创建嵌套类时意外关闭。我怀疑这与元类、父类(super class)或两者有关。这肯定与闭包的创建方式有关。我正在使用 python2.7。

这里有五个简化的例子,它们展示了我所看到的相同问题(它们都建立在第一个之上):

示例 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:

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

这是我的理解(引用例子):

  • 元类是继承的,所以 Subclass 得到 Base 的元类。
  • 只有 __init__ 受到影响,Subclass.other 方法不受影响(#1)。
  • 删除 Subclass.other 没有任何区别(#1)。
  • Subclass.__init__ 中删除 self.name=name 没有任何区别(#1)。
  • 闭包单元中的对象不是函数。
  • 该对象不是MetaclassBase,而是一些Metaclass 类型的对象,就像Base 是(#1)。
  • 该对象实际上是嵌套子类 (#1) 类型的对象。
  • t1.subclass.__init__t1.subclass2.__init__ 的闭包单元是相同的,即使它们来自两个不同的类 (#1)。
  • 当我不嵌套创建 Subclass (#1) 时,就不会创建闭包。
  • 当我不在 Subclass.init__ 中调用 super(...).__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__ 设置闭包?
  • 为什么没有为 other 设置闭包?
  • 为什么闭包单元格中的对象设置为__init__所属的类?
  • 为什么只有在调用 super(...).__init__ 时才会发生这种情况?
  • 为什么调用 Base.__init__(self) 时不会发生这种情况?
  • 这实际上与使用元类有任何关系吗(可能是因为默认的元类是 type)?

感谢您的帮助!

-埃里克

(更新)这是我当时发现的一些东西(基于 Jason 的洞察力):

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

首先,函数的名称在其自身的范围内。其次,如果函数引用了定义它们的函数,则函数会获得这些函数的闭包。

我没有意识到函数名称在这样的范围内。上课也是如此。当一个类在一个函数的范围内定义时,在类的方法中对该类名的任何引用都会导致该类绑定(bind)到该方法的函数的闭包中,如下所示:

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

好东西!

最佳答案

Why does a closure get set for __init__?

它引用封闭函数(即setup)中的局部变量(即Subclass)。

Why doesn't the closure get set for other?

因为它不引用任何封闭函数中的任何局部变量(或参数)。

Why is the object in the closure cell set to the class to which __init__ belongs?

这是被引用的封闭变量的值。

Why does this only happen when super(...).__init__ is called?

Why doesn't this happen when Base.__init__(self) is called?

因为 Base 不是任何封闭函数中的局部变量。

Does this actually have anything at all to do with using metaclasses?

没有。

关于python - (Python) 意外创建的闭包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3374427/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com