python自动化运维之路 --面向对象

                                                      作者:程小航

版权声明:原创作品,谢绝转载!否则将追究法律责任。

 

   如果你想开发一款游戏,会存在角色的混搭的情况,这个时候“面向对象过程”就出现了,他能轻松的解决这个问题。

一.编程范式

  编程是程序员用特定的语法+数据结构+算法组成的代码来告诉计算机如何执行任务的过程 。

  一个程序是程序员为了得到一个任务结果而编写的一组指令的集合,正所谓条条大路通罗马,实现一个任务的方式有很多种不同的方式, 对这些不同的编程方式的特点进行归纳总结得出来的编程方式类别,即为编程范式。 不同的编程范式本质上代表对各种类型的任务采取的不同的解决问题的思路, 大多数语言只支持一种编程范式(比如说:java),当然也有些语言可以同时支持多种编程范式(Python)。 两种最重要的编程范式分别是面向过程编程和面向对象编程。

  

二.面向过程编程(Procedural Programming)
  Procedural programming uses a list of instructions to tell the computer what to do step-by-step. 
  面向过程编程依赖 - 你猜到了- procedures,一个procedure包含一组要被进行计算的步骤, 面向过程又被称为top-down languages, 就是程序从上到下一步步执行,一步步从上到下,从头到尾的解决问题 。基本设计思路就是程序一开始是要着手解决一个大的问题,然后把一个大问题分解成很多个小问题或子过程,这些子过程再执行的过程再继续分解直到小问题足够简单到可以在一个小步骤范围内解决。

  举个典型的面向过程的例子, 数据库备份, 分三步,连接数据库,备份数据库,测试备份文件可用性。

def db_conn():
    print("connecting db...")
 
def db_backup(dbname):
    print("导出数据库...",dbname)
    print("将备份文件打包,移至相应目录...")
 
def db_backup_test():
    print("将备份文件导入测试库,看导入是否成功")
 
def main():
    db_conn()
    db_backup('my_db')
    db_backup_test()
 
if __name__ == '__main__':
    main()


"'
      这样做的问题也是显而易见的,就是如果你要对程序进行修改,对你修改的那部分有依赖的各个部分你都也要跟着修改, 举个例子,如果程序开头你设置了一个变量值 为1 , 但如果其它子过程依赖这个值 为1的变量才能正常运行,那如果你改了这个变量,那这个子过程你也要修改,假如又有一个其它子程序依赖这个子过程 , 那就会发生一连串的影响,随着程序越来越大, 这种编程方式的维护难度会越来越高。 
      所以我们一般认为, 如果你只是写一些简单的脚本,去做一些一次性任务,用面向过程的方式是极好的,但如果你要处理的任务是复杂的,且需要不断迭代和维护 的, 那还是用面向对象最方便了。
'''
   
模拟数据库备份

 

三.面向对象编程

  OOP编程是利用“类”和“对象”来创建各种模型来实现对真实世界的描述,使用面向对象编程的原因一方面是因为它可以使程序的维护和扩展变得更简单,并且可以大大提高程序开发效率 ,另外,基于面向对象的程序可以使它人更加容易理解你的代码逻辑,从而使团队开发变得更从容。

面向对象的几个核心特性如下

  1>.Class 类:一个类即是对一类拥有相同属性的对象的抽象、蓝图、原型。在类中定义了这些对象的都具备的属性(variables(data))、共同的方法(其实类就是一堆函数组成的);

  2>.Object 对象:一个对象即是一个类的实例化(就好像是zabbix模板被监控的主机引用的过程)后实例,一个类必须经过实例化后方可在程序中调用,一个类可以实例化多个对象,每个对象亦可以有不同的属性,就像人类是指所有人,每个人是指具体的对象,人与人之前有共性,亦有不同;

  3>.Encapsulation 封装:在类中对数据的赋值、内部调用对外部用户是透明的,这使类变成了一个胶囊或容器,里面包含着类的数据和方法;

  4>Inheritance 继承:一个类可以派生出子类,在这个父类里定义的属性、方法自动被子类继承;

  5>.Polymorphism 多态:多态是面向对象的重要特性,简单点说:“一个接口,多种实现”,指一个基类中派生出了不同的子类,且每个子类在继承了同样的方法名的同时又对父类的方法做了不同的实现,这就是同一种事物表现出的多种形态。
  

  编程其实就是一个将具体世界进行抽象化的过程,多态就是抽象化的一种体现,把一系列具体事物的共同点抽象出来, 再通过这个抽象的事物, 与不同的具体事物进行对话。
对不同类的对象发出相同的消息将会有不同的行为。比如,你的老板让所有员工在九点钟开始工作, 他只要在九点钟的时候说:“开始工作”即可,而不需要对销售人员说:“开始销售工作”,对技术人员说:“开始技术工作”, 因为“员工”是一个抽象的事物, 只要是员工就可以开始工作,他知道这一点就行了。至于每个员工,当然会各司其职,做各自的工作。多态允许将子类的对象当作父类的对象使用,某父类型的引用指向其子类型的对象,调用的方法是该子类型的方法。这里引用和调用方法的代码编译前就已经决定了,而引用所指向的对象可以在运行期间动态绑定

 

四.面向对象编程(Object-Oriented Programming )介绍

无论用什么形式来编程,我们都要明确记住以下原则:
  1>.写重复代码是非常不好的低级行为;
  2>.你写的代码需要经常变更;
  
  其实OOP编程的主要作用也是使你的代码修改和扩展变的更容易,那么小白要问了,既然函数都能实现这个需求了,还要OOP干毛线用呢? 呵呵,说这话就像,古时候,人们打仗杀人都用刀,后来出来了枪,它的主要功能跟刀一样,也是杀人,然后小白就问,既然刀能杀人了,那还要枪干毛线,哈哈,显而易见,因为枪能更好更快更容易的杀人。函数编程与OOP的主要区别就是OOP可以使程序更加容易扩展和易更改。好了 ,我就不废话了,让我们开始写我们的第一个类吧:
#!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :rianley
#blog:http://www.cnblogs.com/rianley
#EMAIL:rianley@qq.com
class Man(object): #定义类名首字母需要大写哟
    def __init__(self,name,type): #初始化对象(初始化函数又叫构造函数),即一旦调用Man这个类,就会执行以下代码
        self.name = name  #这个步骤是相当于a.name = name,为了就是方便下面的函数去调用他们
        self.type = type  #这个步骤相当于a.type = type
    def introduce(self):
        print("[%s] is a good boy!" %  self.name)
    def eat(self,food):
        print("[%s] eating [%s]"%(self.name,food))
jie = Man("rianleycheng","goodboy")
print(jie.name,jie.type)
jie.introduce()
jie.eat("apple")



#以上代码执行结果如下:
rianleycheng goodboy
[rianleycheng ] is a good boy!
[rianleycheng ] eating [apple]

五.面向对象的特性

1.什么是特性property(是用来提供接口的一种方式)

property是一种特殊的属性,访问它时会执行函数然后返回值

#!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :rianleycheng
#blog:http://www.cnblogs.com/rianley
#EMAIL:rianley@qq.com
import math
class Circle:
    def __init__(self,radius): #圆的半径radius
        self.radius=radius
    @property   #其实就是一个装饰器,作用等效于 area = property(area)
    def area(self):
        return math.pi * self.radius**2 #计算面积
    @property  #作用等效于 area = property(perimeter)
    def perimeter(self):
        return 2*math.pi*self.radius #计算周长

c=Circle(5)  #传入参数半径
print(c.radius)  #调用的时候就不用调用类里面的方法(函数),直接调用数据属性,不需要调用函数属性
print(c.area) #可以向访问数据属性一样去访问area,会触发一个函数的执行,动态计算出一个值
print(c.perimeter) #同上


#以上代码执行结果如下:
5
78.53981633974483
31.41592653589793
property装饰器的用法案例

2 .为什么要用property

  将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则,即它是将一个方法变成静态属性。

除此之外,看下

'''
ps:面向对象的封装有三种方式:
【public】
这种其实就是不封装,是对外公开的
【protected】
这种封装方式对外不公开,但对朋友(friend)或者子类(形象的说法是“儿子”,但我不知道为什么大家 不说“女儿”,就像“parent”本来是“父母”的意思,但中文都是叫“父类”)公开
【private】
这种封装对谁都不公开
'''

  

python并没有在语法上把它们三个内建到自己的class机制中,在C++里一般会将所有的所有的数据都设置为私有的,然后提供set和get方法(接口)去设置和获取,在python中通过property方法可以实现

使用展示一:

#!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :rianleycheng
#blog:http://www.cnblogs.com/rianley
#EMAIL:rianley@qq.com
class Man(object):
    name = "ddddd"
    def __init__(self ,name):
        self.name = name
    @classmethod
    def talk(self):
        print("%s is talking" % self.name)
    @property #把eat这个方法变成静态属性
    def eat(self):
        print("%s is eating"% self.name)
    @eat.setter  #赋值,
    def eat(self,num):
        print("changing status", num)
    @eat.deleter  #删除,
    def eat(self):
        print("deleting....eat")
d = Man("rianleycheng")
d.eat  #触发 @property
d.eat =  1000  #触发 @eat.setter
del d.eat     #触发 @eat.deleter


#以上代码执行结果如下:
rianleycheng is eating
changing status 1000
deleting....eat

  

使用展示二:

#!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :rianleycheng
#blog:http://www.cnblogs.com/rianley
#EMAIL:rianley@qq.com
class Foo:
    def __init__(self,val):
        self.__NAME=val #将所有的数据属性都隐藏起来

    @property
    def name(self):
        return self.__NAME #obj.name访问的是self.__NAME(这也是真实值的存放位置)

    @name.setter
    def name(self,value):
        if not isinstance(value,str):  #在设定值之前进行类型检查
            raise TypeError('%s must be str' %value)
        self.__NAME=value #通过类型检查后,将值value存放到真实的位置self.__NAME

    @name.deleter
    def name(self):
        raise TypeError('Can not delete')

f=Foo('rianley')
print(f.name)
# f.name=10 #抛出异常'TypeError: 10 must be str'
# del f.name #抛出异常'TypeError: Can not delete'

#以上代码执行结果如下:
rianley

  

应用场景

 

#!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :rianleycheng
#blog:http://www.cnblogs.com/rianley
#EMAIL:rianley@qq.com


class Flight(object):
    def __init__(self, name):
        self.flight_name = name

    def checking_status(self):
        print("checking flight %s status " % self.flight_name)
        return 3

    @property
    def flight_status(self):
        status = self.checking_status()
        if status == 0:
            print("flight got canceled...")
        elif status == 1:
            print("flight is arrived...")
        elif status == 2:
            print("flight has departured already...")
        else:
            print("cannot confirm the flight status...,please check later")

    @flight_status.setter  # 修改
    def flight_status(self, status):
        status_dic = {
            0: "canceled",
            1: "arrived",
            2: "departured"
        }
        print("\033[31;1mHas changed the flight status to \033[0m", status_dic.get(status))

    @flight_status.deleter  # 删除
    def flight_status(self):
        print("status got removed...")


f = Flight("CA980")
f.flight_status
f.flight_status = 2  # 触发@flight_status.setter
del f.flight_status  # 触发@flight_status.deleter



#以上代码执行结果如下:
checking flight CA980 status 
cannot confirm the flight status...,please check later
Has changed the flight status to  departured
status got removed...

  

六.封装

  封装,其实就是使用构造方法将内容封装到某个具体对象中,然后通过对象直接或者self间接获取被封装的内容

  封装最好理解了。封装是面向对象的特征之一,是对象和类概念的主要特性。

  封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。

 

 

学习封装前要掌握的知识点:

1>类变量:既可以作为默认公有属性也可以全局修改或增加新属性。

#!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :rianley
#blog:http://www.cnblogs.com/rianley
#EMAIL:rianley@qq.com
'''
类变量的作用:
    1>.作为默认公有属性
    2>.全局修改或增加新属性
'''

class People(object):
    nationality = "CN" #类变量
    def __init__(self,name,age,job):
        pass
p = People("rianleycheng","21","IT")
p.nationality = "JP"  #修改类变量
print(p.nationality)
p2 = People("egon","18","IT")
People.weapon = "Nepal Saber"  #全局加武器装备尼泊尔军刀,这个就是类变量的应用
print(p.weapon)



#以上代码执行结果如下:
JP
Nepal Saber
类变量的应用

2>.实例变量(成员属性):其特性和类变量相反,仅仅属于你自己的实例变量。一般构造函数的实例变量都是实例变量,(即每个实例。存在自己内存空间里的属性。)

#!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :rianley
#blog:http://www.cnblogs.com/rianley
#EMAIL:rianley@qq.com
'''
类变量的作用:
    1>.作为默认公有属性
    2>.全局修改或增加新属性
'''

class People(object):
    nationality = "CN" #类变量
    def __init__(self,name,age,job):
        self.name = name  #实例变量,换句话说只要在构造函数里面定义的变量都是实例变量!当然你也可以新增哟。
        self.age = age
        self.job = job
p = People("rianleycheng","21","IT")
p.hobbie = "basketball"  #添加一个实例变量
print(p.hobbie)



#以上代码执行结果如下:
basketball
实例变量展示

3>.公有属性:对应的就是类变量的属性

#!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :rianleycheng
#blog:http://www.cnblogs.com/rianley
#EMAIL:rianley@qq.com
class Man(object): #定义类名首字母需要大写哟
    age = 25  #类变量,存在内的内存地址里,可以被所有实例共享引用
    def __init__(self,name,type): #初始化函数(构造函数)
        self.name = name  #这个步骤是相当于jie.name = name,为了就是方便下面的函数去调用他们
        self.type = type  #这个步骤相当于jie.type = type
    def introduce(self):
        print("[%s] is a good boy!  I have  [%s]  years old!" %  (self.name,self.age))  #注意:“self.age”其实是引用Man中的类变量
    def eat(self,food):
        print("[%s] eating [%s]"%(self.name,food))
jie = Man("rianleycheng","goodboy")  #其中“jie”就是Man的实例,整个动作“jie = Man("rianleycheng","goodboy") ”叫做类的“实例化”, 就是把一个虚拟的抽象的类,通过这个动作,变成了一个具体的对象了
print(jie.name,jie.type)
jie.introduce()
jie.eat("apple")
jie.name = "程小航"  #赋值
print(jie.name)


#以上代码执行结果如下:
rianleycheng  goodboy
[rianleycheng] is a good boy!  I have  [21]  years old!
[rianleycheng] eating [apple]
程小航
类的实例化以及类的赋值演示

4>.私有属性:表示不想被别人访问到的属性,只能在内部各函数中调用。隐藏一些功能的实现细节,只给外部暴露调用接口

#!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :rianley
#blog:http://www.cnblogs.com/rianley
#EMAIL:rianley@qq.com
'''
类变量的作用:
    1>.作为默认公有属性
    2>.全局修改或增加新属性
'''

class People(object):
    nationality = "CN" #类变量
    def __init__(self,name,age,sex):
        self.name = name  #实例变量,换句话说只要在构造函数里面定义的变量都是实例变量!当然你也可以新增哟。
        self.age = age
        self.__sex = sex   #定义私有属性,其只能在内部各函数(严格来说我们应该叫“内部方法”)中调用
    def go_to_toilet(self):
        if self.__sex == "F":  #在内部的方法中是可以成功调用的!
            print("stand up.....")
        else:
            print("蹲着.....")
p = People("rianley","25","F")
p.go_to_toilet()
# print(p.sex)  #外部调用的话会报错!因为私有属性只能内部方法调用,而不能从外部调用!



#以上代码执行结果如下:
stand up.....
私有属性用法展示
#!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :rianley
#blog:http://www.cnblogs.com/rianley
#EMAIL:rianley@qq.com
class People(object):
    nationality = "CN" #类变量
    def __init__(self,name,age,sex):
        self.name = name  #实例变量,换句话说只要在构造函数里面定义的变量都是实例变量!当然你也可以新增哟。
        self.age = age
        self.__sex = sex   #定义私有属性,其只能在内部各函数(严格来说我们应该叫“内部方法”)中调用
    def get_sex(self):
        return self.__sex  #将私有属性的值返回
p = People("rianley","25","F")
print(p.get_sex())  #外部只能访问,不可以修改哟,(因为不能给方法复制!)




#以上代码执行结果如下:
F
外部调用私有属性的方法

七.继承

1.继承顺序

 

#!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :rianley
#blog:http://www.cnblogs.com/rianley
#EMAIL:rianley@qq.com
class A(object):
    def test(self):
        print('from A')

class B(A):
    def test(self):
        print('from B')

class C(A):
    def test(self):
        print('from C')

class D(B):
    def test(self):
        print('from D')

class E(C):
    def test(self):
        print('from E')

class F(D,E):
    # def test(self):
    #     print('from F')
    pass
f1=F()
f1.test()
print(F.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性

'''
新式类继承顺序:F->D->B->E->C->A   (广度优先,【不会优先找到最顶级的类】)
经典类继承顺序:F->D->B->A->E->C    (深度优先)
python3中统一都是新式类
pyhon2中才分新式类与经典类
'''

#以上代码执行结果如下:

from D
(<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
继承顺序案例详解

 

2.继承原理(python如何实现的继承)

python到底是如何实现继承的,对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表,例如

>>> F.mro() #等同于F.__mro__
[<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

 

为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。
而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:
1.子类会先于父类被检查
2.多个父类会根据它们在列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类

3.子类中调用父类方法

子类继承了父类的方法,然后想进行修改,注意了是基于原有的基础上修改,那么就需要在子类中调用父类的方法

方法一:父类名.父类方法()

#!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :rianley
#blog:http://www.cnblogs.com/rianley
#EMAIL:rianley@qq.com
class Vehicle:  # 定义交通工具类
    Country = 'China'

    def __init__(self, name, speed, load, power):
        self.name = name
        self.speed = speed
        self.load = load
        self.power = power

    def run(self):
        print('开动啦...')

class Subway(Vehicle):  # 地铁
    def __init__(self, name, speed, load, power, line):
        Vehicle.__init__(self, name, speed, load, power)
        self.line = line

    def run(self):
        print('地铁%s号线欢迎您' % self.line)
        Vehicle.run(self)

line15 = Subway('中国地铁', '180m/s', '1000人/箱', '电', 15)
line15.run()


#以上代码执行结果如下:
地铁15号线欢迎您
开动啦...

  

方法二:super()

#!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :rianley
#blog:http://www.cnblogs.com/rianley
#EMAIL:rianley@qq.com
class Vehicle:  # 定义交通工具类
    Country = 'China'

    def __init__(self, name, speed, load, power):
        self.name = name
        self.speed = speed
        self.load = load
        self.power = power
    def run(self):
        print('开动啦...')
class Subway(Vehicle):  # 地铁
    def __init__(self, name, speed, load, power, line):
        # super(Subway,self) 就相当于实例本身 在python3中super()等同于super(Subway,self)
        super().__init__(name, speed, load, power)
        self.line = line
    def run(self):
        print('地铁%s号线欢迎您' % self.line)
        super(Subway, self).run()
class Mobike(Vehicle):  # 摩拜单车
    pass
line13 = Subway('中国地铁', '180m/s', '1000人/箱', '电', 13)
line13.run()

#以上代码执行结果如下:
地铁13号线欢迎您
开动啦...

  

不用super引发的惨案

#!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :rianley
#blog:http://www.cnblogs.com/rianley
#EMAIL:rianley@qq.com
#每个类中都继承了且重写了父类的方法
class A:
    def __init__(self):
        print('A的构造方法')
class B(A):
    def __init__(self):
        print('B的构造方法')
        A.__init__(self)


class C(A):
    def __init__(self):
        print('C的构造方法')
        A.__init__(self)


class D(B,C):
    def __init__(self):
        print('D的构造方法')
        B.__init__(self)
        C.__init__(self)

    pass
f1=D()

print(D.__mro__) #python2中没有这个属性



#以上代码执行结果如下:
D的构造方法
B的构造方法
A的构造方法
C的构造方法
A的构造方法
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
多继承方法案例

 

当你使用super()函数时,Python会在MRO列表上继续搜索下一个类。只要每个重定义的方法统一使用super()并只调用它一次,那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次(注意注意注意:使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表

 

#!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :rianley
#blog:http://www.cnblogs.com/rianley
#EMAIL:rianley@qq.com
#每个类中都继承了且重写了父类的方法
class A:
    def __init__(self):
        print('A的构造方法')
class B(A):
    def __init__(self):
        print('B的构造方法')
        super(B,self).__init__()


class C(A):
    def __init__(self):
        print('C的构造方法')
        super(C,self).__init__()


class D(B,C):
    def __init__(self):
        print('D的构造方法')
        super(D,self).__init__()

f1=D()

print(D.__mro__) #python2中没有这个属性


#以上代码执行结果如下:
D的构造方法
B的构造方法
C的构造方法
A的构造方法
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
巧用__mro__方法展示

 

面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。

  通过继承创建的新类称为“子类”或“派生类”。

  被继承的类称为“基类”、“父类”或“超类”。

  继承的过程,就是从一般到特殊的过程。

  要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。

  在某些 OOP 语言中,一个子类可以继承多个基类。但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。

继承概念的实现方式主要有2类:实现继承、接口继承。

  1>.实现继承是指使用基类的属性和方法而无需额外编码的能力;
  2>. 接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力(子类重构爹类方法);
在考虑使用继承时,有一点需要注意,那就是两个类之间的关系应该是“属于”关系。例如,Employee(员工) 是一个人,Manager(领导) 也是一个人,因此这两个类都可以继承 Person 类。但是 Leg(推) 类却不能继承 Person(人) 类,因为腿并不是一个人。
  抽象类仅定义将由子类创建的一般属性和方法。

  OO开发范式大致为:划分对象→抽象类→将类组织成为层次化结构(继承和合成) →用类与实例进行设计和实现几个阶段。

 

#!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :rianley
#blog:http://www.cnblogs.com/rianley
#EMAIL:rianley@qq.com
class SchoolMember(object):
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
    def tell(self):
        info  = """
        --------info of %s-------------
        name :  %s
        age  :  %s
        sex  :  %s
        """%(self.name,self.name,self.age,self.sex)

class Teacher(SchoolMember):  #继承父类“SchoolMember”,这样的话如果父类的一些变量就不用重复再子类中定义了.
    def __init__(self,name,age,sex,salary):  #初始化函数
        SchoolMember.__init__(self,name,age,sex)  #这个步骤表示将“name,age,sex”这几个值传递给父类SchoolMember中的"__init__(self,name,age,sex):",这样就继承了父类的所有实例变量
        self.salary = salary  #表示重新构造函数
    def teaching(self,course):
        print("%s is teaching %s"%(self.name,course))

t = Teacher("rianley",25,"boy","1000") #调用子类的时候除了在父类中含有的功能外,还多了一个“salary”参数。
print(t.name)
print(t.sex)
print(t.salary)


#以上代码执行结果如下:
rianley
boy
1000
重新构造函数
#!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :rianley
#blog:http://www.cnblogs.com/rianley
#EMAIL:rianley@qq.com
class SchoolMember(object):
    members = 0
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
        SchoolMember.members += 1  #注意着是调用的类变量,我们不能用"self.members"去自加哟!
        print("初始化了一个新学校成员",self.name)
    def tell(self):
        info  = """
        --------info of %s-------------
        name :  %s
        age  :  %s
        sex  :  %s
        """%(self.name,self.name,self.age,self.sex)
        print(info)
class Teacher(SchoolMember):  #继承父类“SchoolMember”,这样的话如果父类的一些变量就不用重复再子类中定义了.
    def __init__(self,name,age,sex,salary):  #初始化函数
        SchoolMember.__init__(self,name,age,sex)  #这个步骤表示将“name,age,sex”这几个值传递给父类SchoolMember中的"__init__(self,name,age,sex):",这样就继承了父类的所有实例变量
        self.salary = salary  #表示重新构造函数
    def teaching(self,course):
        print("%s is teaching %s"%(self.name,course))
class Student(SchoolMember):
    def __init__(self, name, age, sex, salary):  # 初始化函数
        SchoolMember.__init__(self, name, age, sex)
    def pay_tuition(self, amount):
        self.paid_tuition = amount
        print("student %s has paid tution amoint %s" % (self.name, amount))
t = Teacher("rianley",25,"boy","1000") #调用子类的时候除了在父类中含有的功能外,还多了一个“salary”参数。
s = Student("lifeng","26","M","pys600")
t.tell()
t.teaching("python")
s.pay_tuition(11000)
print("目前学校公有[%s]个学生"% SchoolMember.members)


#以上代码执行结果如下:
初始化了一个新学校成员 rianley
初始化了一个新学校成员 lifeng

        --------info of yinzhengjie-------------
        name :  rianley
        age  :  25
        sex  :  boy
        
rianley is teaching python
student lifeng has paid tution amoint 11000
目前学校公有[2]个学生
重新构造函数升级版本,自动统计学校的人数
#!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :rianley
#blog:http://www.cnblogs.com/rianley
#EMAIL:rianley@qq.com
'''
继承的作用:
    1>.直接调用父类方法;
    2>.继承父类方法并重构父类方法,先重构,在重构的方法里手动调用父类方法
    3>.可以定义子类自己的方法;
    4>.可以析构方法"__del__"
'''
class SchoolMember(object):
    members = 0
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
        SchoolMember.members += 1  #注意着是调用的类变量,我们不能用"self.members"去自加哟!
        print("初始化了一个新学校成员",self.name)
    def tell(self):
        info  = """
        --------info of %s-------------
        name :  %s
        age  :  %s
        sex  :  %s
        """%(self.name,self.name,self.age,self.sex)
        print(info)
    def __del__(self):  #析构函数(析构方法)
        print(("注意:[%s]已经被开除了!" % self.name))
        SchoolMember.members -= 1
class Teacher(SchoolMember):  #继承父类“SchoolMember”,这样的话如果父类的一些变量就不用重复再子类中定义了.
    def __init__(self,name,age,sex,salary):  #初始化函数
        SchoolMember.__init__(self,name,age,sex)  #这个步骤表示将“name,age,sex”这几个值传递给父类SchoolMember中的"__init__(self,name,age,sex):",这样就继承了父类的所有实例变量
        self.salary = salary  #表示重新构造函数
    def teaching(self,course):
        print("%s is teaching %s"%(self.name,course))
class Student(SchoolMember):
    def __init__(self, name, age, sex, salary):  # 初始化函数
        SchoolMember.__init__(self, name, age, sex)
    def pay_tuition(self, amount):
        self.paid_tuition = amount
        print("student %s has paid tution amoint %s" % (self.name, amount))
t = Teacher("rianley",21,"boy","1000") #调用子类的时候除了在父类中含有的功能外,还多了一个“salary”参数。
s = Student("lifeng","26","M","pys600")
s2 = Student("test","22","F","pys16")
s3 = Student("test_1","23","F","pys16")
del  s2 #删除一个实例用del,在实例被销毁后自动执行
t.tell()
t.teaching("python")
s.pay_tuition(11000)
print("目前学校公有[%s]个学生"% SchoolMember.members)



#以上大米执行结果如下:
初始化了一个新学校成员 rianley
初始化了一个新学校成员 lifeng
初始化了一个新学校成员 test
初始化了一个新学校成员 test_1
注意:[test]已经被开除了!

        --------info of yinzhengjie-------------
        name :  yinzhengjie
        age  :  25
        sex  :  boy
        
yinzhengjie is teaching python
student lifeng has paid tution amoint 11000
目前学校公有[3]个学生
注意:[test_1]已经被开除了!  #以为程序结束了,内存会被释放掉,所以在del实例后,会打印以下3行代码。
注意:[rianley]已经被开除了!
注意:[lifeng]已经被开除了!
析构方法用法展示

八.组合

  软件重用的重要方式除了继承之外还有另外一种方式,即:组合

  组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合

  用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如教授有生日,教授教python课程。当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好。

 

#!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :rianley
#blog:http://www.cnblogs.com/rianley
#EMAIL:rianley@qq.com
class BirthDate:
    def __init__(self,year,month,day):
        self.year=year
        self.month=month
        self.day=day
class Couse:
    def __init__(self,name,price,period):
        self.name=name
        self.price=price
        self.period=period

class Teacher:
    def __init__(self,name,gender):
        self.name=name
        self.gender=gender
    def teach(self):
        print('teaching')
class Professor(Teacher):
    def __init__(self,name,gender,birth,course):
        Teacher.__init__(self,name,gender)  #直接将Teacher类的方法那来这个类里面用的方式就叫组合
        self.birth=birth
        self.course=course

p1=Professor('egon','male',BirthDate('1992','1','27'),Couse('python','28000','4 months'))
print(p1.birth.year,p1.birth.month,p1.birth.day)
print(p1.course.name,p1.course.price,p1.course.period)




#以上代码执行结果如下:
1992 1 27
python 28000 4 months
组合用法展示

 

 

九.接口与归一化设计

1.什么是接口

 

=================第一部分:Java 语言中的接口很好的展现了接口的含义: IAnimal.java
/*
* Java的Interface很好的体现了我们前面分析的接口的特征:
* 1)是一组功能的集合,而不是一个功能
* 2)接口的功能用于交互,所有的功能都是public,即别的对象可操作
* 3)接口只定义函数,但不涉及函数实现
* 4)这些功能是相关的,都是动物相关的功能,但光合作用就不适宜放到IAnimal里面了 */

package com.oo.demo;
public interface IAnimal {
    public void eat();
    public void run(); 
    public void sleep(); 
    public void speak();
}

=================第二部分:Pig.java:猪”的类设计,实现了IAnnimal接口 
package com.oo.demo;
public class Pig implements IAnimal{ //如下每个函数都需要详细实现
    public void eat(){
        System.out.println("Pig like to eat grass");
    }

    public void run(){
        System.out.println("Pig run: front legs, back legs");
    }

    public void sleep(){
        System.out.println("Pig sleep 16 hours every day");
    }

    public void speak(){
        System.out.println("Pig can not speak"); }
}

=================第三部分:Person2.java
/*
*实现了IAnimal的“人”,有几点说明一下: 
* 1)同样都实现了IAnimal的接口,但“人”和“猪”的实现不一样,为了避免太多代码导致影响阅读,这里的代码简化成一行,但输出的内容不一样,实际项目中同一接口的同一功能点,不同的类实现完全不一样
* 2)这里同样是“人”这个类,但和前面介绍类时给的类“Person”完全不一样,这是因为同样的逻辑概念,在不同的应用场景下,具备的属性和功能是完全不一样的 */

package com.oo.demo;
public class Person2 implements IAnimal { 
    public void eat(){
        System.out.println("Person like to eat meat");
    }

    public void run(){
        System.out.println("Person run: left leg, right leg");
    }

    public void sleep(){
        System.out.println("Person sleep 8 hours every dat"); 
    }

    public void speak(){
        System.out.println("Hellow world, I am a person");
    } 
}

=================第四部分:Tester03.java
package com.oo.demo;

public class Tester03 {
    public static void main(String[] args) {
        System.out.println("===This is a person==="); 
        IAnimal person = new Person2();
        person.eat();
        person.run();
        person.sleep();
        person.speak();
        
        System.out.println("\n===This is a pig===");
        IAnimal pig = new Pig();
        pig.eat();
        pig.run();
        pig.sleep();
        pig.speak();
    } 
}
java中的interface

继承有两种用途:

      1>:继承基类的方法,并且做出自己的改变或者扩展(代码重用)

      2>:声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能

 

class Interface:#定义接口Interface类来模仿接口的概念,python中压根就没有interface关键字来定义一个接口。
    def read(self): #定接口函数read
        pass

    def write(self): #定义接口函数write
        pass


class Txt(Interface): #文本,具体实现read和write
    def read(self):
        print('文本数据的读取方法')

    def write(self):
        print('文本数据的读取方法')

class Sata(Interface): #磁盘,具体实现read和write
    def read(self):
        print('硬盘数据的读取方法')

    def write(self):
        print('硬盘数据的读取方法')

class Process(All_file):
    def read(self):
        print('进程数据的读取方法')

    def write(self):
        print('进程数据的读取方法')

  

实践中,继承的第一种含义意义并不很大,甚至常常是有害的。因为它使得子类与基类出现强耦合。

  继承的第二种含义非常重要。它又叫“接口继承”。
  接口继承实质上是要求“做出一个良好的抽象,这个抽象规定了一个兼容接口,使得外部调用者无需关心具体细节,可一视同仁的处理实现了特定接口的所有对象”——这在程序设计上,叫做归一化。

  归一化使得高层的外部使用者可以不加区分的处理所有接口兼容的对象集合——就好象linux的泛文件概念一样,所有东西都可以当文件处理,不必关心它是内存、磁盘、网络还是屏幕(当然,对底层设计者,当然也可以区分出“字符设备”和“块设备”,然后做出针对性的设计:细致到什么程度,视需求而定)。

 

  在python中根本就没有一个叫做interface的关键字,上面的代码只是看起来像接口,其实并没有起到接口的作用,子类完全可以不用去实现接口 ,如果非要去模仿接口的概念,可以借助第三方模块:http://pypi.python.org/pypi/zope.interfacetwisted的twisted\internet\interface.py里使用zope.interface

  文档https://zopeinterface.readthedocs.io/en/latest/

  设计模式:https://github.com/faif/python-patterns

2. 为何要用接口

  接口提取了一群类共同的函数,可以把接口当做一个函数的集合。然后让子类去实现接口中的函数。这么做的意义在于归一化,什么叫归一化,就是只要是基于同一个接口实现的类,那么所有的这些类产生的对象在使用时,从用法上来说都一样。归一化,让使用者无需关心对象的类是什么,只需要的知道这些对象都具备某些功能就可以了,这极大地降低了使用者的使用难度。

  比如:我们定义一个动物接口,接口里定义了有跑、吃、呼吸等接口函数,这样老鼠的类去实现了该接口,松鼠的类也去实现了该接口,由二者分别产生一只老鼠和一只松鼠送到你面前,即便是你分别不到底哪只是什么鼠你肯定知道他俩都会跑,都会吃,都能呼吸。再比如:我们有一个汽车接口,里面定义了汽车所有的功能,然后由本田汽车的类,奥迪汽车的类,大众汽车的类,他们都实现了汽车接口,这样就好办了,大家只需要学会了怎么开汽车,那么无论是本田,还是奥迪,还是大众我们都会开了,开的时候根本无需关心我开的是哪一类车,操作手法(函数调用)都一样

 

十.抽象类

什么是抽象类:

  与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化。

为什么要有抽象类:  

  如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类是从一堆中抽取相同的内容而来的,内容包括数据属性和函数属性。 比如我们有香蕉的类,有苹果的类,有桃子的类,从这些类抽取相同的内容就是水果这个抽象的类,你吃水果时,要么是吃一个具体的香蕉,要么是吃一个具体的桃子。。。。。。你永远无法吃到一个叫做水果的东西。从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。从实现角度来看,抽象类与普通类的不同之处在于:抽象类中只能有抽象方法(没有实现功能),该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接口有点类似,但其实是不同的,即将揭晓答案

  其实抽象类说直白了就是让你们的程序更加的规范化:

#!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :rianley
#blog:http://www.cnblogs.com/rianley
#EMAIL:rianley@qq.com
#一切皆文件
import abc #利用abc模块实现抽象类

class All_file(metaclass=abc.ABCMeta):
    all_type='file'
    @abc.abstractmethod #定义抽象方法,无需实现功能,只要这个类中的方法中含有该装饰器“abc.abstractmethod”,所以继承该类的人都要重写该方法!
    def read(self):
        '子类必须定义读功能'
        pass
    @abc.abstractmethod #定义抽象方法,无需实现功能
    def write(self):
        '子类必须定义写功能'
        pass
# class Txt(All_file):
#     pass
#
# t1=Txt() #报错,子类没有定义抽象方法

class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法
    def read(self):
        print('文本数据的读取方法')

    def write(self):
        print('文本数据的读取方法')

class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法
    def read(self):
        print('硬盘数据的读取方法')

    def write(self):
        print('硬盘数据的读取方法')

class Process(All_file): #子类继承抽象类,但是必须定义read和write方法
    def read(self):
        print('进程数据的读取方法')

    def write(self):
        print('进程数据的读取方法')

wenbenwenjian=Txt()

yingpanwenjian=Sata()

jinchengwenjian=Process()

#这样大家都是被归一化了,也就是一切皆文件的思想
wenbenwenjian.read()
yingpanwenjian.write()
jinchengwenjian.read()

print(wenbenwenjian.all_type)
print(yingpanwenjian.all_type)
print(jinchengwenjian.all_type)


#以上代码执行结果如下:
文本数据的读取方法
硬盘数据的读取方法
进程数据的读取方法
file
file
file
抽象类的应用

 

抽象类与接口

  抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计 

 

十一.多态

  多态性(polymorphisn)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。
  那么,多态的作用是什么呢?我们知道,封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——代码重用。而多态则是为了实现另一个目的——接口重用!多态的作用,就是为了类在继承和派生的时候,保证使用“家谱”中任一类的实例的某一属性时的正确调用。
   多态:我们可以这么理解,就是一种事物的不同形态如序列类型包含:字符串,列表,元组;
   多态性:一个接口函数有多种实现方式。
 
#!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :rianley
#blog:http://www.cnblogs.com/rianley
#EMAIL:rianley@qq.com
#序列内形的不同形态如下:分别有字符串,元组和列表,这就体现了同一种食物的不同形态,简称多态。
name = "程小航"
tuple_test = ("rianley","123")
list_test = ["程小航","21","175","上海","黄埔"]


#多态性:一个入口函数有多种实现方式
def fun(obj): #"obj"这个参数就体现多态性。原理就是传递进来的对象都有相同(同名)的“__len__()”方法,只不过同一个方法会执行不同的功能而已。
    print(obj.__len__()) #相当于len(obj)

fun(name)
fun(tuple_test)
fun(list_test)


#以上代码的执行结果如下:
3
2
5
案例一
#!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :rianley
#blog:http://www.cnblogs.com/rianley
#EMAIL:rianley@qq.com
#多态如下:
class Animal:
    def talk(self):
        pass
class People(Animal):
    def talk(self):
        print("say hello")

class Pig(Animal):
    def talk(self):
        print("say heng····heng")

class Dog(Animal):
    def talk(self):
        print("say wang···wang")

class Cat(Animal):
    def talk(self):
        print("miao~miao~miao~")

p1 = People()  #这就是一个实例,其本质上就是将“p1 = People()”传递给“self”
pig1 = Pig()
D1 = Dog()
c  = Cat()

#多态性:
def fun(obj):
    obj.talk()
fun(p1)
fun(pig1)
fun(D1)
fun(c)

#以上代码执行结果如下:
say hello
say heng····heng
say wang···wang
miao~miao~miao~
案例二
#!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :rianley
#blog:http://www.cnblogs.com/rianley
#EMAIL:rianley@qq.com
#定义多态如下:
class Animal(object):
    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):
        print('【%s】: 喵喵喵!' % self.name)
class Dog(Animal):
    def talk(self):
        print('【%s】: 汪!汪!汪!' % self.name)
#定义多态性:
def func(obj):  # 一个接口,多种形态
    obj.talk()
c1 = Cat('hello kitty')
d1 = Dog('犬夜叉')

func(c1)
func(d1)

#以上代码执行结果如下:
【hello kitty】: 喵喵喵!
【犬夜叉】: 汪!汪!汪!
案例三

Pyhon 很多语法都是支持多态的,比如 len(),sorted(), 你给len传字符串就返回字符串的长度,传列表就返回列表长度。

#!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :rianley
#blog:http://www.cnblogs.com/rianley
#EMAIL:rianley@qq.com
'''
继承的作用:
    1>.直接调用父类方法;
    2>.继承父类方法并重构父类方法,先重构,在重构的方法里手动调用父类方法
    3>.可以定义子类自己的方法;
    4>.可以析构方法"__del__"
'''
class SchoolMember(object):
    members = 0
    test = 111111
    print("in  SchoolMember ")
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
        SchoolMember.members += 1  #注意着是调用的类变量,我们不能用"self.members"去自加哟!
        print("初始化了一个新学校成员",self.name)
class Course(object):  #定义一个类其实也可以不用谢初始化函数用,只写类变量也可以
    test = 666666
    print("in  Course ")
    Course_name = "python自动化"
    period = "9m"
    outtline = "test"
class Student(SchoolMember,Course): #继承了2个父类,继承顺序优先级由左往右依次递减
    def __init__(self, name, age, sex, salary):  # 初始化函数
        SchoolMember.__init__(self, name, age, sex)
    def pay_tuition(self, amount):
        self.paid_tuition = amount #存在实例里,方便其他函数(方法)调用。
        print("student %s has paid tution amoint %s" % (self.name, amount))
s = Student("rianley","25","M","pys11000")
print(s.Course_name,Course.outtline)
print(s.test)


#以上代码执行结果如下:
in  SchoolMember 
in  Course 
初始化了一个新学校成员 rianley
python自动化 test
111111
继承

 

毒鸡汤:

其实,做一件事情,你智商不高没问题,你情商不高也没有问题,关键是在于坚持。欢迎加入程序员之家:687226766

posted @ 2018-06-01 15:47  rianley  阅读(206)  评论(0编辑  收藏  举报