在子类中设置父属性

时间:2019-06-03 06:29:04

标签: python python-3.x class subclassing

我刚刚意识到我可以设置只有父类使用的子类的属性

In [34]: class A:
    ...:     def __init__(self):
    ...:         pass
    ...:
    ...:     def a(self):
    ...:         print(f'b = {self.b}')
    ...:
    ...: class B(A):
    ...:     def __init__(self):
    ...:         super(B, self).__init__()
    ...:         self.b = 1
    ...:

In [35]: b = B()
    ...: b.a()
b = 1

此实现似乎违反直觉,对此有些不妥,但我不确定它是什么。

我认为以下内容更有意义

In [38]: class A:
    ...:     def __init__(self, b):
    ...:         self.b = b
    ...:
    ...:     def a(self):
    ...:         print(f'b = {self.b}')
    ...:
    ...: class B(A):
    ...:     def __init__(self):
    ...:         super(B, self).__init__(1)
    ...:

In [39]: b = B()
    ...: b.a()
b = 1

在某些情况下,前者会比后者更受推荐吗?

1 个答案:

答案 0 :(得分:2)

从概念上讲,您正在做两种不同的事情。在第一种情况下,您具有类似 abstract 的类;换句话说,一个基类不是要单独实例化的,因为某些属性的定义是“缺失的”;可以理解,子类将实现这些属性。

更惯用的方法是使用A模块将abc标记为抽象基类,例如:

from abc import ABCMeta, abstractmethod

class A(metaclass=ABCMeta):

    @property
    @abstractmethod
    def x(self):
        pass

    def print_me(self):
        print(f'x = {self.x}')

class B(A):

    @property
    def x(self):
        return 1

A().print_me()

输出将是:

TypeError: Can't instantiate abstract class A with abstract methods x

另一方面,这可行:

B().print_me()  # prints x = 1

这样做,您可以清楚地表明子类必须覆盖x属性,否则print_me函数将无法正常工作。

转到第二种情况,您有一个具体的基类和子类,而该子类的作用类似于对可创建实例性质的约束。在这种情况下,A的独立实例是完全有效的;只是B的实例提供了额外的保证,即特定属性将始终为某个值(或者,如果您打算使您的类可变,则至少将其初始化为某个值)。