简体   繁体   English

在python中访问超(父)类变量

[英]Accessing super(parent) class variable in python

I am new to python.我是python的新手。 Im trying to access the parent class variable in child class using super() method but it throws error "no arguments".我试图使用 super() 方法访问子类中的父类变量,但它抛出错误“无参数”。 Accessing class variable using class name works but i like to know whether it is possible to access them using super() method.使用类名访问类变量有效,但我想知道是否可以使用 super() 方法访问它们。

class Parent(object):
        __props__ = (
            ('a', str, 'a var'),
            ('b', int, 'b var')
        )

        def __init__(self):
            self.test = 'foo'

class Child(Parent):
    __props__ = super().__props__ + (
        ('c', str, 'foo'),
    ) # Parent.__props__


    def __init__(self):
        super().__init__()

Error:错误:

    __props__ = super().__props__ + (
RuntimeError: super(): no arguments

super helps you get the parent class when you have an instance of it.当您拥有父类的实例时, super可帮助您获取父类。 As far as I know, there's no easy way to do this at the class level without an instance, like you're trying to do.据我所知,在没有实例的情况下,没有简单的方法可以在类级别执行此操作,就像您尝试做的那样。 The only way I could think of to do this is to refer to the parent class explicitly:我能想到的唯一方法是显式引用父类:

class Child(Parent):
    __props__ = Parent.__props__ + ...

To clarify a bit further, there's two basic problems:为了进一步澄清,有两个基本问题:

  • super() is syntactic sugar for super(Child, self) , or more generally, super(type(self), self) . super()super(Child, self)语法糖,或更一般地说是super(type(self), self) Since there is no self where you're using it, it doesn't make sense.因为在你使用它的地方没有self ,所以它没有意义。
  • Even the class Child doesn't exist at the point that super() is getting called.在调用super() ,即使是Child类也不存在。 It's still in the process of being defined, and so it would be invalid syntax to even have super(Child, self) (go ahead and try it, I can wait), because Child isn't a thing yet.它仍在定义过程中,因此即使拥有super(Child, self) (继续尝试,我可以等待)也是无效的语法,因为Child还不是一个东西。

As such, you'll need to explicitly refer to the parent class, like I show above.因此,您需要明确引用父类,就像我上面展示的那样。

You could define an __init_subclass__ method of the Parent class that initializes Child.__props__ .您可以定义初始化Child.__props__Parent类的__init_subclass__方法。 This method is called every time a subclass of of Parent is created, and we can use it to modify the __props__ that class inherits with an optional __props__ argument passed as part of the class definition.每次创建Parent的子类时都会调用此方法,我们可以使用它来修改类继承的__props__ ,并带有作为类定义的一部分传递的可选__props__参数。

class Parent:
    __props__ = (('a', str, 'a var'), ('b', int, 'b var'))
    def __init_subclass__(cls, __props__=(), **kwargs):
        super().__init_subclass__(**kwargs)
        cls.__props__ = cls.__props__ + __props__

class Child(Parent, __props__=(('c', str, 'foo'),)):
    pass

print(Child.__props__)
# (('a', <class 'str'>, 'a var'), ('b', <class 'int'>, 'b var'), ('c', <class 'str'>, 'foo'))

class GrandChild(Child, __props__=(('d', float, 'd var'),)):
    pass

print(GrandChild.__props__)
# (('a', <class 'str'>, 'a var'), ('b', <class 'int'>, 'b var'), 
#  ('c', <class 'str'>, 'foo'), ('d', <class 'float'>, 'd var'))

A bit late to the party but this is a job for metaclasses :聚会有点晚了,但这是元类的工作:

class Parent(object):
    __props__ = (
        ('a', str, 'a var'),
        ('b', int, 'b var')
    )

    def __init__(self):
        self.test = 'foo'

class AddPropsMeta(type):
    def __init__(cls, name, bases, attrs):
        cls.__props__ = sum((base.__props__ for base in bases), ()) + cls.__props__
        super().__init__(name, bases, attrs)

class Child(Parent, metaclass=AddPropsMeta):
    __props__ = (
        ('c', str, 'foo'),
    )
>>> Child.__props__
(('a', str, 'a var'), ('b', int, 'b var'), ('c', str, 'foo'))

You can use the __new__ method to change attributes of the parent class.您可以使用__new__方法来更改父类的属性。

class Parent(object):
    __props__ = (
        ('a', str, 'a var'),
        ('b', int, 'b var')
    )

    def __init__(self):
        self.test = 'foo'


class Child(Parent):

    def __new__(cls, *args, **kwargs):
        parent = super(Child, cls)
        cls.__props__ = parent.__props__ + (('c', str, 'foo'),)
        return super(Child, cls).__new__(cls, *args, **kwargs)

p = Parent
print(p.__props__)
c = Child()
print(c.__props__)

Output:输出:

(('a', <type 'str'>, 'a var'), ('b', <type 'int'>, 'b var'))
(('a', <type 'str'>, 'a var'), ('b', <type 'int'>, 'b var'), ('c', <type 'str'>, 'foo'))

At the same time be aware of this:同时要注意这一点:

print(p.__props__)
c = Child
print(c.__props__)
c = Child()
print(c.__props__)
c = Child
print(c.__props__)

Output:输出:

(('a', <type 'str'>, 'a var'), ('b', <type 'int'>, 'b var'))
(('a', <type 'str'>, 'a var'), ('b', <type 'int'>, 'b var'))
(('a', <type 'str'>, 'a var'), ('b', <type 'int'>, 'b var'), ('c', <type 'str'>, 'foo'))
(('a', <type 'str'>, 'a var'), ('b', <type 'int'>, 'b var'), ('c', <type 'str'>, 'foo'))

The __props__ will change only after the first instantiation of your Child class. __props__只会在你的Child类的第一次实例化之后改变。

Your mistake is you write the super you use the Parent class name only.你的错误是你写了你只使用父类名的超级。

class Parent:
        __props__ = (
            ('a', str, 'a var'),
            ('b', int, 'b var')
        )

    def __init__(self):
        self.test = 'foo'


class Child(Parent):
    __props__ = Parent.__props__ + (
        ('c', str, 'foo'),
    ) # Parent.__props__


    def __init__(self):
        Parent.__init__()

Hope It's useful.希望它有用。 Thank you.谢谢你。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM