【问题标题】:Accessing super(parent) class variable in python在python中访问超级(父)类变量
【发布时间】:2019-04-10 21:55:06
【问题描述】:

我是 python 新手。我试图使用 super() 方法访问子类中的父类变量,但它抛出错误“无参数”。使用类名访问类变量是可行的,但我想知道是否可以使用 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__()

错误:

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

【问题讨论】:

  • 我看不到你在这里要做什么。 super() 是您在实例方法中调用的东西,而不是在类级别。而且你也不应该定义自己的双下划线属性。
  • 在python 3中,类默认派生自object,所以你可以简单地删除object;关于这个问题;您正在尝试在类顶级定义中使用super();这是做不到的。
  • @DanielRoseman 使代码更易于维护,例如,如果我想更改基类型的名称。到处使用 super 时,只需要在 class 行中更改即可。

标签: python python-3.x class


【解决方案1】:

您可以定义初始化Child.__props__Parent 类的__init_subclass__ 方法。每次创建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'))

【讨论】:

    【解决方案2】:

    super 帮助您在拥有父类的实例时获取父类。据我所知,在没有实例的情况下,没有简单的方法可以在类级别执行此操作,就像您正在尝试做的那样。我能想到的唯一方法是显式引用父类:

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

    为了进一步澄清,有两个基本问题:

    • super()super(Child, self) 的语法糖,或者更一般地说,super(type(self), self)。由于没有 self 在您使用它的地方,它没有任何意义。
    • 在调用super() 时,即使是Child 类也不存在。它仍在被定义的过程中,所以即使有 super(Child, self) 也是无效的语法(继续尝试,我可以等待),因为 Child 还不是一个东西。

    因此,您需要显式引用父类,就像我在上面展示的那样。

    【讨论】:

      【解决方案3】:

      聚会有点晚了,但这是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'))
      

      【讨论】:

        【解决方案4】:

        您可以使用__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__)
        

        输出:

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

        同时注意这一点:

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

        输出:

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

        __props__ 仅在您的 Child 类第一次实例化后才会更改。

        【讨论】:

        • 正如您自己指出的那样,在构造函数中初始化类属性会给您带来不适合问题的结果。为什么你会推荐这种方法?
        • 问题是,是否可以使用super() 访问和修改类属性。从示例中我不清楚该属性是如何使用的,是否必须在实例化类之前对其进行修改。
        【解决方案5】:

        你的错误是你写了你只使用父类名称的超级。

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

        希望有用。谢谢。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-03-17
          • 2011-04-08
          • 2011-03-05
          • 2015-02-03
          • 1970-01-01
          • 2014-08-20
          • 2022-10-24
          相关资源
          最近更新 更多