python类:面向对象、继承、slot、多重继承

来源:互联网 发布:民族知识知多少班会 编辑:程序博客网 时间:2024/06/04 19:41

http://blog.csdn.net/pipisorry/article/details/46381341

python面向对象基础知识

面向对象的三大特性:封装、继承和多态。

[Python 面向对象(初级篇)]

皮皮Blog



继承

在Python中,同时支持单继承与多继承,一般语法如下:
class SubClassName(ParentClass1 [, ParentClass2, ...]):

    class_suite

继承示例

class Parent(object):
    x = 1
class Child1(Parent):
    pass
class Child2(Parent):
    pass
 
print Parent.x, Child1.x, Child2.x
Child1.x = 2
print Parent.x, Child1.x, Child2.x
Parent.x = 3
print Parent.x, Child1.x, Child2.x
 
以上代码的输出是:
1 1 1
1 2 1
3 2 3
最后一行的输出是 3 2 3 而不是 3 2 1。为什么改变了 Parent.x 的值还会改变 Child2.x 的值,但是同时 Child1.x 值却没有改变?这个答案的关键是,在 Python 中,类变量在内部是作为字典处理的。如果一个变量的名字没有在当前类的字典中发现,将搜索祖先类(比如父类)直到被引用的变量名被找到(如果这个被引用的变量名既没有在自己所在的类又没有在祖先类中找到,会引发一个 AttributeError 异常 )。


内建函数insubclass()

实现继承之后,子类将继承父类的属性,也可以使用内建函数insubclass()来判断一个类是不是另一个类的子孙类:

文档字符串__doc__属性

文档字符串对于类,函数/方法,以及模块来说是唯一的,也就是说__doc__属性是不能从父类中继承来的。

继承中的__init__

1. 如果子类没有定义自己的初始化函数,父类的初始化函数会被默认调用;但是如果要实例化子类的对象,则只能传入父类的初始化函数对应的参数,否则会出错。

2. 如果子类定义了自己的初始化函数,而没有显示调用父类的初始化函数,则父类的属性不会被初始化

3. 如果子类定义了自己的初始化函数,显示调用父类,子类和父类的属性都会被初始化

代码的输出为:

super

通过super来调用父类__init__方法,下面看看super的使用。

在子类中,一般会定义与父类相同的属性(数据属性,方法),从而来实现子类特有的行为。也就是说,子类会继承父类的所有的属性和方法,子类也可以覆盖父类同名的属性和方法。

有时候可能需要在子类中访问父类的一些属性:

这时候,可以通过父类名直接访问父类的属性,当调用父类的方法是,需要将”self”显示的传递进去的方式。

这种方式有一个不好的地方就是,需要经父类名硬编码到子类中,为了解决这个问题,可以使用Python中的super关键字

对于”super(Child, self).foo()”可以理解为,首先找到Child的父类Parent,然后调用父类的foo方法,同时将Child的实例self传递给foo方法。

但是,如果当一个子类有多个父类的时候,super会如何工作呢?这是就需要看看MRO的概念了。

多类继承中的方法解析顺序MRO(Method Resolution Order)

假设现在有一个如下的继承结构,首先通过类名显示调用的方式来调用父类的初始化函数:

从输出中可以看到,类A的初始化函数被调用了两次,这不是我们想要的结果:

下面,我们通过super方式来调用父类的初始化函数:

通过输出可以看到,当使用super后,A的初始化函数只能调用了一次:

为什么super会有这种效果?

下面就开始看看Python中的方法解析顺序MRO(Method Resolution Order)。

Python的类有一个__mro__属性,这个属性中就保存着方法解析顺序。结合上面的例子来看看类D的__mro__:

看到这里,对于上面使用super例子的输出就应该比较清楚了。

  • Python的多继承类是通过MRO的方式来保证各个父类的函数被逐一调用,而且保证每个父类函数只调用一次(如果每个类都使用super)
  • 混用super类和非绑定的函数是一个危险行为,这可能导致应该调用的父类函数没有调用或者一个父类函数被调用多次

[Python中MRO算法]

皮皮Blog


__slots__

从前面的介绍可以看到,当我们通过一个类创建了实例之后,仍然可以给实例添加属性,但是这些属性只属于这个实例。

有些时候,我们可以需要限制类实例对象的属性,这时就要用到类中的__slots__属性了。

__slots__属性对于一个tuple,只有这个tuple中出现的属性可以被类实例使用

在这个例子中,当场是给Student的实例s添加一个score属性的时候,就会遇到下面的异常:

子类没有__slots__属性

使用__slots__要注意,__slots__定义的属性仅对当前类的实例起作用,对继承的子类实例是不起作用的:

从代码的输出可以看到,子类Student的实例并不受父类中__slots__属性的限制:

子类拥有__slots__属性

但是,如果子类本身也有__slots__属性,子类的属性就是自身的__slots__加上父类的__slots__

代码的输出为:

[Python 中的类(中)]

皮皮Blog



python多重继承

There are two typical use cases forsuper

In a class hierarchy withsingle inheritance, super can be used to refer to parent classes withoutnaming them explicitly, thus making the code more maintainable. This useclosely parallels the use ofsuper in other programming languages.

The second use case is to support cooperative multiple inheritance in adynamic execution environment. This use case is unique to Python and isnot found in statically compiled languages or languages that only supportsingle inheritance. This makes it possible to implement “diamond diagrams”where multiple base classes implement the same method. Good design dictatesthat this method have the same calling signature in every case (because theorder of calls is determined at runtime, because that order adaptsto changes in the class hierarchy, and because that order can includesibling classes that are unknown prior to runtime).

For both use cases,a typical superclass call looks like this:
class C(B):    def method(self, arg):        super().method(arg)    # This does the same thing as:super(C, self).method(arg)

[super]

类多重继承实例

父类定义:

class Parent1(object):    def on_start(self):        print('do something')class Parent2(object):    def on_start(self):        print('do something else')class Parent3(object):    pass
子类定义1:

class Child(Parent1, Parent2, Parent3):    def on_start(self):        for base in Child.__bases__:            try:                base.on_start(self)            except AttributeError:                # handle that one of those does not have that method                print('"{}" does not have an "on_start"'.format(base.__name__))
Child().on_start()  # c = Child(); c.on_start()


结果输出:
do something
do something else
"Parent3" does not have an "on_start"
子类定义2

class Child(Parent1, Parent2):    def on_start(self):        super(Child, self).on_start()    # <=> super().on_start()        #super().method(arg)    # This does the same thing as:super(C, self).method(arg)         super(Parent1, self).on_start()class Child(Parent1, Parent2):    def on_start(self):        Parent1.on_start(self)        Parent2.on_start(self)Child().on_start()  # c = Child(); c.on_start()两个结果都输出为:do somethingdo something else

Note:

1. since both of the parents implements the same method, super will just be the same as the first parent inherited, from left to right (for your code,Parent1). Calling two functions withsuper is impossible.

2. 注意子类定义2中的用法1:super(Parent1, self).on_start()为什么输出的是”do sth else"?

[Python Multiple Inheritance: call super on all]

注意的问题

按类名访问就相当于C语言之前的GOTO语句...乱跳,然后再用super按顺序访问,就有问题了。

所以建议就是要么一直用super,要么一直用按照类名访问

最佳实现:

  1. 避免多重继承
  2. super使用一致
  3. 不要混用经典类和新式类
  4. 调用父类的时候注意检查类层次
[Python类继承的高级特性]

from:http://blog.csdn.net/pipisorry/article/details/46381341

ref:Python 为什么要继承 object 类?


1 0
原创粉丝点击