作为 OOP 新手,我想知道是否有任何方法可以根据子类在 Python 中的调用方式继承多个类之一。我尝试这样做的原因是因为我有多个同名的方法,但在三个具有不同功能的父类中。对象创建时需要根据一定的条件继承相应的类。
例如,我尝试根据实例化时是否传递任何参数来让C类继承A或B,但没有成功。谁能建议更好的方法来做到这一点?
class A:
def __init__(self,a):
self.num = a
def print_output(self):
print('Class A is the parent class, the number is 7',self.num)
class B:
def __init__(self):
self.digits=[]
def print_output(self):
print('Class B is the parent class, no number given')
class C(A if kwargs else B):
def __init__(self,**kwargs):
if kwargs:
super().__init__(kwargs['a'])
else:
super().__init__()
temp1 = C(a=7)
temp2 = C()
temp1.print_output()
temp2.print_output()
所需的输出将是“A类是父类,编号是7”,后面是“B类是父类,没有给出编号”。
谢谢!
无论您是刚刚开始接触 OOP 还是已经使用了一段时间,我都建议您阅读一本关于设计模式的好书。经典是 Gamma 的 Design Patterns。舵。约翰逊和弗利赛德斯。
除了使用继承之外,您还可以使用 composition 和 delegation。例如:
class A:
def do_something(self):
# some implementation
class B:
def do_something(self):
# some implementation
class C:
def __init__(self, use_A):
# assign an instance of A or B depending on whether argument use_A is True
self.instance = A() if use_A else B()
def do_something(self):
# delegate to A or B instance:
self.instance.do_something()
更新
为了回应 Lev Barenboim 的评论,下面演示了如何使具有委托的组合看起来更像常规继承,因此,如果类
C
已经分配了类 A
的实例,例如, self.instance
,那么 A
的属性(例如 x
)可以在内部访问为self.x
以及 self.instance.x
(假设类 C
本身没有定义属性 x
),同样,如果您创建名为 C
的 c
实例,则可以将该 attribute
称为 c.x
仿佛上课C
继承自类 A
。
__getattr__
和 __getattribute__
。 __getattr__
可以在类上定义,并且每当引用但未定义属性时都会调用。 __getattribute__
可以在对象上调用以按名称检索属性。
请注意,在下面的示例中,类
C
甚至不再需要定义方法 do_something
(如果它所做的只是委托给 self.instance
):
class A:
def __init__(self, x):
self.x = x
def do_something(self):
print('I am A')
class B:
def __init__(self, x):
self.x = x
def do_something(self):
print('I am B')
class C:
def __init__(self, use_A, x):
# assign an instance of A or B depending on whether argument use_A is True
self.instance = A(x) if use_A else B(x)
# called when an attribute is not found:
def __getattr__(self, name):
# assume it is implemented by self.instance
return self.instance.__getattribute__(name)
# something unique to class C:
def foo(self):
print ('foo called: x =', self.x)
c = C(True, 7)
print(c.x)
c.foo()
c.do_something()
# This will throw an Exception:
print(c.y)
打印:
7
foo called: x = 7
I am A
Traceback (most recent call last):
File "C:\Ron\test\test.py", line 34, in <module>
print(c.y)
File "C:\Ron\test\test.py", line 23, in __getattr__
return self.instance.__getattribute__(name)
AttributeError: 'A' object has no attribute 'y'
我认为您不能从类内部将值传递给类的条件。
相反,您可以像这样定义工厂方法:
class A:
def sayClass(self):
print("Class A")
class B:
def sayClass(self):
print("Class B")
def make_C_from_A_or_B(make_A):
class C(A if make_A else B):
def sayClass(self):
super().sayClass()
print("Class C")
return C()
make_C_from_A_or_B(True).sayClass()
哪个输出:
Class A
Class C
注意:您可以通过我在这篇文章(关于解析器工厂)
中发现足够好的示例来找到有关工厂模式的信息我想我会使用@Booboo的答案的变体,如下:
例如这段代码:
# define a class of common utility functions for A and B
class CommonUtils:
common_int: int = 123
def common_util(self):
print("This is a common utility function for A and B.")
# subclass A from CommonUtils
class A(CommonUtils):
kwargs: dict = {}
def __init__(self, **kwargs):
super().__init__()
self.kwargs = kwargs
def print_output(self):
print(f"Class A, {self.kwargs=}")
# subclass B from CommonUtils
class B(CommonUtils):
def __init__(self):
super().__init__()
self.kwargs = None
def print_output(self):
print("Class B, no kwargs")
# define a factory function C that returns either A or B
def C(**kwargs) -> A | B:
if kwargs:
return A(**kwargs)
else:
return B()
# if arguments are passed, C() returns class A
temp1 = C(a=7)
temp1.print_output()
temp1.common_util()
print(temp1.common_int)
# if no arguments are passed, C() returns class B
temp2 = C()
temp2.print_output()
temp2.common_util()
print(temp2.common_int)
返回此输出:
Class A, self.kwargs={'a': 7}
This is a common utility function for A and B.
123
Class B, no kwargs
This is a common utility function for A and B.
123