首页 > 代码库 > Python-面向对象 (二 继承)

Python-面向对象 (二 继承)

一 继承
 
基类定义如下:
class people:
    #define attribute
    name = ‘‘
    age  = 0
    #define private attribute
    __weight = 0

    def __init__(self,n="hello",a=24,w=45.9):
        self.name = n
        self.age  = a
        self.__weight = w

    def __del__(self):
        print("people deconstructor........")

    def __repr__(self):
        print("people class")

    def speak(self):
        print("%s is speaking: I am %d years old" % (self.name,self.age))

    def weight(self):
        print("Weight number:%d" % (self.__weight))


单重继承
class student(people):
    grade = ‘‘
    def __init__(self,n,a,w,g):
        people.__init__(self,n,a,w)
        self.grade = g


    def speak(self):
        print("%s is speaking: I am %d years old,and I am in grade %d" % (self.name,self.age,self.grade))

    def __del__(self):
        print("student deconstructor......")

 s  = student(‘ken‘,20,60,3)
 s.speak()




多重继承
class speaker():
    topic = ‘‘
    name  = ‘‘
    def __init__(self,n,t):
        self.name = n
        self.topic = t
    def speak(self):
        print("I am %s,I am a speaker!My topic is %s " % (self.name,self.topic))
    def __del__(self):
        print("speaker deconstructor.....")

class sample(speaker,student):
    a = ‘‘
    def __init__(self,n,a,w,g,t):
        student.__init__(self,n,a,w,g)
        speaker.__init__(self,n,t)

    def __del__(self):
        print (‘sample deconstructor‘)
       #  speaker.__del__()
       #  student.__del__()

test = sample("Tim",25,80,4,"Python")
test.speak()

需要注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,python从左至右搜索,即方法在子类中未找到时,从左到右查找父类中是否包含方法。


注意:
1. 在Python中,如果父类和子类都重新定义了构造方法__init( )__,在进行子类实例化的时候,子类的构造方法不会自动调用父类的构造方法,必须在子类中显示调用。

2. 如果需要在子类中调用父类的方法,需要以 父类名.方法 这种方式调用,以这种方式调用的时候,注意要传递self参数过去。

  对于继承关系,子类继承了父类所有的公有属性和方法,可以在子类中通过父类名来调用,而对于私有的属性和方法,子类是不进行继承的,因此在子类中是无法通过父类名来访问的。

  Python支持多重继承。对于多重继承,比如

  class SubClass(SuperClass1,SuperClass2)

  此时有一个问题就是如果SubClass没有重新定义构造方法,它会自动调用哪个父类的构造方法?这里记住一点:以第一个父类为中心。如果SubClass重新定义了构造方法,需要显示去调用父类的构造方法,此时调用哪个父类的构造方法由你自己决定;若SubClass没有重新定义构造方法,则只会执行第一个父类的构造方法。并且若SuperClass1和SuperClass2中有同名的方法,通过子类的实例化对象去调用该方法时调用的是第一个父类中的方法。



二 多态

         多态即多种形态,在运行时确定其状态,在编译阶段无法确定其类型,这就是多态。Python中的多态和Java以及C++中的多态有点不同,Python中的变量在定义时不用指明其类型,它会根据需要在运行时确定变量的类型(个人觉得这也是多态的一种体现),并且Python本身是一种解释性语言,不进行预编译,因此它就只在运行时确定其状态,故也有人说Python是一种多态语言。

        在Python中很多地方都可以体现多态的特性,比如内置函数len(object),len函数不仅可以计算字符串的长度,还可以计算列表、元组等对象中的数据个数,这里在运行时通过参数类型确定其具体的计算过程,正是多态的一种体现。这有点类似于函数重载(一个编译单元中有多个同名函数,但参数不同),相当于为每种类型都定义了一个len函数。这是典型的多态表现。有些朋友提出Python不支持多态,我是完全不赞同的。

  本质上,多态意味着可以对不同的对象使用同样的操作,但它们可能会以多种形态呈现出结果。len(object)函数就体现了这一点。在C++、Java、C#这种编译型语言中,由于有编译过程,因此就鲜明地分成了运行时多态和编译时多态。运行时多态是指允许父类指针或名称来引用子类对象,或对象方法,而实际调用的方法为对象的类类型方法,这就是所谓的动态绑定。编译时多态有模板或范型、方法重载(overload)、方法重写(override)等。而Python是动态语言,动态地确定类型信息恰恰体现了多态的特征。在Python中,任何不知道对象到底是什么类型,但又需要对象做点什么的时候,都会用到多态。

  能够直接说明多态的两段示例代码如下:
  1、方法多态
[python] view plaincopy在CODE上查看代码片派生到我的代码片
  1. # -*- coding: UTF-8 -*-  
  2.   
  3. _metaclass_=type # 确定使用新式类  
  4. class calculator:  
  5.     
  6.     def count(self,args):  
  7.         return 1  
  8.   
  9. calc=calculator() #自定义类型  
  10.   
  11. from random import choice  
  12. obj=choice([‘hello,world‘,[1,2,3],calc]) #obj是随机返回的 类型不确定  
  13. print type(obj)  
  14. print obj.count(‘a‘#方法多态  

  对于一个临时对象obj,它通过Python的随机函数取出来,不知道具体类型(是字符串、元组还是自定义类型),都可以调用count方法进行计算,至于count由谁(哪种类型)去做怎么去实现我们并不关心。

  有一种称为”鸭子类型(duck typing)“的东西,讲的也是多态:

[python] view plaincopy在CODE上查看代码片派生到我的代码片
  1. _metaclass_=type # 确定使用新式类  
  2. class Duck:  
  3.     def quack(self):   
  4.         print "Quaaaaaack!"  
  5.     def feathers(self):   
  6.         print "The duck has white and gray feathers."  
  7.    
  8. class Person:  
  9.     def quack(self):  
  10.         print "The person imitates a duck."  
  11.     def feathers(self):   
  12.         print "The person takes a feather from the ground and shows it."  
  13.    
  14. def in_the_forest(duck):  
  15.     duck.quack()  
  16.     duck.feathers()  
  17.    
  18. def game():  
  19.     donald = Duck()  
  20.     john = Person()  
  21.     in_the_forest(donald)  
  22.     in_the_forest(john)  
  23.    
  24. game()  
  就in_the_forest函数而言,参数对象是一个鸭子类型,它实现了方法多态。但是实际上我们知道,从严格的抽象来讲,Person类型和Duck完全风马牛不相及。
  2、运算符多态

[python] view plaincopy在CODE上查看代码片派生到我的代码片
  1. def add(x,y):  
  2.     return x+y  
  3.   
  4. print add(1,2#输出3  
  5.   
  6. print add("hello,","world"#输出hello,world  
  7.   
  8. print add(1,"abc"#抛出异常 TypeError: unsupported operand type(s) for +: ‘int‘ and ‘str‘  
  上例中,显而易见,Python的加法运算符是”多态“的,理论上,我们实现的add方法支持任意支持加法的对象,但是我们不用关心两个参数x和y具体是什么类型。
   Python同样支持运算符重载,实例如下:

[python] view plaincopy在CODE上查看代码片派生到我的代码片
  1. class Vector:  
  2.    def __init__(self, a, b):  
  3.       self.a = a  
  4.       self.b = b  
  5.   
  6.    def __str__(self):  
  7.       return ‘Vector (%d, %d)‘ % (self.a, self.b)  
  8.      
  9.    def __add__(self,other):  
  10.       return Vector(self.a + other.a, self.b + other.b)  
  11.   
  12. v1 = Vector(2,10)  
  13. v2 = Vector(5,-2)  
  14. print v1 + v2  
  一两个示例代码当然不能从根本上说明多态。普遍认为面向对象最有价值最被低估的特征其实是多态。我们所理解的多态的实现和子类的虚函数地址绑定有关系,多态的效果其实和函数地址运行时动态绑定有关。在C++, Java, C#中实现多态的方式通常有重写和重载两种,从上面两段代码,我们其实可以分析得出Python中实现多态也可以变相理解为重写和重载。在Python中很多内置函数和运算符都是多态的。