def myfn():
class MyClass:
pass
return MyClass()
a = myfn()
b = myfn()
print(type(a) is type(b))
我们可以看到type(a)
不是 type(b)
。这总是保证是这样的吗?为什么解释器不对此进行优化,因为MyClass
的定义不依赖于传递给myfn
的任何参数?
答案 0 :(得分:7)
class
语句在执行始终时会创建一个新的类对象。课程不是单身人士。通过将class
语句放在函数中,只需让您多次执行它。
模块级别的类语句只执行一次,因为模块在首次导入时只执行一次。
您可以通过从sys.modules
结构中删除模块对象来绕过此操作;你会注意到我们删除模块后第三次导入的Foo
类是另一个对象:
>>> with open('demomodule.py', 'w') as demomodule:
... demomodule.write('class Foo: pass\n')
...
16
>>> import sys
>>> from demomodule import Foo # first import
>>> id(Foo)
140579578254536
>>> import demomodule # just another reference, module is not run again
>>> id(demomodule.Foo)
140579578254536
>>> del sys.modules['demomodule'] # removing the module object
>>> import demomodule # this causes it to be imported again
>>> id(demomodule.Foo)
140579574812488
当您以脚本运行模块然后使用import
导入相同的模块时,会发生同样的情况;脚本作为__main__
模块运行,使用import
再次导入脚本 ,然后为导入的名称创建单独的模块对象:
$ echo 'class Foo: pass
> import demomodule
> print(__name__, id(Foo), id(demomodule.Foo))
> ' > demomodule.py
$ python demomodule.py
demomodule 140718182184264 140718182184264
__main__ 140718182074440 140718182184264
Python本质上是高度动态的;应用优化(例如缓存由函数生成的类对象)充满了问题。您的功能可能不会采用任何参数,但它不是在真空中运行。例如,我可以替换__build_class__
钩子函数,并在在Python的任何地方创建的任何类的基础中插入一个额外的类:
>>> def foo_class():
... class Foo: pass
... return Foo
...
>>> foo_class().__mro__
(<class '__main__.foo_class.<locals>.Foo'>, <class 'object'>)
>>> import builtins
>>> class Bar: pass
>>> orig_buildclass = builtins.__build_class__
>>> def my_buildclass(f, name, *bases, **kwargs):
... return orig_buildclass(f, name, *((Bar,) + bases), **kwargs)
...
>>> builtins.__build_class__ = my_buildclass
>>> foo_class().__mro__
(<class '__main__.foo_class.<locals>.Foo'>, <class '__main__.Bar'>, <class 'object'>)
Python充满了像这样的钩子。