从子类主体访问父类属性

时间:2012-03-18 17:41:55

标签: python python-3.x

我有一个类Klass,其类属性为my_list。我有一个它的子类SubKlass,其中我想要一个类属性my_list,它是来自父类的相同属性的修改版本:

class Klass():
    my_list = [1, 2, 3]


class SubKlass(Klass):
    my_list = Klass.my_list + [4, 5] # this works, but i must specify parent class explicitly
    #my_list = super().my_list + [4, 5] # SystemError: super(): __class__ cell not found
    #my_list = my_list + [4, 5] # NameError: name 'my_list' is not defined 


print(Klass.my_list)
print(SubKlass.my_list)

那么,有没有办法在不指定名称的情况下访问父类属性?

更新

Python问题跟踪器存在错误:http://bugs.python.org/issue11339。我们希望在某些时候它会solved

5 个答案:

答案 0 :(得分:12)

你不能。

Python中的类定义的工作原理如下。

  1. 解释器会看到一个class语句,后跟一段代码。

  2. 它创建一个新的命名空间并在命名空间中执行该代码。

  3. 它使用生成的命名空间,类名,基类和元类(如果适用)调用type内置函数。

  4. 它将结果分配给班级名称。

  5. 在类定义中运行代码时,您不知道基类是什么,因此您无法获取它们的属性。

    >


    编辑:这是一个可用于更新属性的小类装饰器。这个想法是你给它一个名字和一个功能。它查看了类的所有基类,并使用该名称获取其属性。然后它使用从基类继承的值列表和您在子类中定义的值调用该函数。此调用的结果与名称绑定。

    代码可能更有意义:

    >>> def inherit_attribute(name, f):
    ...     def decorator(cls):
    ...             old_value = getattr(cls, name)
    ...             new_value = f([getattr(base, name) for base in cls.__bases__], old_value)
    ...             setattr(cls, name, new_value)
    ...             return cls
    ...     return decorator
    ... 
    >>> def update_x(base_values, my_value):
    ...    return sum(base_values + [my_value], tuple())
    ... 
    >>> class Foo: x = (1,)
    ... 
    >>> @inherit_attribute('x', update_x)
    ... class Bar(Foo): x = (2,)
    ... 
    >>> Bar.x
    (1, 2)
    

    您的想法是在x中将(2,)定义为Bar。然后装饰者将查看Bar的子类,找到他们所有的x,并用它们调用update_x。所以它会调用

    update_x([(1,)], (2,))
    

    它通过连接它们来组合它们,然后再将它们绑定回x。这有意义吗?

答案 1 :(得分:2)

正如@katrielalex所解释的那样,{<1}}默认情况下不在命名空间中,之后创建了类。但是,如果你想深入了解元类,你可以在Python 3中做的是手动将my_list添加到命名空间:

my_list

请注意,此示例可能还没有很好地处理菱形继承结构。

新的class Meta(type): def __prepare__(name, bases, **kwds): print("preparing {}".format(name), kwds) my_list = [] for b in bases: if hasattr(b, 'my_list'): my_list.extend(b.my_list) return {'my_list': my_list} class A(metaclass=Meta): my_list = ["a"] class B(A): my_list.append(2) print(A().my_list) print(B().my_list) 属性在PEP 3115中定义。

答案 2 :(得分:1)

您可以使用元类或类装饰器。以下是在Python 2.x中使用元类的方法:

class Klass(object):
    my_list = [1, 2, 3]

class KlassMeta(type):

    def __new__(cls, name, bases, attrs):
        # grab last base class, which in this case is Klass
        attrs['my_list'] = bases[-1].my_list + [4, 5]
        return super(KlassMeta, cls).__new__(cls, name, bases, attrs)

class SubKlass(Klass):
    __metaclass__ = KlassMeta

使用Python 3,您可以使用更新的语法声明元类:

class SubKlass(Klass, metaclass=KlassMeta):
    pass

答案 3 :(得分:0)

班上的身体没有办法;从自我可用的上下文(或类本身)开始,您可以检查__bases__

答案 4 :(得分:0)

正如你从其他回应中看到的那样,例如katriealex:不,你不能。至少不容易。

问:你究竟想做什么?

问:你为什么要这样做?