在超类构造函数中添加子类中的方法
我想自动向 Python 子类添加方法(更具体地说:方法别名)。如果子类定义了一个名为“get”的方法,我想将方法别名“GET”添加到子类的字典中。
为了不重复我自己,我想在基类中定义这个修改例程。但是如果我检查基类 __init__ 方法,则没有这样的方法,因为它是在子类中定义的。通过一些源代码,它会变得更加清晰:
class Base:
def __init__(self):
if hasattr(self, "get"):
setattr(self, "GET", self.get)
class Sub(Base):
def get():
pass
print(dir(Sub))
输出:
['__doc__', '__init__', '__module__', 'get']
它还应该包含 'GET'
。
有没有办法在基类中做到这一点?
I want to add methods (more specifically: method aliases) automatically to Python subclasses. If the subclass defines a method named 'get' I want to add a method alias 'GET' to the dictionary of the subclass.
To not repeat myself I'd like to define this modifation routine in the base class. But if I check in the base class __init__
method, there is no such method, since it is defined in the subclass. It will become more clear with some source code:
class Base:
def __init__(self):
if hasattr(self, "get"):
setattr(self, "GET", self.get)
class Sub(Base):
def get():
pass
print(dir(Sub))
Output:
['__doc__', '__init__', '__module__', 'get']
It should also contain 'GET'
.
Is there a way to do it within the base class?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您的类的
__init__
方法将一个绑定方法作为属性添加到您的类的实例。这与将属性添加到类中并不完全相同。通常,方法的工作原理是将函数作为属性存储在类中,然后创建方法对象,因为这些函数作为属性从任一类中检索(创建只知道它们所属的类的未绑定方法)或实例(创建绑定方法,它知道它们的实例。)这与您正在做的有什么不同?好吧,您分配给特定实例的
GET
instance属性,而不是类。绑定方法成为实例数据的一部分:请注意该方法如何位于键
GET
下,而不是在get
下。GET
是一个实例属性,但get
不是。这在很多方面都有细微的不同:类对象中不存在该方法,因此您无法执行Sub.GET(instance)
来调用Sub
的GET
方法,即使您可以执行Sub.get(instance)
。其次,如果您有一个 Sub 子类,它定义了自己的GET
方法,但没有定义自己的get
方法,则实例属性将使用基类中绑定的get
方法隐藏子类GET
方法。第三,它在绑定方法和实例之间创建循环引用:绑定方法具有对实例的引用,并且实例现在存储对绑定方法的引用。通常绑定的方法不会存储在实例上,部分原因是为了避免这种情况。循环引用通常不是一个大问题,因为我们现在有 cycling-gc 模块 (gc
) 来处理它们,但它不能总是清理引用循环(例如,当您的类也有一个 __del__ 方法。)最后,存储绑定方法对象通常会使您的实例不可序列化:大多数序列化程序(例如pickle
)无法处理绑定方法。您可能不关心这些问题,但如果您关心,那么有一个更好的方法来实现您想要做的事情:元类。您可以在创建类时将普通函数分配给类属性,而不是在创建实例时将绑定方法分配给实例属性:
Now、
Sub.get
和Sub.GET
实际上是别名,并且在子类中重写一个而不是另一个可以按预期工作。(当然,如果您不想覆盖其中一个而不是另一个,您只需在元类中将其设置为错误即可。)您可以使用 class 执行与元类相同的操作装饰器(在 Python 2.6 及更高版本中),但这意味着需要在 Base 的每个子类上使用类装饰器——类装饰器不会被继承。
Your class's
__init__
method adds a bound method as an attribute to instances of your class. This isn't exactly the same as adding the attribute to the class. Normally, methods work by storing functions in the class, as attributes, and then creating method objects as these functions are retrieved as attributes from either the class (creating unbound methods which only know the class they belong to) or the instance (creating bound methods, which know their instance.)How does that differ from what you're doing? Well, you assign to the
GET
instance attribute of a specific instance, not the class. The bound method becomes part of the instance's data:Notice how the method is there under the key
GET
, but not underget
.GET
is an instance attribute, butget
is not. This is subtly different in a number of ways: the method doesn't exist in the class object, so you can't doSub.GET(instance)
to callSub
'sGET
method, even though you can doSub.get(instance)
. Secondly, if you have a subclass of Sub that defines its ownGET
method but not its ownget
method, the instance attribute would hide the subclassGET
method with the boundget
method from the baseclass. Thirdly it creates a circular reference between the bound method and the instance: the bound method has a reference to the instance, and the instance now stores a reference to the bound method. Normally bound methods are not stored on the instance partly to avoid that. Circular references are usually not a big issue, because we nowadays have the cyclic-gc module (gc
) that takes care of them, but it can't always clean up reference cycles (for instance, when your class also has a__del__
method.) And lastly, storing bound method objects generally makes your instances unserializable: most serializers (such aspickle
) can't handle bound methods.You may not care about any of these issues, but if you do, there's a better approach to what you're trying to do: metaclasses. Instead of assigning bound methods to instance attributes as you create instances, you can assign normal functions to class attributes as you create the class:
Now,
Sub.get
andSub.GET
really are aliases, and overriding the one and not the other in a subclass works as expected.(Of course, if you don't want overriding the one and not the other to work, you can simply make this an error in your metaclass.) You can do the same thing as the metaclass using class decorators (in Python 2.6 and later), but it would mean requiring the class decorator on every subclass of Base -- class decorators aren't inherited.
这是因为 Sub 类尚未启动,请在其实例中执行此操作,例如
Its because class Sub hasn't been initiated yet, do it in its instance like
在派生类中创建一个派生构造函数来设置属性。
Create a derived constructor in your derived class which sets the attribute.