class 语法和 type() 有什么区别?
What is the difference between class syntax and type()?
我很清楚 类 可以在 python 中使用 type
动态声明,并且在这里和那里都使用过它。但是我还是不清楚这两个函数有什么区别。
def class_factory():
def init(self, attr):
self.attr = attr
class_ = type('DynamicClass', (), {'__init__' : init})
return class_
和
def class_factory():
class DynamicClass:
def __init__(self, attr):
self.attr = attr
return DynamicClass
我已经看到很多代码库(如 django)中使用了第一种模式,但到目前为止从未见过第二种模式。我仍然觉得第二个在语法上更清晰。
我正在努力寻找关于为什么人们使用 first pattern
来声明动态 类 而不是 second
的正确解释。我对这两个函数进行了试验,但没有发现从这两个函数获得的 类 之间有任何显着差异。我希望从任何方面(性能方面或任何其他方面)对上述两个 patterns/syntaxes 之间的差异进行明确的解释。
谢谢,
你选择了一个正确的例子,你如何用你的第二个例子动态创建一个 class?您无法正确地做到这一点,这就是为什么首选第一种情况的原因。看看这个基于你的玩具示例。
def class_factory(many_args=False):
def init1(self, attr):
self.attr = attr
def init2(self, *attr):
self.attr = attr
init = init1
if many_args:
init = init2
class_ = type('DynamicClass', (), {'__init__': init})
return class_
many = class_factory(True)(1, 2, 3, 4)
one = class_factory()(1)
结果:
>>> print(many.attr, one.attr)
(1, 2, 3, 4) 1
在你的第二个例子中很难用不同的属性和方法组成一个class。
class
语句是调用 metaclass.
的声明性语法
class Foo(Bar, metaclass=SomeMeta): # If not specified, the metaclass is type
...
等同于
Foo = SomeMeta('Foo', (Bar,) {...})
其中 {...}
是从 class
语句的主体构建的一些映射。举个简单的例子,不详述:
class Foo(Bar, metaclass=SomeMeta):
some_attr = "foo string"
def __init__(self, x=9):
self.y = x = 3
将定义一个函数名称 __init__
,然后将 {'__init__': __init__, 'some_attr': 'foo string'}
传递给 SomeMeta
。名称 __init__
仅存在于由 class
语句创建的临时名称空间中,不影响可能存在于语句之外的任何名称 __init__
。
为了回答您的问题,有时自己构建第三个参数 metaclass 比让 class
语句为您完成更灵活或更简单。第二个参数也是如此。 first 参数由 class
语句的语法固定,但如果您自己调用 metaclass 则可以在 运行 时生成.
请注意,这意味着您可以真正滥用class
声明。 EnumMeta
来自 enum
模块,在我看来,扩展了你应该用一个模块做什么。这是一个 really 辱骂的例子。 metaclass 实际上不一定是类型;它只需要是可调用的,并且需要接受三个位置参数。它也可以接受额外的关键字参数。然后它可以用这些参数做任何它想做的事情,return它也可以做任何它想做的事情。
def FooMeta(name, bases, dct, msg):
print(f'{msg} from {name}')
return 3
class Foo(metaclass=FooMeta, msg="hi"):
pass
Foo
甚至都不是 class;它绑定到 3
.
我很清楚 类 可以在 python 中使用 type
动态声明,并且在这里和那里都使用过它。但是我还是不清楚这两个函数有什么区别。
def class_factory():
def init(self, attr):
self.attr = attr
class_ = type('DynamicClass', (), {'__init__' : init})
return class_
和
def class_factory():
class DynamicClass:
def __init__(self, attr):
self.attr = attr
return DynamicClass
我已经看到很多代码库(如 django)中使用了第一种模式,但到目前为止从未见过第二种模式。我仍然觉得第二个在语法上更清晰。
我正在努力寻找关于为什么人们使用 first pattern
来声明动态 类 而不是 second
的正确解释。我对这两个函数进行了试验,但没有发现从这两个函数获得的 类 之间有任何显着差异。我希望从任何方面(性能方面或任何其他方面)对上述两个 patterns/syntaxes 之间的差异进行明确的解释。
谢谢,
你选择了一个正确的例子,你如何用你的第二个例子动态创建一个 class?您无法正确地做到这一点,这就是为什么首选第一种情况的原因。看看这个基于你的玩具示例。
def class_factory(many_args=False):
def init1(self, attr):
self.attr = attr
def init2(self, *attr):
self.attr = attr
init = init1
if many_args:
init = init2
class_ = type('DynamicClass', (), {'__init__': init})
return class_
many = class_factory(True)(1, 2, 3, 4)
one = class_factory()(1)
结果:
>>> print(many.attr, one.attr)
(1, 2, 3, 4) 1
在你的第二个例子中很难用不同的属性和方法组成一个class。
class
语句是调用 metaclass.
class Foo(Bar, metaclass=SomeMeta): # If not specified, the metaclass is type
...
等同于
Foo = SomeMeta('Foo', (Bar,) {...})
其中 {...}
是从 class
语句的主体构建的一些映射。举个简单的例子,不详述:
class Foo(Bar, metaclass=SomeMeta):
some_attr = "foo string"
def __init__(self, x=9):
self.y = x = 3
将定义一个函数名称 __init__
,然后将 {'__init__': __init__, 'some_attr': 'foo string'}
传递给 SomeMeta
。名称 __init__
仅存在于由 class
语句创建的临时名称空间中,不影响可能存在于语句之外的任何名称 __init__
。
为了回答您的问题,有时自己构建第三个参数 metaclass 比让 class
语句为您完成更灵活或更简单。第二个参数也是如此。 first 参数由 class
语句的语法固定,但如果您自己调用 metaclass 则可以在 运行 时生成.
请注意,这意味着您可以真正滥用class
声明。 EnumMeta
来自 enum
模块,在我看来,扩展了你应该用一个模块做什么。这是一个 really 辱骂的例子。 metaclass 实际上不一定是类型;它只需要是可调用的,并且需要接受三个位置参数。它也可以接受额外的关键字参数。然后它可以用这些参数做任何它想做的事情,return它也可以做任何它想做的事情。
def FooMeta(name, bases, dct, msg):
print(f'{msg} from {name}')
return 3
class Foo(metaclass=FooMeta, msg="hi"):
pass
Foo
甚至都不是 class;它绑定到 3
.