我正在编写一些代码,该代码是继承的颠倒三角形。我有一个基本的Linux类,该类具有一个拥有连接的CLIENT attr。我有几个在逻辑上分开的API(kvm,yum,gdb,dhcp等),它们使用CLIENT,但我只希望用户需要创建Linux类的单个实例,但能够从中调用所有方法。家长班。在保持父母之间良好的逻辑代码分离的同时:
class Linux(
SSHClient,
yum.Yum,
kvm.Kvm,
ldap.Ldap,
lshw.Lshw,
packet_capture.Tcpdump,
tc.TrafficControl,
networking.Networking,
gdb.Gdb,
dhcp.Dhcp,
httputil.Http,
scp.Scp,
fileutils.FileUtils):
我举了一个小例子:
class Dad(object):
def __init__(self):
raise NotImplementedError("Create Baby instead")
def dadCallBaby(self):
print('sup {}'.format(self.babyName))
class Mom(object):
def __init__(self):
raise NotImplementedError("Create Baby instead")
def momCallBaby(self):
print('goochi goo {}'.format(self.babyName))
class Baby(Mom, Dad):
def __init__(self, name):
self.babyName = name
def greeting(self):
self.momCallBaby()
self.dadCallBaby()
x=Baby('Joe')
x.greeting()
这叫什么?这是鸭子打字吗?还有更好的选择吗?
答案 0 :(得分:3)
确实没有“纯子级属性”这样的东西。
属性babyName
仅存储在每个对象的名称空间中,并在那里查找。 Python不在乎它是由Baby.__init__
存储的。实际上,您可以在Mom
以外的Baby
上写存储相同的属性,并且将以相同的方式工作:
class NotABaby(Mom):
def __init__(self): pass
mom = NotABaby()
mom.babyName = 'Me?'
mom.momCallBaby()
此外,很难提出一种更好的方法来做自己的事情,因为您所做的事情本质上是令人困惑的,可能不应该这样做。
继承通常意味着子类型化-即,Baby
仅应是Mom
的子类,如果每个Baby
实例都可以用作Mom
。 1 < / sup>
但是婴儿不是妈妈和爸爸。 2 婴儿有妈妈和爸爸。表示这种情况的方法是为其父亲和母亲提供Baby
属性:
class Baby(object):
def __init__(self, mom, dad, name):
self.mom, self.dad, self.name = mom, dad, name
def greeting(self):
self.mom.momCallBaby(self.name)
self.dad.dadCallBaby(self.name)
请注意,例如,这意味着同一个女人可以是两个孩子的妈妈。既然您在此处建模的真实事物也是如此,则表明您在正确建模事物。
您的“真实”示例不太清楚,但我怀疑那里也发生了同样的事情。
据我所知,您要使用继承的唯一原因是:
我只希望用户需要创建Linux类的单个实例
您不需要或不需要继承:
class Linux(object):
def __init__(self):
self.ssh_client = SSHClient()
self.yum = yum.Yum()
# etc.
…但是可以从Parent类调用所有方法
如果yum.Yum
,ldap.Ldap
和dhcp.Dhcp
都具有名为lookup
的方法,那么Linux.lookup
将调用哪个方法?
您可能想要的只是将属性保留为公共属性,并明确使用它们:
system = Linux()
print(system.yum.lookup(package))
print(system.ldap.lookup(name))
print(system.dhcp.lookup(reservation))
或者您将希望提供一个包含所有底层API的“ Linux API”:
def lookup_package(self, package):
return self.yum.lookup(package)
def lookup_ldap_name(self, name):
return self.ldap.lookup(name)
def lookup_reservation(self, reservation):
return self.dhcp.lookup(reservation)
如果您确实确实想转发所有不同组件的每种方法,并且确定它们之间没有冲突,并且有太多方法需要手动写出,则可以始终这样做以编程方式,通过迭代所有类,迭代每个类的inspect.getmembers
,过滤掉以_
开头或不是未绑定方法的那些,创建代理函数,以及setattr
-将其放到Linux
上。
或者,或者(在这种情况下可能不是一个好主意,但在没什么不同的情况下非常有用),您可以在方法查找时通过实现__getattr__
方法来动态代理(通常是__dir__
方法)。
我认为这两种代理之一可能就是您在此之后真正的。
1。在某些情况下,您想要继承的原因不是子类型化。例如,您继承了mixin类以获得一堆方法的实现。在任何情况下,只要在mixin实例可用的地方都可以使用您的类,这个问题就没有任何意义,因为mixin在任何地方都不可用(作为基类除外)。但是,子类型化仍然是您弯腰的标准。
2。如果是,请致电儿童保护服务。并致电X教授,因为这在物理上是不可能的。