首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >从子类体访问父类属性

从子类体访问父类属性
EN

Stack Overflow用户
提问于 2012-03-19 01:41:55
回答 5查看 11.7K关注 0票数 25

我有一个具有my_list属性的类Klass。我有一个SubKlass的子类,在这个子类中我想有一个类属性my_list,它是父类中相同属性的修改版本:

代码语言:javascript
复制
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问题跟踪器上有一个bug:http://bugs.python.org/issue11339。让我们希望它会在某个时候成为solved

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2012-03-19 01:53:27

你不能这么做。

类定义在Python中的工作方式如下。

  1. 解释器看到一条class语句,后面跟着一段代码。
  2. 它创建一个新的命名空间并执行该命名空间中的代码。
  3. 它使用生成的命名空间、类名、基类和元类调用type内置(如果将结果分配给类的名称。

< code >G211

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

您可以做的是在定义类之后立即修改它。

编辑:这是一个小的类装饰器,你可以用它来更新属性。这个想法是你给它一个名字和一个函数。它会遍历您的类的所有基类,并获取具有该名称的属性。然后,它使用从基类继承的值列表和您在子类中定义的值调用函数。此调用的结果绑定到名称。

代码可能更有意义:

代码语言:javascript
复制
>>> 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)

其想法是在Bar中将x定义为(2,)。然后,装饰器将遍历Bar的子类,找到它们的所有x,并使用它们调用update_x。因此,它将调用

代码语言:javascript
复制
update_x([(1,)], (2,))

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

票数 14
EN

Stack Overflow用户

发布于 2015-10-01 17:29:48

正如@katrielalex回答的那样,在创建类之前,默认情况下my_list不在名称空间中。然而,在Python3中,如果您想深入研究元类,则可以手动将my_list添加到名称空间:

代码语言:javascript
复制
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中定义了新的__prepare__属性。

票数 3
EN

Stack Overflow用户

发布于 2012-03-19 01:56:42

您可以使用元类或类装饰器。下面是如何在Python 2.x中使用元类:

代码语言:javascript
复制
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中,您将使用较新的语法声明元类:

代码语言:javascript
复制
class SubKlass(Klass, metaclass=KlassMeta):
    pass
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9760595

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档