Python自动化运维之路Day8基础篇之面向对象下篇

Posted DBQ

tags:

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

今日目录:

类成员

类成员修饰符

特殊的类成员

面向对象相关联的其他知识

异常捕获与处理

设计模式之单例模式

 

一. 类成员

类的成员有:字段、方法和属性

关系图如下:

1. 字段:

字段分:

  • 静态字段
  • 普通字段

两者在定义和使用上有所区别,如下代码:

class Province:
    contry = \'中国\'  #静态字段,保存在类中

    def __init__(self,name):
        self.name = name  #普通字段,保存在对象中

在内存中的存储位置是不同的, 静态字段保存在类中, 而普通字段保存在对象中。调用字段:

class Province:
    contry = \'中国\'

    def __init__(self,name):
        self.name = name


sx = Province(\'山西\')

#访问静态字段和普通字段
# 静态字段存储在类中, 使用类调用, 如 Province.contry
# 普通字段存储在对象中, 由对象调用, 如 sx.name
print(\'国家: %s\\n省份: %s\'%(Province.contry,sx.name))

#执行结果:
国家: 中国
省份: 山西

 可以看出:

静态字段存储在类中, 只在内存中保存一份;

普通字段存储在每个对象中,需要在每个对象中都保存一份

所以,当类创建时,如果每个对象都具有相同的字段,就使用静态字段。

2. 方法

包括:

  • 普通方法,由对象调用,至少需要一个self参数。执行普通方法时,self就是对象本身,自动将调用该方法的对象赋值给self
  • 静态方法,属于类,由来调用执行,无默认参数,等同于函数。创建方式:  @staticmethod。
  • 类方法,是静态方法的一种特殊形式。由调用,至少要有一个参数cls,值为类名。创建方式: @classmethod

所有的方法都属于类,只不过调用方式不同。

class Province:
    #静态字段
    country = \'中国\'

    def __init__(self,arg):
        self.arg = arg

    #普通方法
    def show(self):
        print(\'普通方法,由对象调用,至少需要一个self参数。执行普通方法时,self就是对象本身,自动将调用该方法的对象赋值给self!\')

    #静态方法
    @staticmethod
    def static_show():
        print(\'静态方法,属于类,由类来调用执行,无默认参数。创建方式:  @staticmethod\')

    @classmethod
    def class_show(cls):
        print(\'是静态方法的一种特殊形式。由类调用,至少要有一个参数cls,值为类名。创建方式: @classmethod\')
        # print(cls)

#调用静态方法,由类调用
Province.static_show()
#调用类方法, 由类调用
Province.class_show()

#调用普通方法,需要先实例化
obj = Province(\'山西\')
obj.show()

#执行结果:
静态方法,属于类,由类来调用执行,无默认参数。创建方式:  @staticmethod
是静态方法的一种特殊形式。由类调用,至少要有一个参数cls,值为类名。创建方式: @classmethod
普通方法,由对象调用,至少需要一个self参数。执行普通方法时,self就是对象本身,自动将调用该方法的对象赋值给self!



#类方法的参数cls是类本身,也可以在类方法里操作, 如下:
    @classmethod
    def class_show(cls):
        # print(\'是静态方法的一种特殊形式。由类调用,至少要有一个参数cls,值为类名。创建方式: @classmethod\')
        a = cls(\'核弹\')
        a.static_show()


#执行结果:
静态方法,属于类,由类来调用执行,无默认参数。创建方式:  @staticmethod
定义和使用方法

相同点:由于所有的方法都属于类, 所以在内存中存储只保存一份。

不同点:由于各种方法的调用方式不同,调用方法时自动传入的参数不同。

但是有个比较刺激的, 继续上面的例子:

#直接在对象中调用静态方法和类方法
obj = Province(\'山西\')
obj.show()
obj.static_show()
obj.class_show()

#执行结果:
普通方法,由对象调用,至少需要一个self参数。执行普通方法时,self就是对象本身,自动将调用该方法的对象赋值给self!
静态方法,属于类,由类来调用执行,无默认参数。创建方式:  @staticmethod
是静态方法的一种特殊形式。由类调用,至少要有一个参数cls,值为类名。创建方式: @classmethod

so,也是可以被调用的,虽说可以调用,但是不到万不得已,不要用对象来直接调用原属于类该调用的东西。这就是要谈到的要遵循的编程规则了:

一般情况下,自己访问自己的字段,虽说Python没有做严格的限制,但是这是理应遵循的一种编程习惯。

3. 属性

访问属性时和访问字段时一样,不需要加()。 在Python中,属性其实就是普通方法的变种

(1) 基本使用

class C1:
    xxx = \'静态字段\'
    def func(self):
        print(\'普通方法\')

    #定义一个属性,使用 @property装饰
    @property
    def f1(self):
        print(\'属性\')

#实例化
obj = C1()
#调用普通字段,用类调用
C1.xxx
#调用普通方法, 需要()
obj.func()
#调用定义的属性,直接用调用字段的方式,不用加()
obj.f1


#代码执行结果:
普通方法
属性
class C1:
    xxx = \'静态字段\'
    def func(self):
        print(\'普通方法\')

    #定义一个属性,使用 @property装饰
    @property
    def f1(self):
        return \'属性\'  

#实例化
obj = C1()
#调用普通字段,用类调用
C1.xxx
#调用普通方法, 需要()
obj.func()
#调用定义的属性,直接用调用字段的方式,不用加()
result = obj.f1  #如果有return值,需要赋值给变量,而后调用
print(result)
View Code

属性的定义和调用要注意:

定义时,在普通方法上面加 @property 装饰器来装饰

定义时,属性中仅有一个self参数,不能有其他的

调用的时候, 不需要()

属性存在意义是: 访问属性时可以制造出和访问字段相同的假象

属性是普通方法变种而来,如果Python中没有属性,方法完全可以代替其功能。

实例: 对于主机列表页面,每次请求不可能把数据库中的所有的内容显示到页面上,而是通过分页的功能显示,所以,在向数据库请求数据时就需要显式指定获取从第m条到第n条的数据(limit m,n), 这个分页的功能包括:

  • 根据用户请求的当前页和总数据条数计算出m和n
  • 根据m和n去数据库中请求数据
class Pager:
    def __init__(self,curr_num,per_page):
        \'\'\'
        构造函数
        :param curr_num:  当前请求的页码
        :param per_page:  每页要显示的数据
        :return:
        \'\'\'
        self.curr_num = curr_num
        self.per_page = per_page

    #计算出开始位
    @property
    def start(self):
        #-1就是找出上一页开始位置
        value = (self.curr_num-1) * self.per_page
        return value

    #计算出结束位
    @property
    def end(self):
        value = self.curr_num * self.per_page
        return value

#实例化,传入请求页码和每页显示的数量
#要显示哪页,传入参数即可
P = Pager(1,10)

#起始值
print(P.start)
#结束值
print(P.end)


#执行结果
0
10
实例

(2) 属性的两种定义方式

a. 装饰器方式:

在普通方法的上面添加 @property装饰器的方式

Python中的类有经典类和新式类(python3中全是新式类),新式类的类型比经典类丰富。(如果类继object,那么该类是新式类)

经典类,有一种 @property装饰器

class Pager:
    def __init__(self,curr_num,per_page):
        \'\'\'
        构造函数
        :param curr_num:  当前请求的页码
        :param per_page:  每页要显示的数据
        :return:
        \'\'\'
        self.curr_num = curr_num
        self.per_page = per_page

    #计算出开始位
    @property
    def start(self):
        #-1就是找出上一页开始位置
        value = (self.curr_num-1) * self.per_page
        return value

    #计算出结束位
    @property
    def end(self):
        value = self.curr_num * self.per_page
        return value

#实例化,传入请求页码和每页显示的数量
P = Pager(1,10)

#起始值
print(P.start)  #自动执行 @property装饰的start方法
#结束值
print(P.end)    #自动执行 @property装饰的end方法
@property

新式类,有三种 @property装饰器,类似于在字典中我们的操作,如:

a = {\'k1\':\'v1\'}
print(a.get(\'k1\'))    #获取值
a[\'k1\'] = \'v2\'        #设置一个值
del a[\'k1\']           #删除一个key
print(a)
class Pager:
    def __init__(self,curr_num,per_page):
        \'\'\'
        构造函数
        :param curr_num:  当前请求的页码
        :param per_page:  每页要显示的数据
        :return:
        \'\'\'
        self.curr_num = curr_num
        self.per_page = per_page

    #计算出开始位
    @property
    def start(self):
        #-1就是找出上一页开始位置
        value = (self.curr_num-1) * self.per_page
        return value


    @start.setter
    def start(self,value):
        # value = self.curr_num * self.per_page
        print(\'你输入的参数是: %s ,这是新修改的值\'%value)
        #return value

    @start.deleter
    def start(self):
        print(\'这里是删除dele动作,你触发了del操作\')

#实例化,传入请求页码和每页显示的数量
P = Pager(1,10)

#起始值
result = P.start     #自动执行 @property装饰的start方法
print(result)

P.start = \'shayashi\' #自动执行 @start.setter装饰的start方法

del P.start          #自动执行 @start.deleter装饰的start方法


#执行结果:
0
你输入的参数是: shayashi ,这是新修改的值
这里是删除dele动作,你触发了del操作
新式类的三种@property

经典类中的属性只有一种访问方式,对应的是被 @property装饰的方法

新式类中的属性有三种, @property, @方法名.setter,  @方法名.deleter 

b. 静态字段方式

创建值为 property对象的字段, 这种方式经典类和新式类无区别。

class Test:
    def __init__(self,name):
        self.name = name

    def show(self):
        return self.name

    xx = property(show) #注意方法这里不能加(),否则报错

obj1 = Test(\'daniel\')
result = obj1.xx   #自动会调用 show方法,并获取返回值

print(result)
View Code

property构造方法的四个参数:

  • 第一个是fget,值是方法名,调用 对象.属性 属性时自动触发执行
  • 第二个是fset,值是方法名,调用 对象.属性=值 的时候自动触发执行
  • 第三个是fdel,值是方法名,调用 del 对象.属性 的时候自动触发执行
  • 第四个参数是doc, 调用 对象.属性.__doc__ 的时候自动打印,这是该属性的描述信息

以上四种方式中的参数都是可选,可以直接写方法名,但是注意的是,直接写方法名的时候,要对应好位置,比如要写del的一个属性,必须要加上前两个。

class Test:
    def __init__(self,name):
        self.name = name

    def show(self):
        return self.name

    def setter(self,value):
        print(\'setter\')

    def deleter(self):
        print(\'deleter\')

    # xx = property(show,setter,deleter,\'这是一段描述信息\') #注意方法这里不能加(),否则报错
    xx = property(fget=show,fdel=deleter)  #如果只定义一个get和del的属性,那么就需要使用fget和fdel显式指定了,用普通方法名已经不能满足需求了
obj1 = Test(\'daniel\')
result = obj1.xx   #自动会调用 show方法,并获取返回值

# obj1.xx = \'xxoo\'   #自动会调用 setter方法,并获取返回值

del obj1.xx        #自动会调用 deleter 方法,并获取返回值
print(result)
View Code

 

二. 类成员修饰符

上面介绍了类的成员,这会来看下类成员的修饰符,顾名思义,作用就是来修饰类成员的。 对于每一个类的成员,都有两种形式:

  • 公有成员,在任何地方都可以访问
  • 私有成员,只允许在类的内部访问

私有成员和共有成员的定义不同,私有成员命名时,前两个字符是下划线(特殊成员除外,如__init__, __call__等)。

class Foo:
    country = \'中国\'   #公有静态字段
    __xx = \'不给你看!\'  #私有静态字段

    def __init__(self,name):
        self.name = name   #共有普通字段
        self.__oo = \'还不让你看!\'  #私有普通字段

私有成员和公有成员的访问限制不同:

1. 字段

静态字段:

  • 共有静态字段:  类可以访问; 类内部可以访问; 子类中可以访问。
  • 私有静态字段:  仅类内部可以访问class Foo:

 

    country = \'中国\'   #公有静态字段
    __xx = \'不给你看!\'  #私有静态字段

    def __init__(self,name):
        self.name = name   #共有普通字段
        self.__oo = \'还不让你看!\'  #私有普通字段

    def test(self):
        print(self.__xx)

    def test1(self):
        print(self.__oo)

#静态字段:
print(Foo.country)    #从类里访问静态公共字段,成功
#Foo.__xx             #访问私有静态字段, 失败
  
obj = Foo(\'dbq\')       #在类里面访问静态字段, 成功
obj.test()

obj.test1()                #在类里面访问普通私有字段,成功

 

class Foo:
    country = \'中国\'   #公有静态字段
    __xx = \'不给你看!\'  #私有静态字段

    def __init__(self):
        self.__oo = \'还不让你看!\'  #私有普通字段

    def test(self):
        print(Foo.__xx)

    def test1(self):
        print(self.__oo)


class Foo1(Foo):

    def test2(self):
        print(Foo.country)     #子类访问父类公共静态字段, 成功
        print(Foo.__xx)        #子类访问父类私有静态字段, 错误


obj1 = Foo1()   
obj1.test2()

普通字段:

  • 公共普通字段: 对象可以访问, 类内部可以访问,子类(派生类) 中可以访问;
  • 私有普通字段: 仅能从类内部访问;
class Foo:
    country = \'中国\'   #公有静态字段
    __xx = \'不给你看!\'  #私有静态字段

    def __init__(self):
        self.__oo = \'私有普通字段,不让你看!\'  #私有普通字段
        self.name = \'DBQ\'

    def test(self):
        print(self.name)

    def test1(self):
        print(self.__oo)


class Foo1(Foo):
    def test2(self):
        print(self.name)


obj1 = Foo()
print(obj1.name)    #通过对象访问, 成功

obj1.test()         #类内部访问, 成功

obj2 = Foo1()
obj2.test2()        #子类中访问,成功

#执行结果:
DBQ
DBQ
DBQ
公共普通字段
class Foo:
    country = \'中国\'   #公有静态字段
    __xx = \'不给你看!\'  #私有静态字段

    def __init__(self):
        self.__oo = \'私有普通字段,不让你看!\'  #私有普通字段
        self.name = \'DBQ\'

    def test(self):
        print(self.__oo)

    def test1(self):
        print(self.__oo)


class Foo1(Foo):
    def test2(self):
        print(self.__oo)


obj1 = Foo()
print(obj1.__oo)    #通过对象访问, 失败

obj1.test()         #类内部访问, 成功

obj2 = Foo1()
obj2.test2()        #子类中访问, 失败
私有普通字段

注意, 如果要强制访问私有字段,可以通过 [ 对象._类名__私有字段名 ] 来访问,但是强烈不建议强制访问私有成员!

class Foo:
    country = \'中国\'   #公有静态字段
    __xx = \'不给你看!\'  #私有静态字段

    def __init__(self):
        self.__oo = \'私有普通字段,不让你看!\'  #私有普通字段
        self.name = \'DBQ\'

    def test(self):
        print(self.__oo)

    def test1(self):
        print(self.__oo)


class Foo1(Foo):
    def test2(self):
        print(self.__oo)


obj1 = Foo()
print(obj1._Foo__oo)    #通过 [对象名._类名__私有字段名] 强制访问成功
#虽说能成功,但是不建议这么访问私有字段!
强制访问私有字段

2. 方法

普通类方法

 

  • 公共普通类方法:对象可以访问, 子类可以访问
  • 私有普通类方法:仅能从类内部访问
class Foo:
    def show(self):
        print(\'这是公共普通方法\')


class Son(Foo):
    def show1(self):
        print(self.show())

obj = Foo()
obj.show()           #对象访问, 成功
# Foo.show()       #类调用,失败
obj_son = Son()
obj_son.show1()   #子类访问, 成功
公共普通方法
class Foo:
    def __show(self):
        print(\'这是私有静态方法\')

    def show2(self):
        self.__show()


class Son(Foo):
    def show1(self):
        print(self.__show())

obj = Foo()
#obj.__show()        #外部对象访问, 失败

obj.show2()          #类内部访问, 成功

#Foo.show2()         #类调用,失败
obj_son = Son()
obj_son.show1()   #子类访问, 失败
私有普通类方法

静态类方法

  • 公共静态类方法:对象可以访问, 类内部可以访问,子类(派生类) 中可以访问;
  • 私有静态类方法:仅能从类内部访问
class Foo:

    @staticmethod
    def show():
        print(\'这是共有静态类方法\')

    def show2(self):
        self.show()


class Son(Foo):
    def show1(self):
        print(self.show())

obj = Foo()
obj.show()          #外部对象访问, 成功

obj.show2()         #类内部访问, 成功

obj_son = Son()
obj_son.show1()     #子类访问, 成功
公共静态类方法
class Foo:

    @staticmethod
    def __show():
        print(\'这是私有静态类方法\')

    def show2(self):
        self.以上是关于Python自动化运维之路Day8基础篇之面向对象下篇的主要内容,如果未能解决你的问题,请参考以下文章

Python之路,day8-Python基础

Python学习之路——Day8(面向对象进阶)

Python_oldboy_自动化运维之路_面向对象2

Python开发运维之路day8

python

Python100天学习笔记Day8 面向对象编程基础