函数

时间:2018-06-12 17:17:46

标签: python python-3.x class

def myfn():
    class MyClass:
        pass


    return MyClass()


a = myfn()
b = myfn()

print(type(a) is type(b))

我们可以看到type(a) 不是 type(b)。这总是保证是这样的吗?为什么解释器不对此进行优化,因为MyClass的定义不依赖于传递给myfn的任何参数?

1 个答案:

答案 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充满了像这样的钩子。