周记录(第四周)

面向对象编程的基本实现

通过class关键字来定义一个类:

eg. 定义一个汽车的类

class Cart():

pass

ps: (1)类名的书写规范,建议使用驼峰命名法:

大驼峰:MyCar XiaoMi

小驼峰:myCar xiaoMi

(2)类中需要声明什么内容:

一个类有特征和功能两个内容组成:

特征就是一个描述:颜色:白色,品牌:奥迪,排量:2.4。

功能就是一个能力:拉货,兜风。

特征在编程中就是一个变量,在类中称为:属性。

功能在编程中就是一个函数,在类中称为:方法。

类中属性一般定义在前面,方法定义在后面。

# 定义一个汽车的类

class Cart():

#属性 ==> 特征 ==> 变量

   
color = '白色' # 表示颜色属性
brand = '奥迪' # 表示品牌属性  
pailiang = 2.4 # 表示排列属性
 

#方法 ==> 功能 ==> 函数
   
def luohuo(self):

	print('小汽车能拉货')

   
def doufeng(self):

       	print('小汽车能兜风')

 	   
def kuaile(self):

       	print('能快乐玩耍')

 

**********************************

如何通过类实例化对象并使用?


aodiobj = Cart()

 # print(aodiobj,type(aodiobj))
# <__main__.Cart object at0x106f08550> <class '__main__.Cart'>


# 调用对象的方法

aodiobj.bamei()



# 获取对象的属性

print(aodiobj.brand)

成员属性和成员方法的操作

对象操作成员

1.对象的成员:一个对象通过类实例化之后,那么在类中定义的属性和方法,可以使用实例化的对象进行操作。类中定义的属性也称为成员属性,类中定义的方法,也成为成员方法。

成员属性:

  访问:  对象.成员属性名

  修改:  对象.成员属性名法 = 新值。(此时等于给这个对象创建了一个自己的属性)

  添加:  对象.新成员属性 = 值 (此时是给这个对象自己新建了一个属性)

  删除:  del 对象.成员属性 (注意:只能删除这个对象自己的属性)

  

成员方法:

  访问:  对象.成员方法名()

  修改:  对象.成员方法名 = func(此时等于给这个对象创建了一个自己的方法)

  添加:  对象.方法名 = func (此时是给这个对象自己新建了一个方法)

  删除:  del 对象.方法名 (注意:只能删除这个对象自己的方法)

2.对象的成员的操作

在类的外部,使用对象操作成员属性
(1)访问成员属性:先访问a对象自己的color属性,没有,就去访问这个对象的类的属性res = a.color  # 通过对象访问类中的属性 
(2)修改对象的属性值: 实际上等于给这个对象创建了一个a对象自己的color属性。a.color = '黑色'  # 修改对象的属性print(b.color) # b对象的属性依然原来的值 
(3)添加对象的属性: 给当前a对象创建了自己独有的属性a.name = 'A6'  # 给对象添加属性 此时的name属性只属于当前a这个对象。 print(b.name)  # AttributeError: 'Cart' object has no attribute 'name' 。
(4)删除属性,只能删除这个对象自己的属性,包括给对象添加的和修改的
	# del a.brand  # AttributeError: brand
	del a.color 
	brand属性不能删除,但是name属性可以删除:因为删除一个对象的属性时,只能删除当前这个对象自己的属性才可以,上面例子中的brand属性并不是a对象自己的属性,而是属性Cart这个类,因此不能删除。而name这个属性,是单独给a对象添加的属性,因为可以删除。 

3.在类的外部,操作对象的方法:

访问对象的方法:实际上如果这个对象没有自己独立的方法,那么会访问这个对象的类的方法。
res = a.lahuo() # 通过对象访问类中方法 
修改对象的方法:给这个对象的方法重新定义
def func():    
	print('这是一个新的方法') 
a.lahuo = func  # 把一个函数赋值给成员
a.lahuo()    # 去调用方法 
添加新的方法:给这个对象自己新创建的方法
a.func2 = func
a.func2() 
删除方法:可以删除当前这个对象自己的方法
del a.lahuo  # 可以删除del a.func2  # 可以删除
del a.bamei # 不可以删除这个对象的类的方法 

总结:

一个类可以实例化出多个对象,每个对象在内存中都独立存在的。

当通过类实例化对象时,并不会把类中的成员复制一份给对象,而去给对象了一个引用。

访问对象成员的时候,如果对象自己没有这个成员,对象会向实例化它的类去查找。

对象成员的添加和修改,都只会影响当前对象自己,不会影响类和其它对象。

删除对象的成员时,必须是该对象自己具备的成员才可以,不能删除类中引用的成员。

对类的成员操作,会影响通过这个类创建的对象,包括之前创建的。

1.成员方法 self

# 定义人类

class Person():

#成员属性

	name = '名字'
	
	age = '年龄'
	   
	sex = '性别'
	
	 
		
 #成员方法

 def s**ing(self):

   print('会唱。。。')



def dance(self):

   print('会跳。。。')



def rap(self):

   print(f'我是{self.name}我会rap。。。')



def func(self):

   
    测试,在类的内部是否可以像类的外部一样,去访问和操作成员

       
    print(self)

       
    print(self.name)  # 访问对象的属性

       
    self.name = '张三三' # 修改对象的属性

       
    self.sanwei = '80 80 80' #添加对象的属性

       
    print(self.sanwei)

       
    self.rap()  # 调用对象的方法

   
# 只要是对象能干的事,self都可以代表对象去完成


#定义不含self的方法  绑定类方法 (不接受对象参数的方法,只能使用类去访问)

def func2():

   print('我是一个没有self的方法')

# 实例化对象

zs = Person()

# zs.name = '张三'

# 通过类实例化的对象,可以在类的外部去访问成员属性和成员方法  对象.成员

# print(zs)

# zs.func()

# zs.rap()

self 在类的方法中代表当前这个对象。

self 代表调用这个方法的对象,谁调用了这个方法,self就代表谁。

self 就可以在类的内部代替对象进行各种操作。

如果在类中定义的方法不含self这个形参时,(self形参,包括其它的代替都不可以)那么这个方法就不能使用对象去调用,不含self形参的方法,只能使用类去调用,这种不接受对象作为形参的方法,叫做绑定类方法。

zs.func2()

Person.func2()

2.魔术方法

初始化方法

魔术方法:

魔术方法也和普通方法一样都是类中定义的成员方法。

魔术方法不需要去手动调用的,魔术方法会在某种情况下,自动触发。(自动执行)

魔术方法还有一个比较特殊的地方:就是多数的魔术方法 前后都有两个连续的下划线。

魔术方法不是我们自己定义的,而是系统定义好的,我们来使用。

init 初始化方法:

触发机制:在通过类实例化对象后,自动触发的一个方法

作用:  可以在对象实例化后完成对象的初始化(属性的赋值,方法的调用。。)

应用场景: 文件的打开,数据的获取,干活前的一些准备功能


class Person():

#成员属性

name = None

age = None

sex = None


#__init__ 初始化方法

def __init__(self,n,a,s):

    print('我是一个初始化方法')

       
# 完成对象属性的初始化

       
self.name = n

       
self.age = a

       
self.sex = s

       
# 调用方法

self.say()


# 成员方法

def say(self):	
       
print(f'大噶好,唔系{self.name},系兄弟就来砍我。。')


# 实例化对象

# zzh = Person()

zzh = Person('渣渣灰',56,'男')
 	
# print(zzh.name)

# 3.析构方法 del

__del __析构方法

触发机制:析构方法会在对象被销毁时自动触发。

作用:关闭一些开发的资源。

注意:是对象被销毁时触发了析构方法,而不是析构方法销毁了对象。

对象会在哪些情况下被销毁?

1. 当程序执行完毕,内存中所有的资源都会被销毁释放。

2. 使用 del 删除时。

3。.对象没有被引用时,会自动销毁。

定义一个类,完成一个日志的记录

调用这个对象的时候,传递一个日志信息

这个对象会创建一个文件,开始写入,并在最后关闭这个文件

import time

class writeLog():

#成员属性

#文件的路径


fileurl = './'

#日志文件的名称


filename = '2019-09-19'



#初识化  打开文件

def __init__(self):

   #完成文件的打开

   print('初始化方法触发类。完成文件的打开')

   self.fileobj = open(self.fileurl+self.filename,'a+',encoding='utf-8')



#写日志的方法

def log(self,s):

   print(f'把日志:{s} 写入文件中')



#析构方法

def __del__(self):

   print('析构方法触发了,关闭打开的文件')

   # 在对象被销毁时,关闭在初始化方法中打开的文件对象

   self.fileobj.close()

实例化对象

l = writeLog()

l.log('今天天气还不错哦。。')
	 

# 使用del手动删除

del l

 	
# 当对象没有被引用时

writeLog()

4.日志类的封装

日志类

class  Mylog

功能:能够随时写入一个日志信息

分析:

日志文件在什么地方? 默认在当前目录

日志的文件名是什么? 当前日期 2019-09-20.log

日志的格式是什么样的? 2019-09-20 12:12:12 错误信息



属性:成员属性的作用就是存储信息,供成员方法来使用的。

fileurl 日志文件的地址

filename 日志文件的名称
       
fileobj 打开的文件对象



方法:具体完成的一个功能的过程。

   
__init__()  ==> 初始化方法,完成对象的初始化,并打开文件

       
log()      ==> 负责接受用给的日志信息,并写入到日志文件中

       
__del__()   ==> 析构方法,在对象被销毁时,关闭打开的文件

 

import time

class Mylog():

    #属性

	fileurl = './'
	
	filename = str(time.strftime('%Y-%m-%d'))+'.log'

	fileobj = None

    #方法

def __init__(self):

   
# 打开文件

   
self.fileobj = open(self.fileurl+self.filename,'a+',encoding='utf-8')

def log(self,s):

   
	# 准备数据,开始写入
	
	       
	# 2019-09-20 12:12:12 错误信息
	
	       
	date = time.strftime('%Y-%m-%d %H:%M:%S')
	
	       
	msg = date+' '+s+'\n'
	
	       
# 写入
  
self.fileobj.write(msg)


def __del__(self):

	# 关闭打开的文件
	self.fileobj.close()
	# 实例化对象
	w = Mylog()
	# 调用方法:写日志
	w.log('今天天气不太好')
	w.log('于是心情不太好')

面向对象的三大特性:封装,继承,多态

1.封装

封装就是使用特殊的语法,对成员属性和成员方法进行包装,达到保护和隐藏的目的。
但是一定注意,不能把成员全部封装死,就失去意义了。
被封装的成员主要是供类的内部使用。
被特殊语法封装的成员,会有不同的访问的权限。

封装的级别

    成员   ==> 公有的
    _成员  ==> 受保护的 (约定俗成,而python没有具体实现)
    __成员 ==> 私有的
          公有的 public    受保护的 protected     私有的 private
在类的内部      OK              OK                 OK
在类的外部      OK              No(python可以)      No

在python中给成员进行私有化,其实就是改了成员的名字
私有化 ==> _类名__成员


class Person():
    # 成员属性
    name = '名字'
    _age = '年龄'  # 在成员前面 加一个 _ 受保护的成员
    __sanwei = '三维'# 在成员前面 加两个 __ 私有的成员

    # 初始化方法
def __init__(self,n,a,s):
    self.name = n
    self._age = a
    self.__sanwei = s

def func(self):
    # 在类的内部可以操作任意成员
    print(self.__sanwei)
    self.__kiss()

# 成员方法
def say(self):
    print('聊聊人生和理想。。。')

def _sing(self):
    print('高歌一曲,豪放一生。。。')

def __kiss(self):
    print('打个kiss 。。。。')


#实例化对象
ym = Person('杨幂',28,'60 55 60')

# print(ym._age)   # 在类的外部不能操作 受保护的成员 (但是Python中可以)
# print(ym.__sanwei)# 在类的外部不能操作  私有成员属性

# print(ym._Person__sanwei) # 可以使用特殊的语法获取私有成员

# ym._sing()    # ok
# ym.__kiss() # X  在类的外部不能操作  私有成员属性

# ym.func()

# 查看对象的所以成员
print(ym.__dict__)  # 可以获取当前对象的所有成员信息
# print(Person.__dict__) # 可以获取当前类的所有成员信息

2. 继承

当子类继承父类后,就可以去使用父类中的成员属性和方法 。(除了私有成员)
子类可以有自己独立的成员,也可以没有。
子类继承父类后,重新定义了父类中的方法,这种情况称为对父类方法的重写。
在子类中可以去直接调用父类中定义的方法 super().父类方法名()。
子类继承父类后,定义类父类中没有的方法,这种情况称为对父类的扩展。
一个父类可以被多个子类继承。
子类调用父类的方法时,如果该方法有参数要求,也需要传递参数。

# 猫科动物
class maoke():
    # 属性
    maose = '猫纹'
    sex = 'm'

    # 方法
def pao(self):
    print('走猫步')

def pa(self):
    print('能上树')

# 定义猫类  去继承 猫科 类
class mao(maoke):

# 继承父类后,重新定义了父类中的方法
def pa(self):
    # 在子类中可以使用super直接调用父类的方法
    super().pa()
    print('很快的就能上树了')

def zhua(self):
    print('喜欢抓老鼠')

# 通过猫类 实例化对象
h = mao()
# print(h)
# print(h.__dict__)  # {}
	
# 可以获取对象的属性 猫对象自己的属性 ==> 猫类的属性,===> 继承的父类
# print(h.maose)
# 调用对象的方法
# h.pao()
# h.pa()
# h.zhua()


class bao(maoke):
pass

b = bao()
print(b)
b.pa()

res = 100/3
print(res)

多继承

# 多继承和多继承中的父类方法的调用

# 父亲类
class F():
def eat(self):
    print('大口喝酒,大口吃肉。。。')

# 母亲类
class M():
    def eat(self):
        print('动作优雅,浅尝即止')

# 孩子类
class C(F,M):
    def eat(self):
        super().eat() # 多继承和多继承中的父类方法的调用
        print('吃也哭,不吃也哭。。。')

# 实例化对象
c = C()
c.eat()

菱形继承

'''
    HuMan
 F       M
     C
'''


# 祖先类
	class HuMan():
    num = 444

    def eat(self):
        print(self.num)
        print('顿顿都是小烧烤。。。')


# 父亲类
class F(HuMan):
    num = 333

    def eat(self):
        super().eat()
        print(super().num)
        print('大口喝酒,大口吃肉。。。')


# 母亲类
class M(HuMan):
    num = 222

    def eat(self):
        super().eat()
        print(super().num)
        print('动作优雅,浅尝即止')


# 孩子类
class C(F, M):
    num = 111

    def eat(self):
        super().eat()
        print(super().num)
        print('吃也哭,不吃也哭。。。')


# 实例化对象
c = C()
c.eat()


继承的关系:C->F->M->HuMan

111
顿顿都是小烧烤。。。
444
动作优雅,浅尝即止
222
大口喝酒,大口吃肉。。。
333
吃也哭,不吃也哭。。。


	# mro() 获取MRO列表,就是类的继承关系
	print(C.mro())
	# [<class '__main__.C'>, <class '__main__.F'>, <class '__main__.M'>, <class '__main__.HuMan'>, <class 'object'>]
	

super()
    使用super去调用父级的方法时,实际上是在用super调用MRO列表中的上一级中的方法,
    使用super去访问父级的属性时,实际上是在用super访问MRO列表中的上一级中的属性。
    super()本身调用父级方法时,传递的self对象,就是这个方法中的那个self对象自己。

继承关系检测

class A:
    pass

class B(A):
    pass

class C(A):
    pass

class D(B,C):
    pass

# 获取类的 MRO列表

# print(A.mro())


# 检测一个类是否是另一个类的子类
res = issubclass(D,B) # True 检测D类是不是B类的子类
res = issubclass(D,C) # True 检测D类是不是C类的子类
res = issubclass(D,A) # True 检测D类是不是A类的子类
res = issubclass(A,D) # False 检测A类是不是D类的子类

print(res)

3.多态

多态 普通版本

# 对于同一个方法,由于调用的对象不同(或者传入的对象不同),最终实现了不同的结果

# 定义电脑类
class Computer():
    # 在电脑类中定义一个 sub 的规范的接口 方法
    def usb(self,obj):
        obj.start()

# 定义鼠标类
class Mouse():
    def start(self):
        print('鼠标启动成功,可以双击单击嗨起来。。。')

# 定义键盘类
class KeyBord():
    def start(self):
        print('键盘启动成功了,赶紧双击666。。。')

# 定义 U盘 类
class Udisk():
    def start(self):
        print('U盘启动了,赶紧检查一下我的种子还在不在。。。')

# 实例化对象
c = Computer()  # 电脑对象
m = Mouse()     # 鼠标对象
k = KeyBord()   # 键盘对象
u = Udisk()     # u盘对象


# 把不同的设备插入到电脑的usb的接口中
c.usb(m)
c.usb(k)
c.usb(u)

多态 继承版

定义一个接口规范类,其它类都继承这个类,并实现(重写)父类中的方法。
由于每个对象实现父类方法的方式或者过程都不相同,最后的结果是不一样的形态。


# 定义 USB
class USB():
    '''
     当前类的说明:
         这个类是一个接口规范类,需要子类继承并实现start方法
         start方法不做任何具体功能的实现
    '''
    #  在usb类中定义一个规范的接口方法,但是不实现任何功能,
    def start(self):
        pass



# 定义鼠标类
class Mouse(USB):
    def start(self):
        print('鼠标启动成功,可以双击单击嗨起来。。。')

# 定义键盘类
class KeyBord(USB):
    def start(self):
        print('键盘启动成功了,赶紧双击666。。。')

# 定义 U盘 类
class Udisk(USB):
    def start(self):
        print('U盘启动了,赶紧检查一下我的种子还在不在。。。')

# 实例化对象
m = Mouse() # 鼠标对象
k = KeyBord() # 键盘对象
u = Udisk()  # U盘对象

m.start()
k.start()
u.start()

面向对象高阶-描述符与设计模式

1.描述符

当一个类中,包含了三个魔术方法(__get__,__set__,__delete__)之一,或者全部时,那么这个类就称为描述符类。

作用:
1.描述符的作用就是对一个类中的某个成员进行一个详细的管理操作(获取,赋值,删除)
2.描述符就是代理了一个类中的成员的操作,描述符属于类,只能定义为类的属性

使用格式:
1把当前的描述符类赋值给一个需要代理的类中的成员属性


# 定义描述符类
class PersonName():
    __name = 'abc'

    def __get__(self, instance, owner):
        # print(self,instance,owner)
        return self.__name

    def __set__(self, instance, value):
        # print(self,instance,value)
        self.__name = value

    def __delete__(self, instance):
        # print(self,instance)
        # del self.__name
        print('不允许删除')

# 定义的普通类
class Person():
    # 把类中的一个成员属性交给一个描述符类来实现
    # 一个类中的成员的值是另一个描述符类的对象()
    # 那么当对这个类中得成员进行操作时,可以理解为就是对另一个对象的操作
    name = PersonName()

# 实例化对象
zs = Person()
print(zs.name)
zs.name = '张三'
print(zs.name)
del zs.name
print(zs.name)

2.描述符的应用案例解析

定义一个学生类,需要记录 学员的id,名字,分数
class Student():
    def __init__(self,id,name,score):
        self.id = id
        self.name = name
        # self.score = score

        # 检测分数范围
    if score >= 0 and score <= 100:
        self.score = score
    else:
        print('当前分数不符合要求')

def returnMe(self):
    info =  f'''
    学员编号:{self.id}
    学员姓名:{self.name}
    学员分数:{self.score}
    '''
    print(info)


def __setattr__(self, key, value):
    # 检测是否是给score进行赋值操作
    if key == 'score':
        # 检测分数范围
        if value >= 0 and value <= 100:
            object.__setattr__(self, key, value)
        else:
            print('当前分数不符合要求')
    else:
        object.__setattr__(self,key,value)

#定义描述符类 代理分数的管理
class Score():
    def __get__(self, instance, owner):
        return self.__score
    def __set__(self, instance, value):
        if value >= 0 and value <= 100:
            self.__score = value
        else:
            print('分数不符合要求')

# 使用描述符类代理score分数属性
class Student():
    score = Score()
    def __init__(self,id,name,score):
        self.id = id
        self.name = name
        self.score = score

    def returnMe(self):
        info =  f'''
        学员编号:{self.id}
        学员姓名:{self.name}
        学员分数:{self.score}
        '''
        print(info)
			
# 实例化对象
zs = Student(1011,'张三疯',99)
zs.returnMe()
zs.score = -20
zs.score = 88
zs.returnMe()

3.描述符的三种定义方式

格式一: 通过定义 描述符类来实现
class ScoreManage():
    def __get__(self, instance, owner):
        pass
    def __set__(self, instance, value):
        pass
    def __delete__(self, instance):
        pass

class Student():
    score = ScoreManage()

格式二:使用 property 函数 来实现
class Student():

    # 在当前需要被管理的类中 直接定义类似下面三个方法
    def getscore(self):
        print('getscore')

    def setscore(self,value):
        print('setscore',value)

    def delscore(self):
        print('delscore')

    # 在 property 函数中指定对应的三个方法,对应的方法 1。__get__,2。__set__,3。__delete__
    score = property(getscore,setscore,delscore)

zs = Student()
# print(zs.score)
# zs.score = 200
# del zs.score

格式三: 使用 @property 装饰器语法来实现
class Student():
    __score = None

    @property
    def score(self):
        print('get')
        return self.__score

    @score.setter
    def score(self,value):
        print('set')
        self.__score = value

    @score.deleter
    def score(self):
        print('delete')
        del self.__score

zs = Student()
# print(zs.score)
zs.score = 199
print(zs.score)
del zs.score

4.单例(单态)设计模式

在当前脚本中,同一个类只能实例化一个对象,去使用。
如何实现Python中的单例设计模式呢?

1.需要有一个方法,可以去控制当前对象的创建过程?
    构造方法 __new__
2.需要有一个标示来存储和表示是否有对象
    创建一个私有属性 进行存储,默认值为None
3.在创建对象的方法中去检测和判断是否有对象?
    如果没有对象,则创建对象,并且把对象存储起来,返回对象
    如果存储的是对象,则直接返回对象,就不需要创建新的对象了

class Demo():
    # 2.定义私有属性存储对象,默认值为None
    __obj = None

    # 1.定义构造方法
    def __new__(cls, *args, **kwargs):
        # 3。在创建对象的过程中,判断是否有对象
        if not cls.__obj:
            # 判断如果没有对象,则创建对象,并且存储起来
            cls.__obj = object.__new__(cls)
        # 直接把存储的对象返回
        return cls.__obj


	# 实例化对象
	a = Demo()
	b = Demo()
print(a)
print(b)	

5.Mixin 混合设计模式

继承需要有一个必要的前提,继承应该是一个 'is-a' 的关系。
 interface 接口类 来实现多重继承,python中本身就支持 多继承关系。
#  交通工具 
	class vehicle():
	    # 运输货物
	    def huo(self):
	        print('运输货物')
	
	    # 搭载乘客
    def ren(self):
        print('搭载乘客')


# 飞行器
class FlyingMixin():
    def fly(self):
        print('可以起飞了。。。')


# 定义汽车类
class cart(vehicle):
    pass


# 定义飞机
class airplane(vehicle, FlyingMixin):
    pass


# 定义直升机
class helicopter(vehicle, FlyingMixin):
    pass


此时去定义一个飞行器的类 Flying,让需要飞行的交通工具,直接继承这个类。可以解决这个问题。
但是:(1)出现类多继承,违背了'is-a'  。
     (2)飞行器这个类很容易被误解。
解决方案也是使用多继承,但是给飞行器这个类,定义成为一个 Mixin 混合类,此时就是等于把飞行器这个类,作为了一个扩展的功能,来扩展其它类。

装饰器 decorator

装饰器定义:在不改变原有函数代码,且保持原函数调用方法不变的情况下,给原函数增加新的功能。(或者给类增加属性和方法)
核心思想:用一个函数(或者类)去装饰一个旧函数(或者类),造出一个新函数(或者新类)。
应用场景:引入日志,函数执行时间的统计,执行函数前的准备工作,执行函数后的处理工作,权限校验,缓存等。
语法规则:在原有的函数上加上 @符,装饰器会把下面的函数当作参数传递到装饰器中,@符又被成为 语法糖。

1.装饰器的原型

利用闭包,把函数当作参数传递,并且在函数内去调用传递进来的函数,并返回一个函数。
# 定义外函数,接收一个函数作为参数
def outer(f):
    # 定义内函数,并且在内函数中调用了外函数的参数
    def inner():
        print('我是外函数中的内函数1')
        f()
        print('我是外函数中的内函数2')
    return inner


# 定义普通函数
# def old():
#     print('我是一个普通的函数')
#
# # old()  # 作为普通函数直接调用
# old = outer(old)  # outer返回了inner函数,赋值给了old
# old()             # 此时再调用old函数时,等同于调用了 inner 函数


# 改为装饰器用法
@outer      # 此处使用的@outer的语法就是把outer作为了装饰器,等同于 old = outer(old)
def old():
    print('我是一个普通的函数')

old()  # old函数经过 outer装饰器进行了装饰,代码和调用方法不变,但是函数的功能发送了改变

2.装饰器应用:统计函数的执行时间

import time

# 定义一个统计函数执行时间的 装饰器
def runtime(f):
    def inner():
        start = time.perf_counter()
        f()
        end =  time.perf_counter() - start
        print(f'函数的调用执行时间为:{end}')
    return inner

# 定义一个函数
@runtime
def func():
    for i in range(5):
        print(i,end=" ")
        time.sleep(1)

func()

3.装饰器的嵌套语法

# 1.普通装饰器的定义

# 定义装饰器
# 外函数
def outer(func):
    #内函数
    def inner():
        print('找到TA,成功拿到微信3')
        func()  # 在内函数中调用外函数中的行参-函数
        print('约TA,看一场午夜电影4')
    # 在外函数中返回内函数
    return inner

# 使用一个装饰器
# @outer
# def love():
#     print('畅谈人生')
#
# love() # == inner()

# 2.在定义一个装饰器
def kuozhan(f):
    def kzinner():
        print('扩展1')
        f()
        print('扩展2')
    return kzinner

#  装饰器的嵌套 先执行下面的,再执行上面的。
@kuozhan # 2。再使用上面的 kuozhan 装饰器,装饰 上一次返回的 inner 函数,又返回了 kzinner 函数
@outer   # 1。先使用离得近的 outer装饰器 装饰love函数,返回了一个 inner函数
def love():
    print('跟TA畅谈人生5')

love()
'''
1 3 5 4 2

1 先使用离得近的 outer装饰器 装饰love函数,返回了一个 inner函数
2 再使用上面的 kuozhan 装饰器,装饰 上一次返回的 inner 函数,又返回了 kzinner 函数

最后在调用love函数的时候是怎么执行的
    love() == kzinner()
                ===>  1
                ===>  inner()  
                           ===> 3
                           ===> love() ===> 5
                           ===> 4
                ===>  2

'''

4.对带有参数的函数进行装饰

# 定义装饰器
def outer(func):
    # 如果装饰器带有参数的函数,需要在内函数中定义行参,并传递给调用的函数。因为调用原函数等于调用内函数
    def inner(var):
        print(f'找到{var}TA,成功拿到微信。。')
        func(var)
        print(f'约{var}TA,看一场午夜电影。。')
    return inner

# 有参数的函数
@outer
def love(name):
    print(f'跟{name}畅谈人生。。。')

love('思思') #love() ==> inner()   love('思思') ===> inner('思思')

5.对多参数的函数进行装饰

def outer(func):
    def inner(who,name,*args,**kwargs):
        print('约TA,聊微信。。。')
        func(who,name,*args,**kwargs)
        print('天色一晚,怎么办?')
    return inner


# 定义多参数的 函数
@outer
def love(who,name,*args,**kwargs):
    print(f'{who}跟{name}畅谈人生。。。')
    print('完事去吃了好多美食',args)
    print('看了一场电影',kwargs)

love('三多','思思','火锅','辣条','7块钱的麻辣烫',mov='唐山大地震')
'''
love() ==> inner()
    love(...) ==> inner(...)
        inner(...) ==> love(...)
'''

6.带有参数的装饰器

# 如果你的装饰器需要有参数,那么给当前的装饰器套一个壳,用于接收装饰器的参数
def kuozhan(var):
    def outer(func):
        def inner1():
            print('TA给了你微信')
            func()
        def inner2():
            print('TA给介绍了TA')
            func()
        # 装饰器壳的参数,可以用于在函数内去做流程控制
        if var == 1:
            return inner1
        else:
            return inner2
    return outer


@kuozhan(2) # kuozhan(var) ==> outer() ==> outer(love) ==> inner()
def love():
    print('谈谈人生')

love()

7.用类装饰器装饰函数

class Outer():
    # 魔术方法:当把该类的对象当作函数调用时,自动触发 obj()
    def __call__(self,func):
        self.func = func  # 把传进来的函数作为对象的成员方法
        return self.inner # 返回一个函数

    # 在定义的需要返回的新方法中 去进行装饰和处理
    def inner(self,who):
        print('拿到TA的微信')
        self.func(who)
        print('看一场午夜电影')

@Outer()  # Outer() ==> obj  @obj==>obj(love) ==> __call__(love) ==> inner()
def love(who):
    print(f'{who}和TA谈谈人生')

love('哥') # inner('哥')
print(love) # 此时的 love就是属于Outer类这个对象中的inner方法

8.用类方法装饰函数

class Outer():
    def newinner(func):
        Outer.func = func  # 把传递进来的函数定义为类方法
        return Outer.inner # 同时返回一个新的类方法

    def inner():
        print('拿到妹子微信')
        Outer.func()
        print('看一场午夜电影')


@Outer.newinner  # Outer.newinner(love) ==> Outer.inner
def love():
    print('和妹子谈谈人生喝喝茶。。。')
love()          # love()  ==> Outer.inner()

9.用函数装饰器装饰类

使用函数装饰器,给类进行装饰,增加新的属性和方法。

# 定义函数,接收一个类。返回修改后的类
def kuozhan(cls):
    def func2():
        print('我是在装饰器中追加的新方法,func2')
    cls.func2 = func2 # 把刚才定义的方法赋值给 类
    cls.name = '我是在装饰器中追加的新属性 name'

    #返回时,把追加类新成员的 类 返回去
    return cls


@kuozhan   # kuozhan(Demo) ==> cls ==> Demo
class Demo():
    def func():
        print('我是Demo类中定义的func方法')

Demo.func() # 此时在调用的Demo类是通过装饰器,更新过的Demo类
Demo.func2()
print(Demo.name)

10.使用类装饰器装饰类

class KuoZhan():
    def __call__(self, cls):
        # 把接收的类,赋值给当前对象,作为一个属性
        self.cls = cls
        # 返回一个函数
        return self.newfunc

    def newfunc(self):
        self.cls.name = '我是在类装饰器中追加的新属性 name'
        self.cls.func2 = self.func2
        # 返回传递进来的类的实例化结果,obj
        return self.cls()

    def func2(self):
        print('我是在类装饰器中追加的新方法 func2')



@KuoZhan()  # KuoZhan() ==> obj ==> @obj(Demo) ==> __call__(Demo) ==> newfunc
class Demo():
    def func(self):
        print('我是Demo类中定义的func方法')

obj = Demo()  # Demo() ==> newfunc() ==> obj
obj.func()
obj.func2()
print(obj.name)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值