如何从元类生成静态方法?
How to generate a staticmethod from a metaclass?
我正在尝试通过元编程为一堆 classes 创建一个静态方法、对象创建工厂方法。到目前为止,这是我尝试过的方法:
class PlayMeta(type):
def __new__(cls, clsname, bases, dct):
newclass = super(PlayMeta, cls).__new__(cls, clsname, bases, dct)
@staticmethod
def make():
print('meta make')
setattr(newclass, make.__name__, make)
return newclass
class Fritz(PlayMeta):
pass
Fritz.make()
但是当我 运行 它时,我得到:
AttributeError: type object 'Fritz' has no attribute 'make'
你是怎么做到的?我有很多字段的消息,我希望这是一个 class 来创建和生成不同的消息。这个问题是关于工厂/创建部分的。我正在使用 Python 3.5。谢谢!
编辑:第二,工作版本:
class PlayMeta(type):
def __new__(cls, clsname, bases, dct):
newclass = super(PlayMeta, cls).__new__(cls, clsname, bases, dct)
def instance_method(self, x, y, z):
print('instance method', x, y, z)
setattr(newclass, instance_method.__name__, instance_method)
def static_make(x, y, z):
print('static make', x, y, z)
setattr(newclass, static_make.__name__, static_make)
return newclass
class Fritz(metaclass=PlayMeta):
pass
Fritz.static_make('a', [], 3)
f = Fritz()
f.instance_method('a', [], 3)
成功打印:
static make a [] 3
instance method a [] 3
Python 如何区分实例方法和 class / 静态方法,当它们以相同的方式定义和附加时? 'self'这个词的存在?因为那会很方便,但有点矫揉造作。
edit2:啊,这可能 只是它的调用方式 - 用一个实例调用它,并且使用实例期望方法一切都很好。但是你可以调用任何一个方法,有或没有实例,它们会相应地表现正确或不正确。
edit3,最终形式:) :
@staticmethod
def static_make(x, y, z):
print('static make', x, y, z)
setattr(newclass, 'static_make', static_make)
我不知道 (at)staticmethod 添加了什么——上面的版本 2 有效——但这至少是更多的自我记录。
不确定我是否完全理解您的计划。但是假设 Fritz
是 而不是 本身应该是元 class 而不是常规 class,您需要将其构造为:
class Fritz(metaclass=PlayMeta):
pass
至于静态方法和实例方法之间的区别,所有常规函数的行为都像实例方法,如果在实例上调用,会将其作为第一个位置参数(无论它如何命名)。您可以在 第二个示例 中尝试调用 f.static_method
或 Fritz.instance_method
,它们的行为相同。要了解更多信息,请查看 descriptors.
staticmethod
装饰器将常规函数转换为适当的静态方法,即使在实例上调用该方法也会以相同的方式工作(即它不会将实例作为第一个参数)。但请注意,当应用时,结果对象没有 __name__
属性,如果您以编程方式生成这些方法,则需要该属性。
此外,__new__
的 dct
参数是一组名称和值,将用于设置新 class 的属性,因此这可能是一个很好的选择放置您在 metaclass 中创建的方法的位置。这也将使您能够决定是否希望 Fritz
class 能够覆盖 metaclass 中的属性,反之亦然。
示例(使用 metaclass 覆盖方法,如果它们恰好也在 class 上定义):
class PlayMeta(type):
def __new__(cls, clsname, bases, dct):
def instance_method(self, x, y, z):
print('instance method', x, y, z)
def static_make(x, y, z):
print('static make', x, y, z)
return super(PlayMeta, cls).__new__(cls, clsname, bases, {**dct,
instance_method.__name__: instance_method,
static_make.__name__: staticmethod(static_make),
})
class Fritz(metaclass=PlayMeta):
...
f = Fritz()
...
In [2]: f.instance_method(1, 2, 3)
instance method 1 2 3
In [3]: f.static_make(1, 2, 3)
static make 1 2 3
In [4]: Fritz.static_make(1, 2, 3)
static make 1 2 3
In [5]: Fritz.instance_method(1, 2, 3, 4)
instance method 2 3 4
我正在尝试通过元编程为一堆 classes 创建一个静态方法、对象创建工厂方法。到目前为止,这是我尝试过的方法:
class PlayMeta(type):
def __new__(cls, clsname, bases, dct):
newclass = super(PlayMeta, cls).__new__(cls, clsname, bases, dct)
@staticmethod
def make():
print('meta make')
setattr(newclass, make.__name__, make)
return newclass
class Fritz(PlayMeta):
pass
Fritz.make()
但是当我 运行 它时,我得到:
AttributeError: type object 'Fritz' has no attribute 'make'
你是怎么做到的?我有很多字段的消息,我希望这是一个 class 来创建和生成不同的消息。这个问题是关于工厂/创建部分的。我正在使用 Python 3.5。谢谢!
编辑:第二,工作版本:
class PlayMeta(type):
def __new__(cls, clsname, bases, dct):
newclass = super(PlayMeta, cls).__new__(cls, clsname, bases, dct)
def instance_method(self, x, y, z):
print('instance method', x, y, z)
setattr(newclass, instance_method.__name__, instance_method)
def static_make(x, y, z):
print('static make', x, y, z)
setattr(newclass, static_make.__name__, static_make)
return newclass
class Fritz(metaclass=PlayMeta):
pass
Fritz.static_make('a', [], 3)
f = Fritz()
f.instance_method('a', [], 3)
成功打印:
static make a [] 3
instance method a [] 3
Python 如何区分实例方法和 class / 静态方法,当它们以相同的方式定义和附加时? 'self'这个词的存在?因为那会很方便,但有点矫揉造作。
edit2:啊,这可能 只是它的调用方式 - 用一个实例调用它,并且使用实例期望方法一切都很好。但是你可以调用任何一个方法,有或没有实例,它们会相应地表现正确或不正确。
edit3,最终形式:) :
@staticmethod
def static_make(x, y, z):
print('static make', x, y, z)
setattr(newclass, 'static_make', static_make)
我不知道 (at)staticmethod 添加了什么——上面的版本 2 有效——但这至少是更多的自我记录。
不确定我是否完全理解您的计划。但是假设 Fritz
是 而不是 本身应该是元 class 而不是常规 class,您需要将其构造为:
class Fritz(metaclass=PlayMeta):
pass
至于静态方法和实例方法之间的区别,所有常规函数的行为都像实例方法,如果在实例上调用,会将其作为第一个位置参数(无论它如何命名)。您可以在 第二个示例 中尝试调用 f.static_method
或 Fritz.instance_method
,它们的行为相同。要了解更多信息,请查看 descriptors.
staticmethod
装饰器将常规函数转换为适当的静态方法,即使在实例上调用该方法也会以相同的方式工作(即它不会将实例作为第一个参数)。但请注意,当应用时,结果对象没有 __name__
属性,如果您以编程方式生成这些方法,则需要该属性。
此外,__new__
的 dct
参数是一组名称和值,将用于设置新 class 的属性,因此这可能是一个很好的选择放置您在 metaclass 中创建的方法的位置。这也将使您能够决定是否希望 Fritz
class 能够覆盖 metaclass 中的属性,反之亦然。
示例(使用 metaclass 覆盖方法,如果它们恰好也在 class 上定义):
class PlayMeta(type):
def __new__(cls, clsname, bases, dct):
def instance_method(self, x, y, z):
print('instance method', x, y, z)
def static_make(x, y, z):
print('static make', x, y, z)
return super(PlayMeta, cls).__new__(cls, clsname, bases, {**dct,
instance_method.__name__: instance_method,
static_make.__name__: staticmethod(static_make),
})
class Fritz(metaclass=PlayMeta):
...
f = Fritz()
...
In [2]: f.instance_method(1, 2, 3)
instance method 1 2 3
In [3]: f.static_make(1, 2, 3)
static make 1 2 3
In [4]: Fritz.static_make(1, 2, 3)
static make 1 2 3
In [5]: Fritz.instance_method(1, 2, 3, 4)
instance method 2 3 4