码迷,mamicode.com
首页 > 编程语言 > 详细

Python 面向对象编程

时间:2018-07-08 10:43:35      阅读:254      评论:0      收藏:0      [点我收藏+]

标签:ali   容量   static   cos   报错   method   hid   连接   最大   

面向对象的三大特性:

1.封装

2.继承

3.多态(python中不存在的,而是鸭子类型)

在python中,一切皆对象,对象是某个东西。所以,顾名思义,类当然也是对象,连一个数字、字符串都是对象。

面向对象编程,是一种哲学,编程的哲学、编程的思维。很虚的,只是指导你如何去思考。

面向对象编程,就是将数据与函数绑定到一起,进行封装。

 

一、面向对象

先用现实生活中的一个例子引入:

见过月饼没?(没见过的出门左拐)

要做出一个月饼,首先得要做出月饼的模子,有了这个模子,就可以照着这个模子无限做月饼。

类:就相当于模子。

对象:就是做好的一个个的月饼。(python中,对象是可变的)

 

二、类、实例 

(一).类(模子)

类有它自己的特征(属性)、行为(方法)。

拿“犬类”来理解:

狗的特征(属性):毛色、体重、血统……

狗的行为(方法):吃东西、奔跑、汪汪叫……

特征说白了就是属性,在编程中实则就是变量;行为就是方法,在编程中实则就是函数。

但是,方法和函数是有区别的:与类有着特定关联的函数,才被叫方法。

这里引入一个isinstance()这个内置函数:

技术分享图片
class Dog:
    pass

class Cat:
    pass

d1 = Dog()  # 实例化一个类。加括号,就像调用函数一样
d2 = Dog()

c1 = Cat()

print(d1 is d2)  # False。看清楚了,这里是 is,身份运算符,判断id是不是一样的。d1、d2是两个不同的实例,当然ID不一样了
print(isinstance(d1, Dog))  # True
print(isinstance(c1, Cat))  # True
print(isinstance(c1, Dog))  # False
print(isinstance(c1, (Dog, Cat)))  # True,判断实例是不是属于某一个类,一个为真即为真
View Code

(二).实例

模子创建出来的一个具体的东西。月饼就是由模子做出来的,月饼就是个具体的东西。

每一个实例之间互不相干,可以实例化无限个(只要内存够用)。

class Cat:
    pass

c1 = Cat()  # 一定要加括号,就像调用函数一样

(三).举例理解

老虎、狮子、猎豹,都是猫科动物这一类的。是真实存在的,是猫科动物的具体实例的对象。

而类,则是猫科动物的模版,因为不存在一个叫猫科动物的动物。

三、属性封装

技术分享图片
class Cat:
    var1 = "一只猫"

print(Cat.var1)  # 一只猫。直接通过 "类名.变量名" 来访问

Cat.var2 = "两只猫"  # 只有python可以这么做
print(Cat.var2)  # 两只猫

c1 = Cat()  # 把Cat类实力化
print(c1.var1)  # 一只猫
print(c1.var2)  # 两只猫
View Code

查找变量,首先会去实例中找,没找到再去类中找。

(一)."属性操作"内置函数

getattr()/hasattr()/setattr()/delattr() 其实针对的是变量空间

这四个方法可以在程序运行时决定操作的属性。代码运行之后,决定赋什么属性、什么值。(不是写代码时就写死了,而是运行时可以决定)

此外,hasattr()还可以避免因为属性没有而导致报错。

(二).常用的特殊属性

(1).__name__

以后web开发中,写"路由"的时候会用到__name__,url配置。

路径、网络、函数的名字,一一对应。

返回的是一个字符串。是对象本身的名字,类是类的名字,函数是函数的名字。

技术分享图片
class A:
    pass


def bb():
    pass


print(A.__name__)  # A
print(type(A.__name__))  # <class ‘str‘>
print(bb.__name__)  # bb
print(type(bb.__name__))  # <class ‘str‘>
View Code

(2).__class__

只要有实例,就能得到类。不是类的名称,是类自己本身的对象,而不是名字。

相当于再得到一个类对象。

class A:
    pass


a = A()
b = a.__class__
print(b)  # <class ‘__main__.A‘>

(3).__doc__

写代码要有写注释的习惯,不然过了1个星期,你自己都不知道你写的是啥东西了。

技术分享图片
def jiec(n):
    """
    这是一个计算阶乘的递归函数
    :param n: 对哪个数进行阶乘
    :return: 阶乘的结果
    """
    if n == 1:  # 出口
        return 1
    else:
        return jiec(n - 1) * n  # 自己调用自己


print(jiec.__doc__)
"""
    这是一个计算阶乘的递归函数
    :param n: 对哪个数进行阶乘
    :return: 阶乘的结果
"""

print(help(jiec))
"""
Help on function jiec in module __main__:

jiec(n)
    这是一个计算阶乘的递归函数
    :param n: 对哪个数进行阶乘
    :return: 阶乘的结果

None
"""
View Code

可以把这个多行注释看作是"文档注释",每个类、方法只能有一个。

多行注释是存放在__doc__中,返回的是文档字符串,把多行注释返回了。

(4).__dict__

查看实例中封装的属性。类中的属性返回的是一个一大串底层的字典格式的对象。

 

四、self

在编写类的代码时,它是常客。

self它是一个关键字参数,首要参数(这里就记住:必须加),它是标记给哪个类,给每一个实例贴上标签。指的是对象本身。

如果不加这个self,那么有很多实例的时候,python解释器就分不清是哪一个实例了。python底层是用self来区分每一个实例。

调用时不需要写self这个参数,python底层已自动为我们实现了,python解释器会自动传递。

(一).引入魔法方法:__init__()

先解释一下什么叫魔法方法?被双下划线包裹起来的方法。在特定的情况被触发。就像陷阱,先布置好,一旦有踩到了就触发了这个陷阱。

阅读如下代码,例1:

技术分享图片
class Account:
    def __init__(self, name, number, money):
        self.name = name
        self.number = number
        self.money = money

a = Account("Tuple", "123456", 8888)  # 实例化
View Code

__init__() 初始化的作用,实例化时自动调用(无需手动),初始化属性。用于对象一被创建时,就需要拥有属性的场合,让对象有一些指定的属性。

例如,一个人一出生就拥有血型、指纹……

"例1"中 self.name=name 这条在__init__()中的代码,就是让对象有了这个属性。self指对象本身。

注意:当 __init__() 的括号中有必备参数时,在实例化时,就必须传参数。

看着上述"例1"的代码,理解下图:(在编写类的代码时,如果不写self,那么实例化的时候,python根本就不知道是哪一个类传过去的)

技术分享图片

(二).其他魔法方法

(1).__del__() 释放类时被调用。

python底层有自己的垃圾回收机制。不过当人为 del object 手动删除时,就触发了__del__()。

这里引入一个例子,此例向我们展示了python被称为高级语言的特性之一:"垃圾回收机制",

技术分享图片
class A:
    def __del__(self):
        print("被销毁了")


def func():
    a = A()  # a是在函数调用的时候实例化的
    # 当函数调用结束的时候,里面的对象被销毁


func()  # 调用完了都会被销毁
# 不销毁的话,当很多次调用的时候。a实例在内存中越来越多,最后导致内存溢出,你的电脑瘫痪

"""
运行结果:

被销毁了

为啥?又没去删除过对象,为什么被销毁了?看代码的注释去!
"""
View Code

(2).__str__() 向使用者提供尽可能简洁且有用的信息。针对使用者。print()的时候,就是触发了这个魔法方法。

(3).__repr__() 作用与__str__()很相似。只是这个魔法方法针对开发者,有时用来找BUG的

(4).str没有的时候,会去找repr

 

五、基础OOP的案例

(一).烤红薯

技术分享图片
"""
小应用:烤红薯
属性:
    cookedlevel int :
    0-3 表示生的;超过3 表示半生不熟;超过5 表示已经烤好了;超过8 表示烤焦了
    cookedstring string :
    描述红薯的生熟程度
    coodiment : 调料
行为:
    cook() 把红薯烤一段时间
    addcondiments() 给红薯添加配料
用到的魔法方法:
__init__ 设置默认属性
__str__ 让print的结果更加好看
"""


class SweetPotato:
    """这是烤红薯的类"""

    # 定义初始化方法
    def __init__(self):
        self.cooklevel = 0
        self.cook_string = "生的"
        self.condiments = []

    # 定制print时显示的内容
    def __str__(self):
        msg = self.cook_string + "红薯"
        if len(self.condiments) > 0:
            msg = msg + "("
            for i in self.condiments:
                msg = msg + i + ","
            msg = msg.strip(",")  # 去掉左右两边的逗号
            msg = msg + ")"
        return msg

    # 烤红薯方法
    def cook(self, time):
        self.cooklevel += time
        if self.cooklevel > 8:
            self.cook_string = "烤成灰了"
        elif self.cooklevel > 5:
            self.cook_string = "烤熟了"
        elif self.cooklevel > 3:
            self.cook_string = "半生不熟"
        else:
            self.cook_string = "生的"

    # 加调味品
    def add_condiments(self, condiment):
        self.condiments.append(condiment)


sp = SweetPotato()  # 实例
print("有一个红薯还没有烤。", "level:", sp.cooklevel, sp.cook_string, "。调料:", sp.condiments)
print("接下来开始烤红薯了")
print("已经烤了4分钟")
sp.cook(4)
print(sp)
print("我又烤了3分钟")
sp.cook(3)
print(sp)

print("开始放调料了,我放了芥末")
sp.add_condiments("芥末")
print(sp)
print("我口味比较重,我想放点老干妈")
sp.add_condiments("老干妈")
print(sp)

print("我又烤了5分钟")
sp.cook(5)
print(sp)

print("烤成灰了也要吃,加杯脉动")
sp.add_condiments("脉动")
print(sp)

"""
运行结果:

有一个红薯还没有烤。 level: 0 生的 。调料: []
接下来开始烤红薯了
已经烤了4分钟
半生不熟红薯
我又烤了3分钟
烤熟了红薯
开始放调料了,我放了芥末
烤熟了红薯(芥末)
我口味比较重,我想放点老干妈
烤熟了红薯(芥末,老干妈)
我又烤了5分钟
烤成灰了红薯(芥末,老干妈)
烤成灰了也要吃,加杯脉动
烤成灰了红薯(芥末,老干妈,脉动)
"""
View Code

(二).房间里摆放家具

技术分享图片
"""
你有一个房间,往房间里摆放家具。
用OOP思想编写代码!
"""


class Room:
    def __init__(self, area):
        self.area = area  # 房间的总面积
        self.light = "on"  # 默认让房间的灯是亮着的
        self.contains_item = []  # 家具列表

    def __str__(self):
        msg = "当前房间可用面积为:{},".format(str(self.area))
        if len(self.contains_item) > 0:
            # 房间里有家具
            msg = "{}容纳的物品有:{}".format(msg, "".join([i.get_name() for i in self.contains_item]))
            # 预设方法 : get_name() 获取家具的名称
            # self.contains_item中,放的是Bed类的实例,所以可以直接 ".函数名()" 来操作
            # print(self.contains_item)  # [<__main__.Bed object at 0x003E8430>,...]
        return msg

    def accommodate_item(self, item):
        # 往房间中添加家具
        need_area = item.get_used_area()  # 预设函数 : 已使用多少面积
        if self.area > need_area:
            # 总面积大于家具的面积,可以往房间里添家具
            self.contains_item.append(item)
            self.area -= need_area  # 家具放进房间了,房间总面被占用了,相应减少可以使用的面积
            print("\"{}\"已放进房间里了".format(item.get_name()))
        else:
            print("房间面积不够了,塞不进去了!")


class Bed:
    """这里以 "床" 为例"""

    def __init__(self, area, name="床1"):
        self.area = area  # 床有面积
        self.name = name  # 床有品牌

    def __str__(self):
        return "床的面积为:{}".format(str(self.area))

    def get_used_area(self):
        return self.area

    def get_name(self):
        return self.name


room = Room(20)
print(room)
b1 = Bed(3)
print(b1)

room.accommodate_item(b1)  # 往房间里添床了
# 传过去的是Bed类的实例
print(room)

print()  # 为了看得清楚

b2 = Bed(5, "席梦思")
print(b2)
room.accommodate_item(b2)  # 再添一张床
print(room)

"""
运行结果:

当前房间可用面积为:20,
床的面积为:3
"床1"已放进房间里了
当前房间可用面积为:17,容纳的物品有:床1

床的面积为:5
"席梦思"已放进房间里了
当前房间可用面积为:12,容纳的物品有:床1、席梦思
"""
View Code

(三).文字版CS

技术分享图片
"""
文字版 CS

1. 人类
属性 : 姓名  血量  持有的枪
方法 : 安子弹  安弹夹  拿枪(持有抢)  开枪

2. 子弹类
属性 : 杀伤力
方法 : 伤害敌人(让敌人掉血)

3. 弹夹类
属性 : 容量(子弹存储的最大值)  当前保存的子弹
方法 : 保存子弹(安装子弹的时候)  弹出子弹(开枪的时候)

4. 枪类
属性 : 弹夹(默认没有弹夹,需要安装)
方法 : 连接弹夹(保存弹夹)  射子弹
"""


# 人类
class Ren:
    # 初始化方法
    def __init__(self, name):
        self.name = name
        self.xue = 100
        self.qiang = None

    # 魔术方法
    def __str__(self):
        return self.name + "剩余血量为:" + str(self.xue)

    def anzidan(self, danjia, zidan):
        danjia.baocunzidan(zidan)

    def andanjia(self, qiang, danjia):
        qiang.lianjiedanjia(danjia)

    def naqiang(self, qiang):
        self.qiang = qiang

    def kaiqiang(self, diren):
        self.qiang.she(diren)

    def diaoxue(self, shashangli):
        self.xue -= shashangli


# 弹夹类
class Danjia:
    def __init__(self, rongliang):
        self.rongliang = rongliang
        self.rongnaList = []

    def __str__(self):
        return "弹夹当前的子弹数量为:" + str(len(self.rongnaList)) + "/" + str(self.rongliang)

    def baocunzidan(self, zidan):
        if len(self.rongnaList) < self.rongliang:
            self.rongnaList.append(zidan)

    def chuzidan(self):
        # 判断当前弹夹中是否还有子弹
        if len(self.rongnaList) > 0:
            # 获取最后压入到单夹中的子弹
            zidan = self.rongnaList[-1]
            # 每一次调用都会用掉一发子弹,所以要删除列表中的最后一个元素
            self.rongnaList.pop()
            return zidan
        else:
            return None


# 子弹类
class Zidan:
    def __init__(self, shashangli):
        self.shashangli = shashangli

    def shanghai(self, diren):
        diren.diaoxue(self.shashangli)


# 枪类
class Qiang:
    def __init__(self):
        self.danjia = None

    def __str__(self):
        if self.danjia:
            return "M4A1当前有弹夹"
        else:
            return "M4A1当前没有弹夹"

    def lianjiedanjia(self, danjia):
        if not self.danjia:
            self.danjia = danjia

    def she(self, diren):
        zidan = self.danjia.chuzidan()
        if zidan:
            zidan.shanghai(diren)
        else:
            print("没有子弹了,需要更换弹夹")


police = Ren("德国边防第九大队")
danjia = Danjia(20)
print(danjia)
i = 0
while i < 20:
    zidan = Zidan(20)
    police.anzidan(danjia, zidan)
    i += 1
print(danjia)
qiang = Qiang()
print(qiang)
police.andanjia(qiang, danjia)
print(qiang)
diren = Ren("凤凰战士")
print(diren)
police.naqiang(qiang)
police.kaiqiang(diren)
print(diren)
print(danjia)
police.kaiqiang(diren)
print(diren)
print(danjia)

"""
运行结果:

弹夹当前的子弹数量为:0/20
弹夹当前的子弹数量为:20/20
M4A1当前没有弹夹
M4A1当前有弹夹
凤凰战士剩余血量为:100
凤凰战士剩余血量为:80
弹夹当前的子弹数量为:19/20
凤凰战士剩余血量为:60
弹夹当前的子弹数量为:18/20
"""
View Code

六、继承

就是相同的类,取他们的共性。(也可以说是派生)。抽象出一个更抽象的类,放公共代码。

(一).设计思想:

单继承:从上往下,传统分类思想。

技术分享图片

基于多继承的Mix-in的思路:拼积木,组装。就像拼四驱车,由马达、轴承等等组成一辆完整的四驱车。(代码量一多,拼积木容易把自己绕晕)。一般,Mix-in类是继承的终点。

(二).继承搜索的顺序

先找子类 -> 再找父类 -> 最后找object

注意:不是父类空间的复制。

寻找多继承的轨迹的方式:__mro__ 属性。

(三).super()

用途:当子类需要重写父类时,但还需要用到父类。super()必须加上。

父类中所有的一切,子类都可以直接拿来用。如果父类无法满足子类的需求,在不改变父类作用的前提下,在子类中重写父类方法时,super()得要加上。

因为重写了子类,父类中的属性、方法就会被覆盖了,不会再去找父类中的属性、方法了。所以需要super()手动去找一下。

super()了,后面的__init__()中,self也不用了。

python解释器会自动去找它的父类。super()是通过mro查找的。

父类中有多少参数,super().__init__()也得有同样参数。

super().__init__()拿来的是父类的属性,父类中有哪些属性,都必须要统统写进来。而子类自有的属性就在init中定义。然后传参的时候,就按子类定义的参数传实参就可以了。

(四).练习:

定义一个猫咪的父类,再从父类中分出不同种类的猫

技术分享图片
"""
定义一个猫咪的父类,
再从父类中分出不同种类的猫
"""


class Cat:
    """猫咪的父类"""

    def __init__(self, color="", weight=10, age=1):
        self.color = color  # 颜色
        self.weight = weight  # 体重
        self.age = age  # 年龄

    def __str__(self):
        return "{},体重:{},年龄:{}岁".format(
            self.color, str(self.weight), str(self.age))


class GarfieldCat(Cat):
    """加菲猫"""

    def __init__(self, color, weight, age, hungry):
        super().__init__(color, weight, age)
        self.hungry = hungry

        if self.hungry:
            self.hungry = "我是吃货"
        else:
            self.hungry = "我才不是吃货"

    def speak(self):
        print("我是加菲猫,我会说话!")

    def __str__(self):
        return "{},体重:{},年龄:{}岁,{}".format(
            self.color, str(self.weight), str(self.age), self.hungry)


class TomCat(Cat):
    """TomCat"""

    def iam_cute(self):
        print("我是汤姆猫,我会卖萌")


garfield = GarfieldCat("棕色", 30, 10, True)
print(garfield)
garfield.speak()

print()  # 换行,为了看得清楚

t = TomCat("黑色", 20, 1)
print(t)
t.iam_cute()

"""
运行结果:

棕色,体重:30,年龄:10岁,我是吃货
我是加菲猫,我会说话!

黑色,体重:20,年龄:1岁
我是汤姆猫,我会卖萌
"""
View Code

(五).补充:python不具备多态,python是假多态。(python中是鸭子类型)

鸭子类型:如果走起路来像鸭子,或者叫起来像鸭子,那就是鸭子!比如那天我学嬴政穿着龙袍,那么认为我就是皇帝。

(六).广度优先遍历、深度优先遍历。广度:类似就近原则。深度:一条路找到底。类名.mro()就可以看到寻找的轨迹,既不是广度也不是深度,而是C3算法推导出来的。

技术分享图片

广度的寻找轨迹:找BC,再去B里面的DE,最后是object

深度的寻找轨迹:B -> D -> E -> C

补充一个案例:(由于冲突导致的不能继承)

技术分享图片
"""
用个生动形象的比喻
"""


class A:  # 爸爸
    pass


class B:  # 妈妈
    pass


class C(A, B):  # 儿子。先继承了爸爸的小JJ
    pass


class D(B, A):  # 女儿。先继承了妈妈的...
    pass


# 一旦运行下面代码就会报错
class E(C, D):  # 儿子和女儿能结婚吗?
    pass
"""
Traceback (most recent call last):
  File "D:/python_local/test1.py", line 21, in <module>
    class E(C, D):
TypeError: Cannot create a consistent method resolution
order (MRO) for bases A, B
"""


"""
C先继承了A 然后B,
D先继承了B 然后A,
那么E的寻找轨迹就发生了冲突,到底先找A还是先去找B?然后就报错了。
C3算法找不到继承轨迹了。
"""
View Code

七、装饰器

装饰器(名词):装饰某个东西。给一个现有的函数增加功能,可以反复使用,你装饰什么函数,那个函数就增加功能。

装饰(动词):指向了一个新的函数,除了调用原来的函数外,还会做点别的事。函数名还是原来的函数名,指向的却是新的函数,这个新的函数,会调用原来的函数,也可以做些别的事。

一个装饰器就是一个函数,它接受一个函数作为参数并返回一个新的函数。

(一).使用装饰器的场景

(1).提供一个验证功能的时候

(2).统计函数执行时间

(3).日志模块,自动打印日志

(4).执行函数前的预备处理

(5).函数执行后的一些清理功能

(二).开放封闭原则

写代码要遵循 "开放封闭" 的原则。简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展。

封闭:已实现的功能代码。

开放:对扩展开放。

(三).装饰器练习

一个简单的装饰器,"例1":

技术分享图片
def i_label(fn):
    def add_i():
        return "<i>{}</i>".format(fn())

    return add_i


def b_label(fn):
    def add_b():
        return "<b>{}</b>".format(fn())

    return add_b


@i_label
def sentence1():
    return "第一句话"
    # print("第一句话") <i>None</i>  # print()返回的是None


@b_label
def sentence2():
    return "第二句话"


@i_label
@b_label
def sentence3():
    return "第三句话"


print(sentence1())
print(sentence2())

print(sentence3())
"""
先会去执行b_label,执行完后,返回出一个新的函数,这个新函数包含了刚才代码执行后的结果。
然后再去执行i_label,i_label调用执行的是刚才生成的新函数了,新函数中有b_label执行后的结果,才能拼接在一起。然后返回。
"""

"""
运行结果:
<i>第一句话</i>
<b>第二句话</b>
<i><b>第三句话</b></i>
"""
View Code

带参数的装饰器,"例2":

技术分享图片
"""
满足500元的商品可以打9折。
"""


def discount(price):
    def exchange(x):  # x是original_price
        if price(x) >= 500:  # price()是调用entirely()
            return price(x) * 0.9
        else:
            return price(x)

    return exchange


@discount
def entirely(original_price):
    return original_price


print("合计:{}".format(entirely(600)))  # 合计:540.0
View Code

大装饰器,"例3":

技术分享图片
import time
from functools import wraps

"""
装饰器从里到外起作用的
"""


def what_you_want(command):
    if command == "get_sum":
        def get_sum(func):
            @wraps(func)
            def sum_inner(*args, **kwargs):
                values = func(*args, **kwargs)
                print("打印两数之和:{}".format(sum(values)))
                return values

            return sum_inner

        return get_sum
    elif command == "get_cost_time":
        def get_cost_time(func):
            @wraps(func)
            def time_inner(*args, **kwargs):
                start_time = time.time()
                time.sleep(0.5)
                values = func(*args, **kwargs)
                end_time = time.time()
                print("耗时{}秒".format(str(end_time - start_time)))
                return values  # 如果没有返回,get_sum这个装饰器中就会报错

            return time_inner

        return get_cost_time


"""
所有的装饰器装饰好了再运行。
此案例中,其中一个装饰器需要依赖那个values。
如果装饰完后没有得到values的返回值,就会报错。
"""


@what_you_want("get_sum")  # 如果没有得到values,这条语句必须写再下面语句的后面
@what_you_want("get_cost_time")
def my_func(a, b):
    return a, b


my_func(10, 20)

"""
运行结果:

耗时0.5000286102294922秒
打印两数之和:30
"""
View Code

由"例3"中可看出:装饰器可以叠加使用,若多个装饰器同时装饰一个函数,那么装饰器的调用顺序和语法糖的声明顺序相反。

 

八、描述器

一个类中,只要有 __get__() 、 __set__() 、__delete__() 这三个魔法方法中的其中一个,那么就是描述器。

描述器管理一个"类属性"的访问、修改、删除。(上面已有写了)

基于描述器的装饰器,可以让一个方法,用起来像一个属性。

技术分享图片
class Property:
    """这是一个装饰器,也是一个描述器"""

    def __init__(self, func=None):
        self.func = func

    def __get__(self, obj, objtype=None):
        if obj is None: return self  # 直接通过类来访问时
        if self.func is None: raise AttributeError("unreadable attribute")
        return self.func(obj)


class MyName:
    """想要隐藏自己的昵称,用匿名来代替。如匿名评论"""

    def __init__(self, name):
        self.name = name
        self.isanonymous = False  # 是否是匿名的

    @Property  # 可以让一个方法,用起来像属性
    def show_name(self):
        if self.isanonymous:  # 如果是匿名的
            return "匿名的"
        else:
            return self.name  # 不是匿名直接返回明文


my = MyName("zyb")
my.isanonymous = True
print(my.show_name)

"""
运行结果:

匿名的
"""
View Code

九、内置装饰器

(一).@property装饰器

就是把一个方法,变成属性。就是调用的时候不用加小括号了。

class A:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    @property
    def foo(self):
        print(self.name)
        return "property foo"


p = A("jack", 88)
print(p.foo)  # 直接就是属性的形式了

(二).静态方法:@staticmethod,两个看起来都像普通函数。不需要self参数了。

技术分享图片
class A:
    @staticmethod  # 静态方法了
    def meth():
        print("aaa")
        
    # def meth(self):
    #     print("aaa")


A.meth()  # 直接用类,就相当于看成普通函数

a = A()
a.meth()  # 实例调用的时候 --> A.meth(a)

"""
如果我希望:实例调用和类调用都一样,都看成普通函数,怎么办?@staticmethod
静态方法:会让类和实例,看它都是一个普通函数
"""

"""
运行结果:

aaa
aaa
"""
View Code

(三).类方法:@classmethod,不传实例,只传类。

技术分享图片
class A:
    @classmethod
    def meth(cls):  # 第一个参数是cls 表示类
        print("aaa")


A.meth()  # 直接用类,就相当于看成普通函数

a = A()
a.meth()  # 实例调用的时候 --> A.meth(A) #类当作第一个参数传进去

"""
类方法:第一个传进去的不是实例,而是类。

大概场景:
以后做数据库接入的时候,有一个ORM,基于面向对象的。
在查询的时候,可以使用类方法,来简化你的代码。
"""
View Code

(四).区别

(1).@staticmethod 不需要表示自身对象的self参数和自身类的cls参数,就跟使用普通的函数一样。但不加这个装饰器就不可以了!

(2).@classmethod 不需要self参数,但是第一个cls参数需要表示自身类的cls参数。

(3).@classmethod的话,在类里的所有方法都可以调用的。

Python 面向对象编程

标签:ali   容量   static   cos   报错   method   hid   连接   最大   

原文地址:https://www.cnblogs.com/xuanlv-0413/p/9279044.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!