Python中的简单类继承

阿巴斯

我对Python和OOP相当陌生。假设我有两个课程,Base1Base2假设还Base1计算了一些值a1b1并且Base2有一个将两个值相乘的方法。我的问题是,什么是合格的正确方法a1b1Base1,以乘法的Base2

定义派生类的一种方法Derived如下:

class Base1:
    def __init__(self, x1 , y1):
        # perform some computation on x1 and y1
        # store result in a1 and b1
        self.a1=x1
        self.b1=y1

class Base2:
    def __init__(self, x2 , y2):
        self.a2=x2
        self.b2=y2
        self.c2=self.multiply(self.a1,self.b1) # using a1 and b1 of Base1

    def multiply(self, p,q):
        return p*q

class Derived(Base1,Base2):
    def __init__(self):
        self.describe='Derived Class'
        Base1.__init__(self,3,4)
        Base2.__init__(self,5,6)

然后:

f=Derived()
f.c2=12

然而,在更复杂的情况,很容易失去跟踪的地方self.a1self.b1是从哪里来的。对我来说,这也不是显而易见的,为什么两个基类可以这样访问彼此的属性和方法?

编辑:这是Python 2.7.10。

jpmc26

TL; DR

Python是动态的。在尝试访问属性的实际代码行之前,它不会检查属性是否存在。因此,您的代码碰巧可以正常工作。但是,仅仅因为您可以做到这一点,并不意味着您应该这样做Python取决于您在组织代码时做出明智的决定,而不是试图保护您免于做蠢事。我们都是成年人。

为什么可以访问变量

真正的原因归结为Python是一种动态语言。没有为变量分配任何类型,因此Python不会提前知道该变量的期望值。除了该设计决策外,Python直到实际尝试访问该属性时才真正检查属性是否存在。

让我们Base2进行一些修改以使内容更加清晰。首先,Base1Base2继承object(这是必需的,因此我们可以告诉我们实际上正在处理什么类型。)然后将以下prints添加Base2

class Base2(object):
    def __init__(self, x2 , y2):
        print type(self)
        print id(self)
        self.a2=x2
        self.b2=y2
        self.c2=self.multiply(self.a1,self.b1) # using a1 and b1 of Base1

    def multiply(self, p,q):
        return p*q

现在让我们尝试一下:

>>> d = Derived()
<class '__main__.Derived'>
42223600
>>> print id(d)
42223600

因此,我们可以看到,即使在Base2的初始值设定项中,Python都知道其中self包含一个Derived实例。因为Python使用鸭打字,它不检查的时间提前是否selfa1b1属性; 它只是尝试访问它们。如果他们在那里,那就行得通。如果不是,则会引发错误。您可以通过Base2直接实例化的实例来查看此信息

>>> Base2(1, 2)
<class '__main__.Base2'>
41403888
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 7, in __init__
AttributeError: 'Base2' object has no attribute 'a1'

请注意,即使出现错误,它仍然会尝试访问之前执行print语句在执行一行代码之前, Python不会检查该属性是否存在a1

当代码运行时,我们甚至可以更加疯狂并为对象添加属性:

>>> b = Base1(1,2)
>>> b.a1
1
>>> b.notyet
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Base1' object has no attribute 'notyet'
>>> b.notyet = 'adding an attribute'
>>> b.notyet
'adding an attribute'

应该如何组织此代码

Base2不应尝试在不继承的情况下访问这些变量Base1即使仅实例化实例Derived,也可以执行此操作,但也应假定其他人可以Base2直接使用它,也可以创建一个继承自Base2not的类Base1换句话说,您应该忽略这是可能的。很多事情都像Python中那样。它并没有限制您执行这些操作,但是您不应该执行它们,因为它们会使您或其他人感到困惑,或者以后会引起问题。Python以不试图限制功能而闻名,并取决于(开发人员)明智地使用该语言。社区对此方法有一个口号:我们都是成年人。

我将假定Base2主要是为了提供该multiply方法而进行的混合在这种情况下,我们应该c2在子类上定义Derived,因为它可以访问multiply属性a1b1

对于纯派生值,应使用property

class Derived(Base1,Base2):
    def __init__(self):
        self.describe='Derived Class'
        Base1.__init__(self,3,4)
        Base2.__init__(self,5,6)

    @property
    def c2(self):
        return self.multiply(self.a1,self.b1) # using a1 and b1 of Base1

这样可以防止调用者更改值(除非您显式创建了一个setter),并避免了跟踪其来源的问题。它永远是计算上的苍蝇,即使使用它看起来像只是使用普通的属性:

x = Derived()
print x.c2

这将给出12预期的结果。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章