python自动化运维之面向对象基础

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python自动化运维之面向对象基础相关的知识,希望对你有一定的参考价值。

python中一切皆为对象
      其实面向对象没什么高大上的东西,只不过把我们平时对于事物的描述和动作系统的总结成了一个定义事物的方法而已。
我们平时向别人介绍一个他(她)从未见过的东西,会从外形和外貌特征来说明这个东西,比如颜色,大小等,这就对象的属性。还会介绍这个东西能做什么或者有什么用,这就是对象的方法。所以用属性和方法就可以定义一个对象。也就是说一个对象包含了各种属性和方法。
     在python中使用对象属性和方法的记法为:object.attribute 或 object.method()
     Python中创建对象的第一步是建立一个类(class),这个类就类似于我们区分动物和植物。动物类和植物类各有自己的特征,当我们见到一个事物时,如果它满足动物的特征,我们就说它是动物;如果它满足植物的特征,那么它就属于植物。同样的当我们在python中建立一个类时,就要说名这个类的属性有什么,方法有什么。然后再创建属于这个类的具体实例,也就是对象。那么这个对象也就有了这个类的属性和方法。但具体的属性和方法根据具体对象而定。就像动物类的属性就是有耳朵,有眼睛,有皮毛,方法就是移动,进食等等,具体对象比如说是兔子那就是有长长的耳朵,红色的眼睛,白色的皮毛。方法就是奔跑,进食就是吃胡萝卜。这样理解类和对象或者实例就没什么抽象的了。
1、简单概述
    面向过程:根据业务逻辑从上到下写垒代码,核心是过程二字,过程及即解决问题的步骤,是一种机械式的思维方式。
    函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可,实现了代码的重复使用
    面向对象:对函数进行分类和封装,让开发“更快更好更强...”
2、定义类,实例化对象
面向对象编程是一种编程方式,此编程方式的落地需要使用 “类” 和 “对象” 来实现,所以,面向对象编程其实就是对 “类” 和 “对象” 的使用。
类就是一个模板,模板里可以包含多个函数,函数里实现一些功能
对象则是根据模板创建的实例,通过实例对象可以执行类中的函数

# 创建myclass类
class myclass: # 用关键字class进行类的定义  即 “class 类名:”
    def Hello(self, name): # self为实例化的对象本身,必须填写,即将被实例化的对象obj
        print("%s, Hello!" %name)
# 根据类myclass创建对象obj
obj = myclass()
obj.Hello(‘炫维‘) #执行Hello方法

执行结果:

炫维, Hello!

注意:类中的函数至少有一个位置参数self(也可以是其他的名称),类中定义的函数叫做 “方法”

class myclass:      # 用关键字class进行类的定义  即 “class 类名:”
    def __init__(self):
        # 类中定义的函数叫做 “方法”  __init__ 方法是构造方法 根据类创建对象时自动执行
        # self为实例化的对象本身  即即将被实例化的对象obj
        print("this is my class")
obj = myclass()  # 实例化类 创建对象 会自动执行类中的 __init__

运行结果:

this is my class

当然, __init__() 方法可以有参数,参数通过 __init__() 传递到类的实例化操作上。例如:

class myclass:
    def __init__(self, name1, age1):
        self.name = name1
        self.age = age1
# 因为会自动执行类中的 __init__方法,且该方法中有参数,所以实例化对象时需要传递参数
# self是一个形式参数, 当执行下句代码时,实例化对象obj1,那么self就等于obj1这个对象
obj1 = myclass("IKTP", 22)
# 当执行下句代码时,实例化对象obj2,那么self就等于obj2
# 且这两个对象同都拥有两个属性:name,age
obj2 = myclass("hahaha", 23)
# 当需要调用对象的属性时,即name和age属性,可以直接用对象名字后打点调用需要的属性,例如:
print(obj1.name)  # 执行结果:IKTP
print(obj1.age)   # 执行结果:22
print(obj2.name)  # 执行结果:hahaha
print(obj2.age)   # 执行结果:23

执行结果:

IKTP
22
hahaha
23

3、属性定义
3.1 类属性
类属性定义在类中且在函数体之外;类属性通常不作为实例属性使用;类变量紧接在类名后面定义
类属性的引用:类名.count eg:Employee.count
实例中可以引用类的属性:
a、通过类名引用
b、通过实例名:读取的操作,写的操作(操作的属性是实例的属性,不是类的属性,对类的属性没有影响)

3.2 实例属性
定义在方法中的变量,只作用于当前实例的类;实例变量在__init__()函数里定义
如果所添加的属性名与类中类属性名相同的时,类属性在这个实例对象中就会被屏蔽掉,也就是说实例引用时,同名的实例属性会屏蔽同名的类属性,就类似于全局变量与局部变量的关系。

3.3 局部变量
在类的实例方法中定义的变量,叫局部变量,其作用域仅限于其所在的函数内部,执行到该函数,局部变量生成,函数退出后,局部变量被消亡。
3.4 @porperty 属性装饰器
使用:

@property
def score(self):
    return self.__score
s1=Student(‘a‘,18,90)
print s1.score 直接把方法当属性使用
@property.setter @score.setter 修饰器 修改
def score(self,score):
    pass
s1.score=98 修饰器
@property.deleter @score.deleter 删除

例如:

class Goods():
    def __init__(self,price):
        self.__price=price
    @property
    def price(self):
        print(‘@porperty‘)
        return self.__price
    @price.setter
    def price(self,price1):
        self.__price=price1
        print(‘@price setter‘)
    @price.deleter
    def price(self):
        del self.__price
        print(‘@price.deleter‘)
obj=Goods(100)
print obj.price
obj.price=123
del obj.price

3.5 类的私有属性
两个下划线开头属性,声明该属性为私有属性,不能在类的外部被使用或直接访问,只能在类内部访问。在类内部的方法中使用时的语法:self.__private_attrs。 eg:self.__name
例如

class Person():
    __secretCount = 0 #私有属性
    def __init__(self, name):
        self.name = name #实例属性
        self.__inName = ‘ads‘ #私有属性
    def visit_private_attribute( self ):
        self.__secretCount += 1
        print("__secretCount: ", self.__secretCount)
        print(u"__inName:", self.__inName)
p = Person("prel")
p.visit_private_attribute() 通过方法获取类的私有属性
print u"在类外直接通过实例访问私有属性"
print p.__inName 在类外直接调用,会报错

python的语法并不是那么严格的能够保证私有变量不被随意改动,以下方式可以访问私有属性:

object._className__attrName eg:p._Person__inName

3.4 属性相关
3.4.1 修改类属性
修改类属性的值,有三种方法,分别为:
(1)通过类方法修改
(2)通过实例方法修改
(3)直接通过类对象修改

class employee(object) :
    city = ‘BJ‘ #类属性
    def __init__(self, name) :
        self.name = name #实例变量
    #定义类方法
    @classmethod
    def getCity(cls) :
        return cls.city
    #定义类方法
    @classmethod
    def setCity(cls, city) :
        cls.city = city
    #实例方法
    def set_City(self, city) :
        employee.city = city

调用:

emp = employee(‘joy‘)     # 创建类的实例
print(emp.getCity())      # 通过实例对象引用类方法
print(employee.getCity()) # 通过类对象引用类方法
emp.setCity(‘TJ‘)         # 实例对象调用类方法改变类属性的值
print(emp.getCity())
print(employee.getCity())
employee.setCity(‘CD‘)#类对象调用类方法改变类属性的值
print(emp.getCity())
print(employee.getCity())
emp.set_City(‘SH‘)#调用实例方法修改类属性的值
print(emp.getCity())
print(employee.getCity())
employee.city = 20 #直接修改类属性的值
print(emp.getCity())
print(employee.getCity())

3.4.2 作用域
print(locals()) 返回所有的局部变量
print(globals()) 返回所有的全局变量
在python的作用域规则里面,创建变量时一定会在当前作用域里创建同样的变量,但访问或修改变量时,会在当前作用域中查找该变量,如果没找到匹配的变量,就会依次向上在闭合作用域中进行查找,所以在函数中直接访问全局变量也是可以的
learn to fail, failure to learn
4、方法
方法分为三种:实例方法,类方法,静态方法创建实例对象
4.1 静态方法
通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法,什么是静态方法呢?其实不难理解,普通的方法,可以在实例化后直接调用,并且在方法里可以通过self.调用实例变量或类变量,但静态方法是不可以访问实例变量或类变量的,一个不能访问实例变量和类变量的方法,其实相当于跟类本身已经没什么关系了,它与类唯一的关联就是需要通过类名来调用这个方法

class Dog(object):
    def __init__(self,name):
        self.name = name
    @staticmethod #把eat方法变为静态方法
    def eat(self):
        print("%s is eating" % self.name)
d = Dog("tom")
d.eat()

上面的调用会出以下错误,说是eat需要一个self参数,但调用时却没有传递,没错,当eat变成静态方法后,再通过实例调用时就不会自动把实例本身当作一个参数传给self了。
TypeError: eat() missing 1 required positional argument: ‘self‘
想让上面的代码可以正常工作有两种办法
1. 调用时主动传递实例本身给eat方法,即d.eat(d)
2. 在eat方法中去掉self参数,但这也意味着,在eat中不能通过self.调用实例中的其它变量了

class Dog(object):
    def __init__(self,name):
        self.name = name
    @staticmethod
    def eat():
        print(" is eating")
d = Dog("tom")
d.eat()

执行结果:

 is eating

4.2 类方法  
类方法通过@classmethod装饰器实现,类方法和普通方法的区别是, 类方法只能访问类变量,不能访问实例变量

class Dog(object):
    def __init__(self,name):
        self.name = name
    @classmethod
    def eat(self):
        print("%s is eating" % self.name)
d = Dog("tom")
d.eat()

执行报错如下,说Dog没有name属性,因为name是个实例变量,类方法是不能访问实例变量的
AttributeError: type object ‘Dog‘ has no attribute ‘name‘
此时可以定义一个类变量,也叫name,看下执行效果

class Dog(object):
    name = "我是类变量"
    def __init__(self,name):
        self.name = name
    @classmethod
    def eat(self):
        print("%s is eating" % self.name)
d = Dog("tom")
d.eat()

执行结果:

我是类变量 is eating
class myclass:
    public_var = "this is public_var"
    def __init__(self, name1, age1):
        self.name = name1
        self.age = age1
    #  在类里面定义的函数,统称为方法,方法参数自定义,可在方法中实现相关的操作
    #  创建实例方法时,参数必须包括self,即必须有实例化对象才能引用该方法,引用时不需要传递self实参
    def speak(self):
        print("this is def speak.%s 说:我今年%d岁。" % (self.name, self.age))
    #  我们要写一个只在类中运行而不在实例中运行的方法. 如果我们想让方法不在实例中运行
    #  比如我们需要类中的基础字段public_var,根本不需要实例化对象就可以拿到该字段
    #  这时就需要装饰器@classmethod来创建类方法,至于classmethod的使用场合,会在下篇文章介绍
    #  创建类方法时,参数必须包括cls,即必须用类来引用该方法,引用时不需要传递cls实参
    @classmethod
    def speak2(cls):
        print("this is classmethod")
        return cls.public_var
    #  经常有一些跟类有关系的功能但在运行时又不需要实例和类参与的情况下需要用到静态方法
    #  写在类里的方法,必须用类来调用(极少数情况下使用,一般都在全局里直接写函数了)
    @staticmethod
    def speak3(name2, age2):
        print("this is staticmethod.%s 说:我今年%d岁。" % (name2, age2))

# 无论是类方法、静态方法还是普通方法都可以被实例化的对象调用
# 但是静态方法和类方法可以不用对象进行调用
obj = myclass("IKTP", 22)
obj.speak()                # 执行结果:this is def speak.IKTP 说:我今年22岁。
var = obj.speak2()         # 执行结果:this is classmethod
print(var)                 # 执行结果:this is public_var
obj.speak3("liu", 23)      # 执行结果:this is staticmethod.liu 说:我今年23岁。
# myclass.speak()          # 报错,实例方法不能直接被调用,必须需要实例化的对象调用
var2 = myclass.speak2()    # 不需要实例化对象即可拿到该字段
print(var2)                # 不需要实例化对象即可拿到该字段
myclass.speak3("abc", 12)  # 不需要实例化对象即可执行

执行结果:

this is def speak.IKTP 说:我今年22岁。
this is classmethod
this is public_var
this is staticmethod.liu 说:我今年23岁。
this is classmethod
this is public_var
this is staticmethod.abc 说:我今年12岁。

4.3 属性方法
属性方法的作用就是通过@property把一个方法变成一个静态属性

class Dog():
    def __init__(self,name):
        self.name = name
    @property
    def eat(self):
        print(" %s is eating" %self.name)
d = Dog("ChenRonghua")
d.eat()

5、面向对象三大特性
面向对象的三大特性是指:封装、继承和多态。
5.1 封装
封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。所以,在使用面向对象的封装特性时,需要:
①将内容封装到某处
②从某处调用被封装的内容
第一步:将内容封装到某处

class myclass:
    def __init__(self,name,age):
        self.name = name
        self.age = age
obj1 = myclass("xuanwei", 18 )
obj2 = myclass("tom", 28 )

self 是一个形式参数,当执行obj1 = myclass("xuanwei", 18 )时,self等于obj1;当执行obj2 = myclass("tom", 28 )时,self等于obj2
所以,内容其实被封装到了对象 obj1 和 obj2 中,每个对象中都有name和age属性,在内存里类似于下图来保存。

      ┌─> name = xuanwei
obj1─│
      └─> age = 18
      ┌─> name = tom
obj2─│
      └─> age = 18

第二步:从某处调用被封装的内容
调用被封装的内容时,有两种情况:
通过对象直接调用
通过self间接调用
1、通过对象直接调用被封装的内容
上图展示了对象obj1和obj2 在内存中保存的方式,根据保存格式可以如此调用被封装的内容:对象.属性名

class myclass:
    def __init__(self,name,age):
        self.name = name
        self.age = age
obj1 = myclass("xuanwei", 18 )
print("name: %s; age: %s" %(obj1.name,obj1.age))
obj2 = myclass("tom", 78 )
print("name: %s; age: %s" %(obj2.name,obj2.age))

执行结果:

name: xuanwei; age: 18
name: tom; age: 78

2、通过self间接调用被封装的内容
执行类中的方法时,需要通过self间接调用被封装的内容

class myclass:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def detail(self):
        print("name: %s; age: %s" %(self.name,self.age))
obj1 = myclass("xuanwei", 18 )
obj1.detail()  # Python默认会将obj1传给self参数,即:obj1.detail(obj1),所以,此时方法内部的self=obj1,即:self.name是xuanwei ;self.age 是 18
obj2 = myclass("tom", 28 )
obj2.detail()  # Python默认会将obj2传给self参数,即:obj1.detail(obj2),所以,此时方法内部的 self = obj2,即:self.name 是tom; self.age 是 28

执行结果:

name: xuanwei; age: 18
name: tom; age: 28

综上所述,对于面向对象的封装来说,其实就是使用构造方法将内容封装到 对象 中,然后通过对象直接或者self间接获取被封装的内容。
练习一:在终端输出如下信息

    小明,10岁,男,上山去砍柴
    小明,10岁,男,开车去东北
    小明,10岁,男,最爱大保健
    老李,90岁,男,上山去砍柴
    老李,90岁,男,开车去东北
    老李,90岁,男,最爱大保健

函数式编程:

def kanchai(name, age, gender):
    print("%s,%s岁,%s,上山去砍柴 " %(name, age, gender))
def qudongbei(name, age, gender):
    print("%s,%s岁,%s,开车去东北 " %(name, age, gender))
def dabaojian(name, age, gender):
    print("%s,%s岁,%s,最爱大保健 " %(name, age, gender))
kanchai(‘小明‘, 10, ‘男‘)
qudongbei(‘小明‘, 10, ‘男‘)
dabaojian(‘小明‘, 10, ‘男‘)
kanchai(‘老李‘, 90, ‘男‘)
qudongbei(‘老李‘, 90, ‘男‘)
dabaojian(‘老李‘, 90, ‘男‘)

面向对象编程:

class myclass:
    def __init__(self, name,age, gender):
        self.name = name
        self.age = age
        self.gender = gender
    def kanchai(self):
        print("%s,%s岁,%s,上山去砍柴 " %(self.name, self.age, self.gender))
    def qudongbei(self):
        print("%s,%s岁,%s,开车去东北 " %(self.name, self.age, self.gender))
    def dabaojian(self):
        print("%s,%s岁,%s,最爱大保健 " %(self.name, self.age, self.gender))
xiaoming = myclass("小明", 10, "男")
xiaoming.kanchai()
xiaoming.qudongbei()
xiaoming.dabaojian()
laoli = myclass("老李", 90, "男")
laoli.kanchai()
laoli.qudongbei()
laoli.dabaojian()

上述对比可以看出,如果使用函数式编程,需要在每次执行函数时传入相同的参数,如果参数多的话,又需要粘贴复制了...  ;而对于面向对象只需要在创建对象时,将所有需要的参数封装到当前对象中,之后再次使用时,通过self间接去当前对象中取值即可。
练习二:游戏人生程序

1、创建三个游戏人物,分别是:
    苍井井,女,18,初始战斗力1000
    东尼木木,男,20,初始战斗力1800
    波多多,女,19,初始战斗力2500
2、游戏场景,分别:
    草丛战斗,消耗200战斗力
    自我修炼,增长100战斗力
    多人游戏,消耗500战斗力

实现功能:

class Person:
    def __init__(self, na, gen, age, fig):
        self.name = na
        self.gender = gen
        self.age = age
        self.fight =fig
    def grassland(self):
        """注释:草丛战斗,消耗200战斗力"""
        self.fight = self.fight - 200
    def practice(self):
        """注释:自我修炼,增长100战斗力"""
        self.fight = self.fight + 200
    def incest(self):
        """注释:多人游戏,消耗500战斗力"""
        self.fight = self.fight - 500
    def detail(self):
        """注释:当前对象的详细情况"""
        temp = "姓名:%s ; 性别:%s ; 年龄:%s ; 战斗力:%s"  % (self.name, self.gender, self.age, self.fight)
        print(temp)
# 开始游戏
cang = Person(‘苍井井‘, ‘女‘, 18, 1000)    # 创建苍井井角色
dong = Person(‘东尼木木‘, ‘男‘, 20, 1800)  # 创建东尼木木角色
bo = Person(‘波多多‘, ‘女‘, 19, 2500)      # 创建波多多角色
cang.incest() #苍井空参加一次多人游戏
dong.practice()#东尼木木自我修炼了一次
bo.grassland() #波多多参加一次草丛战斗
#输出当前所有人的详细情况
cang.detail()
dong.detail()
bo.detail()
cang.incest() #苍井空又参加一次多人游戏
dong.incest() #东尼木木也参加了一个多人游戏
bo.practice() #波多多自我修炼了一次
#输出当前所有人的详细情况
cang.detail()
dong.detail()
bo.detail()

5.2 继承
继承是面向对象的重要特征之一,继承是两个类或者多个类之间的父子关系,子类继承了父类的所有公有实例变量和方法。
继承实现了代码的重用。重用已经存在的数据和行为,减少代码的重新编写。
python在类名后用一对圆括号表示继承关系,括号中的类表示父类

class father:
    father_var = "this is father_var"
    def father_def(self):
        print("this is father_def")
class son(father):  # 括号里有类名,代表该类是子类(派生类),继承自父类(基类)father
    pass
obj = son()
# son子类中没有father_var 则去父类father中寻找
print(obj.father_var)  # 执行结果:this is father_var
# son子类中没有father_def方法 则去父类father中寻找
obj.father_def()  # 执行结果:this is father_def

如果父类中有构造方法且子类也有构造方法,则在子类中必须亲自调用且传递相对应的参数
# 如果父类中有构造方法且子类也有构造方法,则在子类中必须亲自调用且传递相对应的参数
# 否则无法找到在父类中定义的属性
# 错误方式

class father:
    def __init__(self, n):
        self.name = n
class son(father):
    def __init__(self):
        print("aaaaa")
obj = son()

# 子类中没有name属性,且没有在子类中调用并传递相对应的参数给父类的构造方法,所以找不到name属性 报错
print(obj.name)
# 正确方式

class father:
    def __init__(self, n):
        self.name = n
class son(father):
    def __init__(self):
        father.__init__(self, "6666")
obj = son()
print(obj.name)  # 执行结果 6666

如果父类中没有构造方法  则不必调用
如果父类中有构造方法但子类中没有构造方法,则在实例化子类对象的时候需要传递父类中的构造参数

class father:
    def __init__(self, n):
        print("bbbbbbbb")
        self.name = n
class son(father):
    def speak(self):
        print("aaaaa")
obj = son()  # 报错 因为子类没有构造方法,所以会执行父类的构造方法,但是没有给父类的构造方法

传递参数

obj = son("IKTP")
print(obj.name)  # 执行结果: IKTP
在子类中调用父类的方法
class father:
    def speak(self):
        print("this is father speak")
class son(father):
    def speak2(self):
        # 调用父类的speak方法的三种方式
        father.speak(self)  # 直接类名后打点调用方法,需要传递self
        super().speak()  # super()代指父类
        super(son, self).speak()
        print("this is son speak2")
obj = son()
obj.speak2()

运行结果:

this is father speak
this is father speak
this is father speak
this is son speak2

覆盖(重写)父类方法

class father:
    def speak(self):
        print("this is father speak")
    def speak2(self):
        print("this is father speak2")
class son(father):
    def speak2(self):
        print("this is son speak2")
obj = son()
obj.speak2()

运行结果:

this is son speak2

# 对象总会先在实例化该对象的类里寻找属性字段或者方法,
# 如果有则执行,如果该类里没有,则再去父类里寻找
# 由于父类本来拥有speak2方法,但是子类里又写了一个speak2方法
# 所以obj不会去父类里寻找该方法,只会执行子类里的speak2方法,这样就称为覆盖或重写

5.3 多继承
一个类可同时继承多个类,与多个类具有继承关系,则这个类可调用所有父类中的方法和字段

class father1():
    father1_var = "this is father1_var"
    def father1_def(self):
        print("this is father1_def")
class father2():
    father2_var = "this is father2_var"
    def father2_def(self):
        print("this is father2_def")
class son(father1, father2):  # son类同时继承father1类和father2类
    def son_def(self):
        print("this is son_def")
obj = son()
print(obj.father1_var)
print(obj.father2_var)
obj.father1_def()
obj.father2_def()

执行结果:

this is father1_var
this is father2_var
this is father1_def
this is father2_def

那么问题来了,假如父类中有相同的字段或者方法名,那么会调用谁的呢?我们来试一试
myclass类同时继承son类和son2类,son类继承father类,father类和son2类又同时继承grandf类
并且每个类里面都有speak方法,我们实例化myclass对象调用speak方法去试试

class grandfather:
    def speak(self):
        print("this is grandfather_def")
class father(grandfather):
    def speak(self):
        print("this is father_def")
class son(father):
    def speak(self):
        print("this is son_def")
class son2(grandfather):
    def speak(self):
        print("this is son2_def")
class myclass(son, son2):
    def speak(self):
        print("this is myclass_def")
obj = myclass()
obj.speak()

执行结果:

this is myclass_def

#先执行myclass里的speak方法
将myclass里的方法speak方法注释掉再运行

class grandfather:
    def speak(self):
        print("this is grandfather_def")
class father(grandfather):
    def speak(self):
        print("this is father_def")
class son(father):
    def speak(self):
        print("this is son_def")
class son2(grandfather):
    def speak(self):
        print("this is son2_def")
class myclass(son, son2):
    pass
obj = myclass()
obj.speak()

执行结果:

this is son_def

#执行的是son类里的方法
将myclass、son类里的方法speak方法注释掉再运行

class grandfather:
    def speak(self):
        print("this is grandfather_def")
class father(grandfather):
    def speak(self):
        print("this is father_def")
class son(father):
    pass
class son2(grandfather):
    def speak(self):
        print("this is son2_def")
class myclass(son, son2):
    pass
obj = myclass()
obj.speak()

执行结果:

this is father_def

#执行的是father类的方法
将myclass、son、father类里的方法speak方法注释掉再运行

class grandfather:
    def speak(self):
        print("this is grandfather_def")
class father(grandfather):
    pass
class son(father):
    pass
class son2(grandfather):
    def speak(self):
        print("this is son2_def")
class myclass(son, son2):
    pass
obj = myclass()
obj.speak()

执行结果:

this is son2_def

#执行的是son2类里的方法
将myclass、son、father、son2类里的方法speak方法注释掉再运行

class grandfather:
    def speak(self):
        print("this is grandfather_def")
class father(grandfather):
    pass
class son(father):
    pass
class son2(grandfather):
    pass
class myclass(son, son2):
    pass
obj = myclass()
obj.speak()

执行结果:

this is grandfather_def

#执行的方法是grandfather类的方法
由上可知,myclass实例化的对象找speak方法的执行顺序是

myclass-->son-->father-->son2-->grandfather

所以得出结论:经典类的搜索方式是按照“从左至右,深度优先”的方式去查找属性,有共同父类的话最后查找父类,无共同父类则“从左到右”挨个将左边类的所有父类关系查找一遍,再向右查找
5.4 多态
多态性(polymorphisn)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。那么,多态的作用是什么呢?我们知道,封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——代码重用。而多态则是为了实现另一个目的——接口重用!多态的作用,就是为了类在继承和派生的时候,保证使用“家谱”中任一类的实例的某一属性时的正确调用。Pyhon不直接支持多态,但可以间接实现

class Animal:
    def __init__(self, name):  # Constructor of the class
        self.name = name
    @staticmethod
    def animal_talk(obj):
        obj.talk()
class Cat(Animal):
    def talk(self):
        print(‘%s:Meow!‘%(self.name))
class Dog(Animal):
    def talk(self):
        print(‘%s:Woof! Woof!‘%(self.name))
c = Cat(‘Missy‘)
d = Dog(‘Lassie‘)
Animal.animal_talk(c)
Animal.animal_talk(d)

执行结果:

Missy:Meow!
Lassie:Woof! Woof!

6、总结
以上就是本节对于面向对象初级知识的介绍,总结如下:
面向对象是一种编程方式,此编程方式的实现是基于对 类和对象 的使用,类是一个模板,模板中包装了多个“函数”供使用;对象,根据模板创建的实例(即:对象),实例用于调用被包装在类中的函数
面向对象三大特性:封装、继承和多态
类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。

类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
实例变量:定义在方法中的变量,只作用于当前实例的类。
继承:即 一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是 模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
实例化:创建一个类的实例,类的具体对象。
方法:类中定义的函数。
对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法


本文出自 “炫维” 博客,请务必保留此出处http://xuanwei.blog.51cto.com/11489734/1957047

以上是关于python自动化运维之面向对象基础的主要内容,如果未能解决你的问题,请参考以下文章

Python自动化运维之异常处理

Python自动化运维之异常处理

python自动化运维之读书笔记

Python3自动化运维之Fabric模版详解

自动化运维之ansible-安装部署与基础命令篇

python自动化运维之Socket网络编程