我刚刚意识到我可以设置只有父类使用的子类的属性
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
在某些情况下,前者会比后者更受推荐吗?
答案 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
的实例提供了额外的保证,即特定属性将始终为某个值(或者,如果您打算使您的类可变,则至少将其初始化为某个值)。>