0
点赞
收藏
分享

微信扫一扫

32.Python面向对象(五)【描述符、运算符底层、装饰器:闭包-闭包参数-内置装饰器-类装饰器】


目录:

  • ​​每篇前言:​​
  • ​​Python面向对象(五)​​
  • ​​1.1 描述符​​
  • ​​1.2 运算符底层调用的什么?​​
  • ​​1.3 装饰器​​
  • ​​第一部分——引入门​​
  • ​​(1)首先、咱再看遍闭包是啥:​​
  • ​​(2)然后,咱稍微高级点,看看闭包参数。​​
  • ​​(3)最后,就来看看第一种装饰器:​​
  • ​​第二部分——类里面的内置装饰器​​
  • ​​(1)引入​​
  • ​​(2)第一个是把类里面的方法变为属性:​​
  • ​​(3)静态方法​​
  • ​​(4)第三个是类方法:​​
  • ​​第三部分——最后阶段​​
  • ​​(1)类装饰器 必须使用__call__方法​​
  • ​​(2)看看高级点的​​
  • ​​拓展一下呗——来个装饰器的习题​​

每篇前言:

🏆🏆作者介绍:【孤寒者】—全栈领域优质创作者、HDZ核心组成员、华为云享专家Python全栈领域博主


Python面向对象(五)

1.1 描述符

描述符协议:python描述符是一个“绑定行为”的对象属性,在描述符协议中,它可以通过方法重写属性的访问。这些方法有​​__get__()​​​, ​​__set__()​​​, 和​​__delete__()​​​。
如果这些方法中的任何一个被定义在一个对象中,这个对象就是一个描述符

举例说明:

# -*- coding: utf-8 -*-
"""
__author__ = 孤寒者
"""
# 描述符:描述符就是类里面的属性base
# 控制实例对象a访问 这个属性 (base) 可以做一些额外的操作
# 描述符 定义了__get__ __set__ __delete__ 当中的一种
class Base:
def __get__(self,instance,owner):
print('恭喜玩家获得荒古宝典')
def __set__(self, instance,value):
print('强化%s'%value)
def __delete__(self,instance):
print('武器已经损坏')

class A:
base = Base()

#实例化
a = A()

a.base # __get__ 会直接输出__get__方法里面的内容

a.base = 50 # __set__ 会直接输出__set__方法里面的内容

del a.base # __delete__ 会直接输出__delete__方法里面的内容

32.Python面向对象(五)【描述符、运算符底层、装饰器:闭包-闭包参数-内置装饰器-类装饰器】_内置装饰器

1.2 运算符底层调用的什么?

  • ​+​​​调用的是​​__add__​

举例说明:

# -*- coding: utf-8 -*-
"""
__author__ = 孤寒者
"""
class A:
def __init__(self,num1,num2):
self.num1 = num1
self.num2 = num2

def __add__(self,other): #self 实例对象 ; other 另外一个实例对象
sum1 = self.num1 + other.num1
sum2 = self.num2 + other.num2
return sum1,sum2


a = A(1,2)
b = A(3,4)
print(a+b) #输出为 (4,6)

32.Python面向对象(五)【描述符、运算符底层、装饰器:闭包-闭包参数-内置装饰器-类装饰器】_描述符_02

运算符方法(了解即可)

__add__(self,other) # x+y

__sub__(self,other) # x-y

__mul__(self,other) # x*y

__mod__(self,other) # x%y

__iadd__(self,other)  # x+=y

__isub__(self,other)  # x-=y

__radd__(self,other)  # y+x

__rsub__(self,other)  # y-x

__imul__(self,other)  # x*=y

__imod__(self,other)  # x%=y

1.3 装饰器

有这个玩意的原因:python是一个动态语言,因为一切都是对象。是一个脚本语言。

第一部分——引入门

(1)首先、咱再看遍闭包是啥:

# -*- coding: utf-8 -*-
"""
__author__ = 孤寒者
"""
#闭包
def fun1():
print('fun1')
def fun2():
print('fun2')
return fun2

#fun1()() ===> fun2()
a = fun1()
a() #会执行两个函数

(2)然后,咱稍微高级点,看看闭包参数。

这种方法比较麻烦,所以下面就引入了装饰器,和这个的功能一模一样,不过
简单了许多:

# -*- coding: utf-8 -*-
"""
__author__ = 孤寒者
"""
#闭包里面有参数 回调函数
def aa(fun): #fun = f1
print('------------aa')
def bb():
fun() #fun() = f1()
print('----------bb')
return bb

def f1():
print('this is f1')

def f2():
print('this is f2')

cc = aa(f1)
cc()

32.Python面向对象(五)【描述符、运算符底层、装饰器:闭包-闭包参数-内置装饰器-类装饰器】_装饰器_03

(3)最后,就来看看第一种装饰器:

# -*- coding: utf-8 -*-
"""
__author__ = 孤寒者
"""
# 装饰器 在不改变原有函数的基础上面增加额外的功能
# 装饰器
def aa(fun): #fun = f1
print('------------aa')
def bb():
fun() #fun() = f1()
print('----------bb')
return bb

# 装饰器 被装饰的函数名字(f1)会被当做参数传递给装饰函数(aa)
# 代码就是: aa(f1)
# 装饰函数(aa)执行完它自己内部的代码之后,会把它的结果返回给
# 被装饰的函数(f1)
# 代码就是: f1 = aa(f1)
# 然后下面又是f1() 就相当于 aa(f1)()

@aa # 就相当于 f1 = aa(f1) 要使用嵌套函数里面的内容 aa(f1)(),就是最后调用的时候f1加个括号
# 而注意函数外部的只要用到装饰器就会执行,而嵌套的内层函数需要调用才会执行,所以
# 用处就是把重要的东西写到嵌套的内层函数,在调用的时候才会执行
def f1():
print('this is f1')

def f2():
print('this is f2')

f1() #输出和上面一个一模一样

32.Python面向对象(五)【描述符、运算符底层、装饰器:闭包-闭包参数-内置装饰器-类装饰器】_python_04

第二部分——类里面的内置装饰器

(1)引入

# -*- coding: utf-8 -*-
"""
__author__ = 孤寒者
"""
class Base:

def fun(self):
print('好好学习,天天向上')


b = Base()
b.fun() # 调用类里面的方法,就会执行类里面的方法fun,打印 好好学习,天天向上

正题:

(2)第一个是把类里面的方法变为属性:

# -*- coding: utf-8 -*-
"""
__author__ = 孤寒者
"""
class Base:
name = '孤寒者'

@property #将方法变为属性 更加简洁
def fun(self):
return('好好学习,天天向上')


b = Base()
print(b.name) #属性的使用不需要加括号;方法的使用才要加括号
print(b.fun) #现在类里面的方法fun就变成了类的属性

32.Python面向对象(五)【描述符、运算符底层、装饰器:闭包-闭包参数-内置装饰器-类装饰器】_类装饰器_05

(3)静态方法

  • 第二个是把类里面的方法变为静态方法,让其可以像使用函数一样去使用,而不需要再实例化才能使用:

# -*- coding: utf-8 -*-
"""
__author__ = 孤寒者
"""
class Base:

@staticmethod #静态方法 方法能够像函数一样的去使用, 比如在类里面,你要写一些闭包什么的就可以在这里面写,相当于扩展了一些功能。
def fun2(): # 注意:这里已经不需要self 和class类断开联系
print('过年好,新年好')

#再来个不加装饰器的
def func(self):
print('这是普通方法')

Base.fun2() # fun2已经变为静态方法,可以像使用函数一样的使用
# 输出为: 过年好,新年好

# Base是类名;Base() 就是实例化
Base().func() # 而没有使用装饰器的方法就需要先实例化,才能去使用

32.Python面向对象(五)【描述符、运算符底层、装饰器:闭包-闭包参数-内置装饰器-类装饰器】_描述符_06

(4)第三个是类方法:

# -*- coding: utf-8 -*-
"""
__author__ = 孤寒者
"""
class Base:

def func(self):
print('这是普通方法')

@classmethod
def fun3(cls): # 没有self 和实例无关,这是类方法 ; 有self的是实例方法,需要先实例化才能使用
print('cls类方法')
cls().func() # cls 代表类本身,即Base这个类


# 类方法的使用,也不用实例化 直接类名点方法
Base.fun3()

32.Python面向对象(五)【描述符、运算符底层、装饰器:闭包-闭包参数-内置装饰器-类装饰器】_类装饰器_07

第三部分——最后阶段

(1)类装饰器 必须使用__call__方法

# -*- coding: utf-8 -*-
"""
__author__ = 孤寒者
"""
class Base:

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

def __call__(self,*args,**kwargs):
print('this is call')

@Base # func = Base(func) 被装饰函数(func)当做参数传递给装饰函数(Base)
def func():
print('this is func')

func() # 此处的括号就相当于 func() = Base(func)()
# __call__方法只要实例化就会被调用
#输出为: this is call

32.Python面向对象(五)【描述符、运算符底层、装饰器:闭包-闭包参数-内置装饰器-类装饰器】_python_08

(2)看看高级点的

# -*- coding: utf-8 -*-
"""
__author__ = 孤寒者
"""
class Base:

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

def __call__(self,*args,**kwargs):
self.fun() #就会打印 this is func
print('this is call')

def __str__(self):
return 'this is str'

@Base # func = Base(func) 相当于实例化 被装饰函数(func)当做参数传递给装饰函数(Base)
def func():
print('this is func')

func() # 此处的括号就相当于 func() = Base(func)()
# __call__方法只要实例化就会被调用
print(func) # 打印类的实例,就会调用类里面的__str__方法

32.Python面向对象(五)【描述符、运算符底层、装饰器:闭包-闭包参数-内置装饰器-类装饰器】_装饰器_09

拓展一下呗——来个装饰器的习题

  • 测试type和isinstance两个函数,哪个速度更加的快?

需要注意的是:程序运行速度比较快 只查看上面两个函数 运行一次的时间显示不出来效果,可以查看循环一万次的时间。

# -*- coding: utf-8 -*-
"""
__author__ = 孤寒者
"""
#time.time() 计算目前的时间 时间戳(格林威治时间, 1970.1.1到现在的总秒数)
import time

def funa(fun):
def funb():
a = time.time()
fun()
b = time.time()
print('函数运行了%s'%(b-a))
return funb

@funa
def f1():
for i in range(100000):
type(1)
f1()

@funa
def f2():
for i in range(100000):
isinstance(1,int)
f2()

32.Python面向对象(五)【描述符、运算符底层、装饰器:闭包-闭包参数-内置装饰器-类装饰器】_python_10


举报

相关推荐

0 条评论