在超类构造函数中的子类中添加方法 [英] add methods in subclasses within the super class constructor

查看:251
本文介绍了在超类构造函数中的子类中添加方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想将方法​​(更具体地说:方法别名)自动添加到Python子类。如果子类定义一个名为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.

为了不重复自己,我想在基类中定义这个修改例程。但是如果我检查基类 __ init __ 方法,没有这样的方法,因为它是在子类中定义的。它将变得更清楚一些源代码:

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))

输出:

['__doc__', '__init__', '__module__', 'get']

它还应包含'GET'

It should also contain 'GET'.

有没有办法在基类中做?

Is there a way to do it within the base class?

推荐答案

您的类的 __ init __ 方法将 bound方法添加为实例的类。这与将属性添加到类完全不同。通常,方法通过将函数存储在类中作为属性,然后创建方法对象来工作,因为这些函数作为属性从类中检索(创建仅绑定方法,只知道它们属于哪个类)或实例(创建绑定方法,它们知道它们的实例。)

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.)

这与你在做什么有什么不同?您可以分配给特定实例的 GET 实例属性,而不是类。绑定方法成为实例数据的一部分:

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:

>>> s.__dict__
{'GET': <bound method Sub.get of <__main__.Sub object at 0xb70896cc>>}

请注意在 GET 下的方法是否存在,但不在 get GET 是一个实例属性,但 get 不是。这在一些方面是微妙的不同:该方法不存在于类对象,所以你不能做 Sub.GET(instance)调用<$即使你可以做 Sub.get(instance) c $ c> c $ c> Sub ' c $ c>。其次,如果你有一个Sub子类定义自己的 GET 方法但不是自己的 get 方法,实例属性将隐藏 get 子类 GET 方法 >方法从基础类。第三,它在绑定方法和实例之间创建一个循环引用:绑定方法具有对实例的引用,实例现在存储对绑定方法的引用。通常绑定的方法不存储在实例上部分地避免。循环引用通常不是一个大问题,因为我们现在有循环gc模块( gc )来处理它们,但它不能总是清除引用循环(例如,当你的类也有一个 __ del __ 方法。)最后,存储绑定的方法对象通常使你的实例unserializable:大多数序列化(如 pickle )无法处理绑定的方法。

Notice how the method is there under the key GET, but not under get. GET is an instance attribute, but get is not. This is subtly different in a number of ways: the method doesn't exist in the class object, so you can't do Sub.GET(instance) to call Sub's GET method, even though you can do Sub.get(instance). Secondly, if you have a subclass of Sub that defines its own GET method but not its own get method, the instance attribute would hide the subclass GET method with the bound get 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 as pickle) 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:

class MethodAliasingType(type):
    def __init__(self, name, bases, attrs):
        # attrs is the dict of attributes that was used to create the
        # class 'self', modifying it has no effect on the class.
        # So use setattr() to set the attribute.
        for k, v in attrs.iteritems():
            if not hasattr(self, k.upper()):
                setattr(self, k.upper(), v)
        super(MethodAliasingType, self).__init__(name, bases, attrs)

class Base(object):
    __metaclass__ = MethodAliasingType

class Sub(Base):
    def get(self):
        pass

c $ c> Sub.get Sub.GET 真的是别名,重写一个而不是子类中的另一个工作原理。

Now, Sub.get and Sub.GET really are aliases, and overriding the one and not the other in a subclass works as expected.

>>> Sub.get
<unbound method Sub.get>
>>> Sub.GET
<unbound method Sub.get>
>>> Sub().get
<bound method Sub.get of <__main__.Sub object at 0xb708978c>>
>>> Sub().GET
<bound method Sub.get of <__main__.Sub object at 0xb7089a6c>>
>>> Sub().__dict__
{}

(当然, em> 覆盖一个,而不是另一个工作,你可以简单地使这是一个错误在你的元类。)你可以做类似的东西,使用类装饰器(在Python 2.6和更高版本)这意味着要求Base类装饰器的每个子类上的类装饰器不被继承。

(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.

这篇关于在超类构造函数中的子类中添加方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆