这个python概念叫什么?使用纯子级属性的父类。

时间:2018-08-07 17:45:30

标签: python python-2.7 duck-typing

我正在编写一些代码,该代码是继承的颠倒三角形。我有一个基本的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()

这叫什么?这是鸭子打字吗?还有更好的选择吗?

1 个答案:

答案 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.Yumldap.Ldapdhcp.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教授,因为这在物理上是不可能的。