Python 使用元类定义方法、类方法/实例方法
我试图更深入地理解元类在python中是如何工作的。我的问题如下,我想使用元类为每个类定义一个方法,该方法将使用在元类中定义的class属性。例如,这有注册应用程序 以下是一个工作示例:Python 使用元类定义方法、类方法/实例方法,python,python-3.x,class,metaclass,class-method,Python,Python 3.x,Class,Metaclass,Class Method,我试图更深入地理解元类在python中是如何工作的。我的问题如下,我想使用元类为每个类定义一个方法,该方法将使用在元类中定义的class属性。例如,这有注册应用程序 以下是一个工作示例: import functools def dec_register(func): @functools.wraps(func) def wrapper_register(*args, **kwargs): (args[0].__class__.list_register_in
import functools
def dec_register(func):
@functools.wraps(func)
def wrapper_register(*args, **kwargs):
(args[0].__class__.list_register_instances).append(args[0])
return func(*args, **kwargs)
return wrapper_register
dict_register_classes = {}
class register(type):
def __new__(meta, name, bases, attrs):
dict_register_classes[name] = cls = type.__new__(meta, name, bases, attrs) # assigniation from right to left
cls.list_register_instances = []
cls.print_register = meta.print_register
return cls
def print_register(self):
for element in self.list_register_instances:
print(element)
def print_register_class(cls):
for element in cls.list_register_instances:
print(element)
#
class Foo(metaclass=register):
@dec_register
def __init__(self):
pass
def print_register(self):
pass
class Boo(metaclass=register):
@dec_register
def __init__(self):
pass
def print_register(self):
pass
f = Foo()
f_ = Foo()
b = Boo()
print(f.list_register_instances)
print(b.list_register_instances)
print(dict_register_classes)
print("1")
f.print_register()
print("2")
Foo.print_register_class()
print("3")
f.print_register_class()
print("4")
Foo.print_register()
我在最后做的测试没有像我预期的那样有效。如果我所说的没有使用正确的语法,我会提前道歉,我会尽可能清楚:
我认为行cls.print\u register=meta.print\u register
使用在元类中定义的方法在类中定义方法。因此,这是一种我可以在对象上使用的方法。我也可以使用它作为类方法,因为它是在元类中定义的。然而,尽管以下工作:
print("1")
f.print_register()
这不能正常工作:
print("4")
Foo.print_register()
有误:
Foo.print_register()
TypeError: print_register() missing 1 required positional argument: 'self'
测试2和测试3也是如此,我希望如果在类级别定义了一个方法,那么它也应该在对象级别定义。然而,测试3产生了一个错误
print("2")
Foo.print_register_class()
print("3")
f.print_register_class()
因此,你能解释一下为什么我对类方法的理解是错误的吗?我希望能够在类或对象上调用方法print\u register
。
也许这有助于了解事实上我试图重现以下非常简单的示例:
# example without anything fancy:
class Foo:
list_register_instances = []
def __init__(self):
self.__class__.list_register_instances.append(self)
@classmethod
def print_register(cls):
for element in cls.list_register_instances:
print(element)
我对元类不是做了完全相同的事情吗?classmethod既可以用于类,也可以用于对象
如果您对代码结构有任何建议,我将不胜感激。我对元类的语法一定很差。基本上,因为您在元类实例(您的类)上隐藏了
print\u register
因此,当您执行Foo.print\u register
时,它会找到您在中定义的print\u register
class Foo(metaclass=register):
...
def print_register(self):
pass
当然,这只是普通函数print\u register
,它需要self
参数
这(几乎)与普通类及其实例发生的情况相同:
class Foo:
def bar(self):
print("I am a bar")
foo = Foo()
foo.bar = lambda x: print("I've hijacked bar")
foo.bar()
注:
这实际上就像在类定义中定义那个函数一样。。。不知道你为什么要这么做
您所做的事情与使用classmethod
完全不同,后者是一个自定义描述符,用于处理方法到实例的绑定,就像您需要在类或实例上调用它一样。这与在类和实例上定义方法不同!您可以在元类\uuuu new\uuuu
中执行此操作,即cls.print\u register=classmethod(meta.print\u register)
并将def print\u register(self)
保留在类定义之外:
import functools
def dec_register(func):
@functools.wraps(func)
def wrapper_register(*args, **kwargs):
(args[0].__class__.list_register_instances).append(args[0])
return func(*args, **kwargs)
return wrapper_register
dict_register_classes = {}
class register(type):
def __new__(meta, name, bases, attrs):
dict_register_classes[name] = cls = type.__new__(meta, name, bases, attrs) # assigniation from right to left
cls.list_register_instances = []
cls.print_register = classmethod(meta.print_register) # just create the classmethod manually!
return cls
def print_register(self):
for element in self.list_register_instances:
print(element)
def print_register_class(cls):
for element in cls.list_register_instances:
print(element)
#
class Foo(metaclass=register):
@dec_register
def __init__(self):
pass
注意,print\u register
不必在元类中定义,实际上,在这种情况下,我只需在模块级别定义它:
def print_register(self):
for element in self.list_register_instances:
print(element)
...
class register(type):
def __new__(meta, name, bases, attrs):
dict_register_classes[name] = cls = type.__new__(meta, name, bases, attrs) # assigniation from right to left
cls.list_register_instances = []
cls.print_register = classmethod(print_register)
return cls
...
我认为你已经充分理解了元类,实际上,据我所知,你对classmethod
的理解是不正确的。如果您想了解classmethod
是如何工作的,实际上,方法实例绑定是如何为常规函数工作的,那么您需要了解描述符。函数对象是描述符,当对实例调用时,它们将实例作为第一个参数绑定到自身(相反,它们创建一个方法对象并返回该对象,但它基本上是部分应用程序)classmethod
对象是另一种描述符,它将类绑定到它在类或实例上调用时所修饰的函数的第一个参数。该链接描述了如何使用纯python编写classmethod
import functools
def dec_register(func):
@functools.wraps(func)
def wrapper_register(*args, **kwargs):
(args[0].__class__.list_register_instances).append(args[0])
return func(*args, **kwargs)
return wrapper_register
dict_register_classes = {}
class register(type):
def __new__(meta, name, bases, attrs):
dict_register_classes[name] = cls = type.__new__(meta, name, bases, attrs) # assigniation from right to left
cls.list_register_instances = []
cls.print_register = classmethod(meta.print_register) # just create the classmethod manually!
return cls
def print_register(self):
for element in self.list_register_instances:
print(element)
def print_register_class(cls):
for element in cls.list_register_instances:
print(element)
#
class Foo(metaclass=register):
@dec_register
def __init__(self):
pass
def print_register(self):
for element in self.list_register_instances:
print(element)
...
class register(type):
def __new__(meta, name, bases, attrs):
dict_register_classes[name] = cls = type.__new__(meta, name, bases, attrs) # assigniation from right to left
cls.list_register_instances = []
cls.print_register = classmethod(print_register)
return cls
...