Fork me on GitHub

Python面向对象编程

一、什么是面向对象

  面向对象编程(OOP,Object Oriented Programming)
  OOP三个主要的特征:数据封装、继承和多态。
  所有的程序是由一定的属性和行为对象组成的,不同的对象的访问通过函数调用来完成,对象间所有的交流都是通过方法调用,通过对封装对象数据,提高复用率。

二、创建类和对象

  面向对象编程是一种编程方式,此编程方式的落地需要使用 "类" 和 "对象"来实现,所以,面向对象编程其实就是对 "类" 和 "对象" 的使用。

  类就是一个模板,模板里可包含多个函数,函数里实现一些功能。对象则是根据模板创建的实例,通过实例对象可以执行类中的方法。

class Role (object):
    def __init__(self,name):
    self.name = name
  
    def buy_weapon(self,weapon):
    pass

  class是关键字,定义一个类,其名称为Role,这个类继承了Python的父类,名为object。在类的下面可以看到有很多函数的定义,但在 class中,函数被称为方法,所以这里暂时在一个名为Role类的下面有__init__和buy_weapon方法。

三、封装

  封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。

  所以,在使用面向对象的封装特性时,需要:1.将内容封装到某处 2.从某处调用被封装的内容

class Role (object):    #object是父类,继承父类
    def __init__(self,name,role,weapon,life_value):     #称为构造方法,根据类创建对象时自动执行
        self.name = name    #成员变量,self 代表传进来的name,在整个类都可以使用这个变量,把一个局部变量变为了全局变量
        self.role = role
        self.weapon = weapon
        self.life_val = life_value
   
    def buy_weapon(self,weapon):
        print("[%s] is buying [%s]" % (self.name,weapon))
        self.weapon = weapon
   
# 把一个抽象的类变成一个具体的过程叫实例化
t1 = Role("Stanley",'Terrorist','Glock',100)    #等价于Role(t1,"Stanley",'Terrorist','b11',100),同时将'Stanley'、'Terrorist'、'Glock'和100封装到t1和self的name、role、weapon、life_value属性中
p1 = Role("Tom",'Police','Desert Eagle',90) #Role(p1,"Tom",'Police','Desert Eagle',90)
print("t1's weapon was [%s] before" % t1.weapon)
print("=".center(40,'='))
t1.buy_weapon('AK47')    #转换为Role.buy_weapon(t1,'AK47')
print("t1's weapon is [%s] now" % t1.weapon)
  
Result:
t1's weapon was [Glock] before
========================================
[Stanley] is buying [AK47]
t1's weapon is [AK47] now

  第一个方法__init__是初始化构造方法,构造方法的第一个参数永远是self,表示这个类的对象本身,真正构造对象时,self这个参数不用写,python编译器会自己加上去,构造方法的作用就是对self对象进行赋值,如下面传进来的name赋给self.name,这么做的目的是因为在class中,每个方法依旧是要遵循函数规则的,在函数下面每个变量都是局部变量,在其他函数中并不能相互调用,如此做就把一个局部变量变为全局变量。

  通过self间接调用被封装的内容:

  第二个方法除了编译器会自己加上去的self参数外,weapon参数接收传入的变量,打印调用的参数。在print之后self.name含义是将调用者的name赋值给self。

  接下来要对p1和t1进行实例化,这是将一个抽象的类变成一个具体的过程,生成了p1和t1两个角色。t1 = Role("Stanley",'Terrorist','Glock',100),Python解释器会将此转换为 Role(t1,"Stanley",'Terrorist','Glock',100),这里通过解释器转换后的t1其实就是self。

  现在t1角色进行购买行为,t1.buy_weapon('AK47'),Python解释器会将此转换为 Role.buy_weapon(t1,'AK47'),如上所述此时的t1就是self,也可理解为将t1传入__init__初始化构造方法,就可直接self.name(等价于t1.name)获取到name的变量了(Stanley)。

  综上所述,对于面向对象的封装来说,其实就是使用构造方法将内容封装到对象中,然后通过对象直接或者self间接获取被封装的内容。

四、继承

  继承,面向对象中的继承和现实生活中的继承相同,即:子可以继承父的内容,也可理解为由一般到特殊。

class SchoolMember(object):
    member_nums = 0
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
        self.enroll()
 
    def enroll(self):
        print("NO.%s SchoolMember [%s] is enrolled!" % (SchoolMember.member_nums,self.name))
        SchoolMember.member_nums += 1   #统计人员数量不可写为self.member_nums += 1,因self实例下没有此变量,两者毫无关联。
 
    def tell(self):
        print("Hello, My name is [%s]" % self.name)
 
class Teacher(SchoolMember):    #参数为继承对象
    def __init__(self,name,age,sex,course,salary):  #如果不写__init__默认就继承了父类的所有属性,但子类需要额外扩展,需先重写再继承
        super(Teacher,self).__init__(name,age,sex)      #上面进行了重写,再继承回来进行覆盖,推荐新式类语法
        #SchoolMember.__init__(self,name,age,sex)        #此为经典类语法,不推荐
        self.course = course
        self.salary = salary
 
    def teaching(self):
        print("Teacher [%s] is teaching [%s]" % (self.name,self.course))
 
class Student(SchoolMember):
    def __init__(self,name,age,sex,course,tuition,):
        super(Student,self).__init__(name,age,sex)
        self.course = course
        self.tuition = tuition
 
    def pay_tuition(self):
        print("Student [%s] pays tuition [%s] again" % (self.name,self.tuition))
 
#实例化老师
t1 = Teacher('Stanley',24,'M','Python',1000)    #实例化,不可实例化SchoolMember,其只可用来继承
t1 = Teacher('Katrina',29,'M','MySQL',1500)    #实例化,不可实例化SchoolMember,其只可用来继承
#实例化学生
s1 = Student('Tim',24,'F','MySQL',10000)
s2 = Student('Bella',27,'M','Python',12000)
print("===========子类使用父类方法============")
t1.tell()
s1.tell()
print("===========子类使用私有方法============")
t1.teaching()
s1.pay_tuition()
 
Result:
NO.0 SchoolMember [Stanley] is enrolled!
NO.1 SchoolMember [Katrina] is enrolled!
NO.2 SchoolMember [Tim] is enrolled!
NO.3 SchoolMember [Bella] is enrolled!
===========子类使用父类方法============
Hello, My name is [Katrina]
Hello, My name is [Tim]
===========子类使用私有方法============
Teacher [Katrina] is teaching [MySQL]
Student [Tim] pays tuition [10000] again

  此为标准继承示例,其中包含三个类,SchoolMember是父类,Teacher和Student是子类,子类中拥有父类的共同属性,除此之外,子类还需要额外进行扩展,所以在子类中要先重写,再从父类继承回来进行覆盖。在继承语法中super为关键字,不可省略,其参数为子类名称,self,__init__参数为需要继承的属性。相关封装特性详见上一段落,不再累述。父类和子类定义好后,实例化Teacher和 Student,在父类中执行注册方法,每个子类都可调用父类的tell方法,并且每个子类都会包含私有方法teaching和pay_tuition,这就利用继承特性实现了简单的权限限制功能。

  综上所述,对于面向对象的继承来说,其实就是将多个类共有的方法提取到父类中,子类仅需继承父类而不必一一实现每个方法。

五、多态

  多态性(polymorphisn)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。

  Pyhon不支持多态并且也用不到多态,多态的概念是应用于Java和C#这一类强类型语言中的。那么,多态的作用是什么呢?我们知道,封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——代码重用。而多态则是为了实现另一个目的——接口重用!多态的作用,就是为了类在继承和派生的时候,保证使用“家谱”中任一类的实例的某一属性时的正确调用。

  通过Python模拟的多态:

class Animal:
    def __init__(self, name):    # Constructor of the class
        self.name = name
    def talk(self):              # Abstract method, defined by convention only
        raise NotImplementedError("Subclass must implement abstract method")
 
class Cat(Animal):
    def talk(self):
        return 'Meow!'
 
class Dog(Animal):
    def talk(self):
        return 'Woof! Woof!'
 
animals = [Cat('Missy'),
           Dog('Lassie')]
 
for animal in animals:
    print animal.name + ': ' + animal.talk()
posted @ 2016-03-13 19:32  stefan.liu  阅读(319)  评论(0编辑  收藏  举报