python装饰器学习详解-函数部分

pyspark.sql.functions中的col函数         嗨喽! 大家好,我是“流水不争先,争得滔滔不绝”的翀,欢迎大家来交流学习,一起入坑数据分析,希望我们一起好好学习,天天向上,目前在社会毒打中~~ col函数的作用相当于python中的dadaframe格式的提取data[‘id’],关键是能够进行计算。可能有点难以理解,下面我举行一些例子说明 spark中我们想查看一下某列数据可以这么做 df_kol_stats.select(col("collect_count")).show(5) +---. 阅读详情

本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理

最近阅读《流畅的python》看见其用函数写装饰器部分写的很好,想写一些自己的读书笔记。众所周知,装饰器是python学习过程中的一道门槛,初学者学习时往往是知其然,不知其所以然,这样的结果是导致一段时间后会遗忘掉该部分内容,只好再次去学习,拉高了学习成本。

想学好python的装饰器,需要明白一下几点;

1:闭包

1)函数嵌套

2)内部函数使用外部函数的变量

3)外部函数的返回值为内部函数

​ 接下来看看《流畅的python》中的例子,我稍微修改了一下:

>>> def make_averager(series=[]):
...     def averager(new_value):
...             series.append(new_value)
...             total = sum(series)
...             return total/len(series)
...     return averager
...
>>> avg = make_averager()
>>> avg
<function make_averager.<locals>.averager at 0x10b82cb00>
>>> avg(10)
10.0
>>> avg(11)
10.5
>>> avg(12)
11.0

​ 函数 make_averager 实现了一个 计算当前所有数字的平均值的功能,不断的添加一个值,然后计算当前的平均值。

​ avg这个对象内存地址指向了make_averager这个函数的内部函数中,而且avg通过不断的添加值进行平均值计算,按理说在这个内部函数没有存储new_value的空间,而且在make_averager对avg赋值后,函数返回后series这个变量也应该消失了,但是avg却依然可以进行计算。

​ 这就是闭包,内部函数averager使用外面的自由变量,也就是属于make_averager的局部变量series

>>> avg.__code__.co_varnames
('new_value', 'total')
>>> avg.__code__.co_freevars
('series',)

​ 可以发现avg的自由变量是make_averager的局部变量,就是说闭包里的内部函数可以使用外部函数的变量,即我们上面提到的第二点:“内部函数使用外部函数的变量”, 注:自由变量只能read,并不能write,不然会提示本地变量并没有赋值的错误,我们举的例子没遇到这个问题,因为我们没有给 series 赋值,我们只是调 用 series.append,并把它传给 sum 和 len。也就是说,我们利用了 列表是可变的对象这一事实 。下图是书中提供的闭包范围图:

2:装饰器的实现

所谓装饰器,就是在不改变基础函数的功能上再次给它封装一层,达到我们想要的目的,接下来我举个简单的例子:

​ deco_demo.py

1 def col(func):
  2     def inner(*args, **kwargs):
  3         print(func.__name__)
  4         print(locals())
  5         print(inner.__code__.co_varnames)
  6         print(inner.__code__.co_freevars)
  7         return func(*args, **kwargs)
  8     return inner
  9
 10
 11 @col
 12 def new_add(x):
 13     return x+2
 14
 15
 16 def new_add_1(x):
 17     return x+3
 18
 19
 20 print(new_add(3))
 21
 22 new_add_1 = col(new_add_1)
 23 print(new_add_1(3))

下方是它的返回结果:

new_add
{'args': (3,), 'kwargs': {}, 'func': <function new_add at 0x10d32aa70>, 'inner': <function col.<locals>.inner at 0x10d32acb0>}
('args', 'kwargs')
('func', 'inner')
5
new_add_1
{'args': (3,), 'kwargs': {}, 'func': <function new_add_1 at 0x10d32add0>, 'inner': <function col.<locals>.inner at 0x10d32a8c0>}
('args', 'kwargs')
('func', 'inner')
6

1-8:是定义的一个简单装饰器,

3:打印当被装饰函数的名字

4:打印inner这个内部函数中的所有变量

5:打印当前inner的局部变量;

6:则打印自由变量;

11-13:修饰了一个简单函数

16,22,23:@这个语法糖,背后实现的过程;

​ 也就是说 col(new_add) 返回的是当前的内部函数的内存地址,而这个调用这个内部函数时会使用自由变量func即col的局部变量,进而达到装饰器的目的;

有参数的装饰器实现

​ 既然无参数的装饰器即@col ,通过内部函数的方式装饰基础函数,那么我们调用有参数的装饰器 则可以再原本的基础即函数col再封装一层函数,使其达到可以通过装饰器传参数的目的

1 from functools import wraps
  2
  3
  4 def col(string="hello world"):
  5     def decorate(func):
  6         @wraps(func)
  7         def inner(*args, **kwargs):
  8             print(string)
  9             return func(*args, **kwargs)
 10         return inner
 11     return decorate
 12
 13
 14 @col()
 15 def new_add(x):
 16     return x+2
 17
 18
 19 @col("hello python")
 20 def new_add_1(x):
 21     return x+3
 22
 23
 24 def new_add_2(x):
 25     return x+4
 26
 27
 28 print(new_add(1))
 29 print(new_add_1(1))
 30
 31
 32 new_add_2 = col("hello china")(new_add_2)
 33 print(new_add_2(1))

导入wrap是为了修复这个装饰器的名称, new_add.__name__ 调用时指向被装饰的函数,而不是内部函数,有兴趣的小伙伴可以去了解一下;

4-11:实现了一个带参数的装饰器,最外层返回的是我们真正的装饰器;

32-33:则是@这个装饰器语法糖背后的实现过程

可以发现new_add与new_add_1这两个函数的装饰器是两个不同值,而我们的装饰器也返回了不同的对应情况

hello world
3
hello python
4
hello china
5

间而言之:装饰器就是在我们需要添加功能的函数上进而封装一层,而python的语法糖@背后,帮助我们省略掉了这些赋值的过程;

3:装饰器何时调用

关于装饰器何时运行,我们分两种情况讨论,一种是当作脚本运行时,另一种是当作模块被导入时;

1 registry = []
  2
  3
  4 def register(func):
  5     print(f"running register {func}")
  6     registry.append(func)
  7     return func
  8
  9
 10 @register
 11 def f1():
 12     print('running f1()')
 13
 14
 15 @register
 16 def f2():
 17     print('running f2()')
 18
 19
 20 def f3():
 21     print('running f3()')
 22
 23
 24 def main():
 25     print('running main()')
 26     print('regisry ->', registry)
 27     f1()
 28     f2()
 29     f3()
 30
 31
 32 if __name__ == '__main__':
 33     main()

当作独立脚本运行时:

running register <function f1 at 0x103f9dcb0>
running register <function f2 at 0x103f9ddd0>
running main()
regisry -> [<function f1 at 0x103f9dcb0>, <function f2 at 0x103f9ddd0>]
running f1()
running f2()
running f3()

被当作模块导入时:

>>> import registration
running register <function f1 at 0x1005a2710>
running register <function f2 at 0x1005a2b90>
>>> registration.registry
[<function f1 at 0x1005a2710>, <function f2 at 0x1005a2b90>]

该段代码的装饰器主要功能是:记录了被装饰函数的个数,通常是web框架以这种方式把函数注册到中央注册器的某处。

总结:可以发现装饰器无论是作为模块被导入,还是单独的脚本运行,它都是优先执行的;

4:装饰器的常用模块

之前介绍的function.wraps不用说了,接下来介绍两种神奇的装饰器;

1:singledispatch

何为singledispatch ?

就是在不改变函数本身的功能上复用该函数,达到重复使用函数名的目的,有点类似多态的感觉;可以把整体方案拆分成多个模块,甚至可以为你无法修改的类提供专门的函数。使用@singledispatch 装饰的普通函数会变成泛函数(generic function);根据第一个参数的类型,以不同方式执行相同操作的一组函数

1 from functools import singledispatch
  2
  3
  4 @singledispatch
  5 def hello(obj):
  6     print(obj)
  7
  8
  9 @hello.register(str)
 10 def _(text):
 11     print("hello world "+text)
 12
 13
 14 @hello.register(int)
 15 def _(n):
 16     print(n)
 17
 18
 19 hello({"what": "say"})
 20 print('*'*30)
 21 hello('dengxuan')
 22 print('*'*30)
 23 hello(123)
{'what': 'say'}
******************************
hello world dengxuan
******************************
123

从该段代码中我们可以发现,当使用singledispatch这个装饰器时,函数hello可以根据不同的参数返回不同的结果。这样的好处就是极大的减少代码中的if/elif/else,并且可以复用函数名称 _ (下横线代表没用),降低了代码的耦合度,达到了多态的效果。

2:lru_cache

根据书上原话:

functools.lru_cache 是非常实用的装饰器,它实现了备忘 (memoization)功能。这是一项优化技术,它把耗时的函数的结果保存 起来,避免传入相同的参数时重复计算。LRU 三个字母是“Least Recently Used”的缩写,表明缓存不会无限制增长,一段时间不用的缓存 条目会被扔掉。

1 from my_tools.runtime import clock
  2 import functools
  3
  4
  5 @functools.lru_cache()
  6 @clock
  7 def fibonacci(n):
  8     if n < 2:
  9         return n
 10     return fibonacci(n-2)+fibonacci(n-1)
 11
 12
 13 if __name__ == '__main__':
 14     print(fibonacci(6))

第5行:注释funtools.lru_cache()

返回结果:

[0.00000046] fibonacci(0) -> 0
[0.00000053] fibonacci(1) -> 1
[0.00006782] fibonacci(2) -> 1
[0.00000030] fibonacci(1) -> 1
[0.00000035] fibonacci(0) -> 0
[0.00000037] fibonacci(1) -> 1
[0.00001312] fibonacci(2) -> 1
[0.00002514] fibonacci(3) -> 2
[0.00010535] fibonacci(4) -> 3
[0.00000030] fibonacci(1) -> 1
[0.00000030] fibonacci(0) -> 0
[0.00000037] fibonacci(1) -> 1
[0.00001209] fibonacci(2) -> 1
[0.00002376] fibonacci(3) -> 2
[0.00000028] fibonacci(0) -> 0
[0.00000038] fibonacci(1) -> 1
[0.00001210] fibonacci(2) -> 1
[0.00000028] fibonacci(1) -> 1
[0.00000036] fibonacci(0) -> 0
[0.00000034] fibonacci(1) -> 1
[0.00001281] fibonacci(2) -> 1
[0.00002466] fibonacci(3) -> 2
[0.00004897] fibonacci(4) -> 3
[0.00008414] fibonacci(5) -> 5
[0.00020196] fibonacci(6) -> 8
8

当取消掉第5行注释时;

[0.00000040] fibonacci(0) -> 0
[0.00000049] fibonacci(1) -> 1
[0.00008032] fibonacci(2) -> 1
[0.00000066] fibonacci(3) -> 2
[0.00009398] fibonacci(4) -> 3
[0.00000063] fibonacci(5) -> 5
[0.00010943] fibonacci(6) -> 8
8

可以发现,lru_cache()这个装饰器,极大的提高了计算性能;

maxsize 参数指定存储多少个调用的结果。缓存满了之后,旧的结果会被扔掉,腾出空间。为了得到最佳性能,maxsize 应该设为 2 的 幂。typed 参数如果设为 True,把不同参数类型得到的结果分开保存,即把通常认为相等的浮点数和整数参数(如 1 和 1.0)区分开。顺 便说一下,因为 lru_cache 使用字典存储结果,而且键根据调用时传 入的定位参数和关键字参数创建,所以被 lru_cache 装饰的函数,它的所有参数都必须是可散列的。

5:多重装饰器

@d1
@d2
def f():
  print('hello world')
  
###########################

def f():
  print("hello world")

f = d1(d2(f))

上下两块代码是等效效果;

想要获取更多Python学习资料可以加
QQ:2955637827私聊
或加Q群630390733
大家一起来学习讨论吧!

 

小甲鱼零基础学python全套课后题及答案 小甲鱼零基础学python全套课后题及答案,96集全部答案。 立即下载

相关推荐

小甲鱼零基础入门学习Python+全套源码课件

完整:小甲鱼python3全套ppt课件.py源码

python 常用函数总结

python 常用函数总结 本文主要是pandas常用函数的总结: 1 import语句 pandas as pd import numpy as np import matplotlib.pyplot as plt import datetime import re 2 文件读取 df = pd.read_csv(path=‘file.csv’) 参数:header=None 用默认列名,0,1...

babymj100的博客 1567

零基础学python.pdf

零基础学python.pdf

小甲鱼python入门_python基础笔记(非系统/自用/参考小甲鱼的零基础入门学习python)上...

---恢复内容开始---1.原始字符串的使用,在字符串前加r就行(用于对\进行自动转译)>>>str = r'C:\now\wifr''C:\\now\\wifr'但在字符串后面不能有空的'\'>>>str = r'C:\now\wirf\'error长字符串的使用,用""" """将字符串包起来>>>str = """ xsf,xfasf,sdasdas"""'xsf,\nxfasf,\nsda...

weixin_39616674的博客 215

零基础入门学习Python_零基础入门学习Python_小甲鱼_

小甲鱼书籍,零基础入门学习Python,适合新手学习,B站有随书教学视频

小甲鱼《零基础入门学习Python》全套课后作业及答案.pdf

⼩甲鱼《零基础⼊门学习Python》全套课后作业及答案 1.⼩甲鱼的课后作业 ⼩甲鱼的课后作业 提取码: 4idx 2.另外赠送⼤家⼀本⾮常实⽤ 另外赠送⼤家⼀本⾮常实⽤Python书籍: 书籍: Python编程:从⼊门到实践 3.再分享⼀本书给⼤家吧,之后⾃⼰渐渐往数据分析和算法⽅向⾛了 再分享⼀本书给⼤家吧,之后⾃⼰渐渐往数据分析和算法⽅向⾛了 利⽤Python进⾏数据分析(第⼆版)_wrapper 书不在多,贵在精,多动⼿,致⼤家永远学不完的编程之路,加油~~~

python中cols和rows,x与y,以及width和height的关系

列cols:X (width)行列与坐标系对应关系。

知识搬运者 853

Win10/Win11系统下冒险岛V128单机版一键搭建教程(含MySQL配置避坑指南)

本文提供Win10/Win11系统下冒险岛V128单机版一键搭建的详细教程,涵盖服务端部署、MySQL配置优化及常见问题解决方案。通过本指南,玩家可轻松实现单机版冒险岛的一键启动,重温经典游戏体验,同时避免常见的技术陷阱。

weixin_29261711的博客 655

col用法总结

    col 过滤掉反向(以及半反向)换行符(LF: line feed or NL: new line), 这样输出按正常顺序,即只包括正向和半正向换行符, 而且在可能的地方使用tab替换白空格.这对 nroff(1) 和 tbl(1) 的输出处理很有用处.     col 从标准输出读入,并写出到标准输出上. 选项如下: -b 不输出任何退格符,在每列的位置上只打印最后写的那个字

Yoara的备忘录 3052

MediaCodec视频解码流程详解及参考demo

本文主要讲解mediacodec的视频解码流程,及demo参考例子。

分享音视频技术 7877

openvpn 安装 (Alibaba Cloud Linux release 3 (Soaring Falcon))

1.错误:configure: error: libnl-genl-3.0 package not found or too old. Is the development package and pkg-config (/usr/bin/pkg-config) installed?# ta.key在/etc/openvpn/server/目录下可以如下配置,否则需要写完整路径。# 配置账号密码登录客户端需要ca证书(可选)# 证书校验算法 配置上面生成的完整路径。# ca证书 配置上面生成的完整路径。

dubhe_zhao的博客 2154

python装饰器详解

python装饰器

weixin_44992737的博客 8万+

Pytorch实现EdgeCNN(基于PyTorch实现)

本专栏整理了《图神经网络代码实战》,内包含了不同图神经网络的相关代码实现(PyG以及自实现),理论与实践相结合,如GCN、GAT、GraphSAGE等经典图网络,每一个代码实例都附带有完整的代码。

优快云 精品推荐 1万+

Python装饰器详解

详细介绍了Python装饰器语法的有关内容与使用技巧,希望对大家有所帮助。

千山暮彩 1万+

Ut接口原理及 VoLTE 补充业务自管理信令流程(GBA 引导认证+业务访问认证+ VoLTE 补充业务自管理)

2. Ut 接口及 VoLTE 业务子管理概述 2.1 UT 接口 —— VoLTE 终端补充业务配置 2.2终端通过 Ut 接口完成 VoLTE 补充业务自管理举例 2.3什么是 GBA 和 GAA 架构 2.4为什么要引入 GBA 架构认证及 BSF 网元 2.5UE(终端) 接口相关网元及功能 2.6GBA 架构流程概述 3. Ut 接口业务自管理信令流程 3.1 补充业务自管理及本文主要参考以下规范 3.2 Ut 接口业务自管理信令流程:查询补充业务 3.2.1 UE获

原来45的博客 1258

Orin 10G PHY网络分析

由于调试用的10G PHY,所以整理下分析过程; 1.从Orin devkit 丝印来看RJ45 对应J17 通过搜索 MGBE_PHY_A_N 找到连接的10G PHY, 原理图上标明了MDIO address 为0x0, 使用的PHY 芯片为 Marvel 的AQR113C, 主要特性: 架构: 关键特征: MDC 连接了GPIO26_XFI0_MDC; MDIO 连接了GPIO25_XFI0_MDIO; 通过pinmux_config映射表也可以..

乐于分享 5667

python中装饰器详解

装饰器 我们知道,在python中,我们可以像使用变量一样使用函,这主要依赖于以下几点: 函数可以被赋值给其他变量 函数可以被删除 可以在函数里面再定义函数,函数嵌套。 函数可以作为参数传递给另外一个函数 函数可以作为另一个函数的返回值 对一个简单的函数进行装饰 为了更好的理解装饰器,我们先从一个简单的例子开始,假设有下面这个函数: def hello(): return...

AFeng521web 7941

核心组件大换血:Backbone与Neck魔改篇:YOLO26结合StarNet结构:2026星状网络在YOLO生态的即插即用实战

本文将介绍如何将StarNet作为Backbone替换YOLO26原生架构,以提升边缘设备上的目标检测性能。文章首先分析了YOLO26在特定场景下的精度瓶颈,指出其通用Backbone设计存在不足。随后深入解析StarNet的核心创新——星操作(Star Operation),这一低维计算却能获得高维特征表达的数学魔术,以及其极简的StarBlock模块设计。通过对比YOLO26原生架构的三大创新与痛点,作者提出两种替换策略:完整替换Backbone或局部替换+Neck联调。文中提供了StarNet核心代码

ZDQ58818的博客 290

【Python】装饰器函数

以上是装饰器函数的一些基本内容, 要尝试着敲一遍才能理解, 如果第一遍看不懂的话,不要慌, 因为装饰器,闭包函数,*操作符等算是python中的中高级内容了, 我也是学习了好多遍,虽然实际中从没用过,但是学学对于理解pyhton的特性还是很有帮助的, 最后, 希望这篇文章可以帮到你!

享你所想 1603

【AI黑话日日新】什么是AI Infra?

是支撑AI模型开发、训练、推理、部署与规模化运营的,是连接底层算力与上层AI应用的“数字基建”。没有高效的AI Infra,大模型训练、推理与落地都无法高效实现。

专注:太空算力、AI infra、异构调度、大模型成本工程 1114

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Python装饰器的使用详解

在函数嵌套的前提下,内部函数使用外部函数的变量,并且外部函数返回内部函数我们把这个使用外部函数变量的内部函数称为闭包。

lIujunXHU的博客 2713

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

python高阶知识之函数装饰器详解

装饰器(decorator)是函数一种高阶用法,定义时需要满足几个条件:1 函数内定义嵌套函数并返回该函数(这种叫函数闭包)2 将函数作为参数传入这样看来实现也不是很复杂,平常我们也会经常用到装饰器函数,比如类中的@staticmethod,@classmethod,Flask框架中的@app.route()等。

kymppcds的博客 1326

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

【python】装饰器详解

本文将带你学习装饰器在 Python 中的工作原理,如果在函数和类中使用装饰器,如何利用装饰器避免代码重复(DRY 原则,Don’t Repeat Yourselfdef __init__(self, a, *args, **kwargs): # 类装饰器参数self.a = adef __call__(self, func): # 被装饰函数print("开始调用example函数..............")example()self.a = a# @语法糖等价形式。

z099164的博客 1051

Python装饰器:函数装饰器①

func()我们可以使用")Hello!在这个例子中,是一个装饰器,它接受函数say_hello作为参数,并返回一个新的函数wrapper。当调用say_hello时,实际上调用的是wrapper函数。装饰器是 Python 中一个非常强大的工具,可以用来扩展和修改函数或方法的行为。通过装饰器,我们可以在不修改原始代码的情况下为函数添加额外的功能。在实际开发中,装饰器有很多应用场景,包括日志记录、访问控制、性能优化等。希望本文能够帮助你更好地理解和使用 Python 中的装饰器。

结合项目案例,记录点点滴滴,自己回顾,分享他人o__o 2904

Python函数:装饰器

本章介绍了python函数中的装饰器

2403_86719076的博客 2333
上一篇: Python 炫技操作:安装包的八种方法,你知道吗?
下一篇: 学习Python之数据类型
pythonputao
博客等级 码龄6年 60粉丝 111原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值