python 静态方法_Python编程思想(25):方法深度解析
# 定义全局空间的test函数def test (): print("全局空间的test方法")# 全局空间的name变量name = 'Bill'class Dog: # 定义Dog空间的run函数 def run(): print("Dog空间的run方法") # 定义Bird空间的bar变量 value = 123# 调用全局空间的函数和变量test()print(name)# 调用Bird空间的函数和变量Dog.run()print(Dog.value)
上面代码在全局空间和Dog类(Dog空间)中分别定义了test函数和name变量,从定义它们的代码来看,几乎没有任何区别,只是在Dog类中定义它们时需要缩进。接下来程序在调用Dog空间内的value变量和run函数(方法)时,只要添加Dog.前缀即可,这说明完全可以通过Dog类来调用run函数(方法)。现在问题来了,如果使用类调用实例方法,那么该方法的第一个参数(self)怎么自动绑定呢?例如如下程序:示例代码:class_demo2.py
class Person: def run (self): print(self, '正在跑步...')# 通过类调用实例方法Person.run()
运行这段代码,程序会抛出如下异常:
TypeError: run() missing 1 required positional argument: 'self'
在这段代码中,run方法缺少传入的self参数,所以导致程序出错。这说明在使用类调用实例方法时, Python不会自动为第1个参数绑定调用者。实际上也没法自动绑定,因此实例方法的调用者是类本身,而不是对象。如果程序依然希望使用类来调用实例方法,则必须手动为方法的第1个参数传入参数值。例如,使用下面的代码:
class Person: def run (self): print(self, '正在跑步...')# 通过类调用实例方法# Person.run()person = Person()# 显式为方法的第一个参数绑定参数值Person.run(person)
这段代码显式地为 run方法的第1个参数绑定了参数值,这样的调用效果完全等同于执行 person.run()方法。实际上,当通过Person类调用run实例方法时, Python只要求手动为第1个参数绑定参数值,并不要求必须绑定Person对象,因此也可使用如下代码进行调用。
# 显式地为方法的第一个参数绑定Python字符串参数值Person.run('Python')
如果按上面方式进行绑定,那么Python字符串就会被传给run()方法的第1个参数self。因此,运行上面代码,将会看到如下输出结果:
Python 正在跑步...
Python的类可以调用实例方法,但使用类调用实例方法时,Python不会自动为方法的第1个参数self绑定参数值。程序必须显式地为第1个参数self传入方法调用者。这种调用方式被称为“未绑定调用”。2. 类方法与静态方法实际上, Python完全支持定义类方法,甚至支持定义静态方法。Python的类方法和静态方法类似,它们都推荐使用类来调用(其实也可使用对象来调用)。类方法和静态方法的区别:Python会自动绑定类方法的第1个参数,类方法的第1个参数(通常建议参数名为cls)会自动绑定到类本身。但对于静态方法则不会自动绑定。使用@ classmethod修饰的方法就是类方法,使用@ staticmethod修饰的方法就是静态方法。下面代码演示了定义类方法和静态方法。示例代码:class_static_method.py
class Pandas: # classmethod修饰的方法是类方法 @classmethod def run (cls): print('类方法run: ', cls) # staticmethod修饰的方法是静态方法 @staticmethod def printName (p): print('静态方法info: ', p)# 调用类方法,Dog类会自动绑定到第一个参数Pandas.run()# 调用静态方法,不会自动绑定,因此程序必须手动绑定第1个参数Pandas.printName('小团子')# 创建Bird对象p = Pandas()# 使用对象调用run()类方法,其实依然还是使用类调用,# 因此第1个参数依然被自动绑定到Pandas类p.run()# 使用对象调用printName静态方法,其实依然还是使用类调用,# 因此程序必须为第一个参数执行绑定p.printName('小团子')
从这段代码可以看出,使用@classmethod修饰的方法是类方法,该类方法定义了一个cls参数,该参数会被自动绑定到Pandas类本身,不管程序是使用类还是对象调用该方法,Python始终都会将类方法的第1个参数绑定到类本身。这段代码还使用 @staticmethod定义了一个静态方法,程序同样既可使用类调用静态方法,也可使用对象调用静态方法,不管用哪种方式调用,Python都不会为静态方法执行自动绑定。在使用 Python编程时,一般不需要使用类方法或静态方法,程序完全可以使用函数来代替类方法或静态方法。但是在特殊的场景(例如,使用工厂模式)下,类方法或静态方法也是不错的选择。3. 函数装饰器前面介绍的@staticmethod和@classmethod的本质就是函数装饰器,其中 staticmethod和classmethod都是 Python内置的函数。使用@符号引用已有的函数(比如@staticmethod和@classmethod)后,可用于修饰其他函数,装饰被修饰的函数。那么我们是否可以开发自定义的函数装饰器呢?答案是肯定的。当程序使用“@函数”(比如函数X)装饰另一个函数(比如函数Y)时,实际上完成如下两步:(1) 将被修饰的函数(函数Y)作为参数传给@符号引用的函数(函数A);(2)将函数Y替换(装饰)成第(1)步的返回值;从上面介绍不难看出,被“@函数”修饰的函数不再是原来的函数,而是被替换成一个新的东西。为了让大家更清楚函数装饰器的作用,下面看一个非常简单的示例。示例代码:decorator_demo.py
def funX(fn): print('X') fn() # 执行传入的fn参数 return 'Python''''下面装饰效果相当于:funX(funY),funY将会替换(装饰)成该语句的返回值;由于funX()函数返回Python,因此funB就是Python'''@funXdef funY(): print('funY')print(funY) # Python
上面程序使用@funX修饰funY,这意味着程序要完成如下两步操作:(1)将funY作为 funX的参数,也就是相当于执行funX(funY);(2) 将funY替换成第(1)步执行的结果,funX()执行完成后返回Python,因此funY就不再是函数,而是被替换成一个字符串;运行这段代码,可以看到如下输出结果:X funY Python通过这个例子,相信读者对函数装饰器的执行关系已经有了一个较为清晰的认识,但读者可能会产生另一个疑问:这个函数装饰器导致被修饰的函数变成了字符串,那么函数装饰器有什么用?别忘记了,被修饰的函数总是被替换成@符号所引用的函数的返回值,因此被修饰的函数会变成什么,完全由@符号所引用的函数的返回值决定。如果@符号所引用的函数的返回值是函数,那么被修饰的函数在替换之后还是函数。下面程序演示了更复杂的函数装饰器(接前面的程序)。
def process(fn): # 定义一个嵌套函数 def print_info(*args): print('-------1-------', args) n = args[0] print('-------2-------', n ** 3) # 查看传给process函数的fn函数 print(fn.__name__) fn(n * (n + 1)) print("*" * 20) return fn(n * (n - 1)) return print_info'''下面装饰效果相当于:process(my_value),my_value将会替换(装饰)成该语句的返回值;由于process()函数返回print_info函数,因此funY就是print_info'''@processdef my_value(a): print("-----my_value函数------", a)# 打印my_value函数,将看到实际上是bar函数print(my_value) ## 下面代码看上去是调用my_value(),其实是调用print_info()函数my_value(10)my_value(6, 5)
上面程序定义了一个装饰器函数process,该函数执行完成后并不是返回普通值,而是返回print_info函数(这是关键),这意味着被该@process修饰的函数最终都会被替换成print_info函数。上面程序使用@process修饰 my_value()函数,因此程序同样会执行process(my_value),并将 my_value替换成process函数的返回值print_info函数。所以,在这段代码中打印 my_value函数时,实际上输出的是print_info函数,这说明my_value已经被替换成print_info函数。接下来程序两次调用 my_value函数,实际上就是调用print_info函数。运行上面程序,可以看到如下输出结果:
<function process.<locals>.print_info at 0x7fb4880a55f0>-------1------- (10,)-------2------- 1000my_value-----my_value函数------ 110********************-----my_value函数------ 90-------1------- (6, 5)-------2------- 216my_value-----my_value函数------ 42********************-----my_value函数------ 30
通过@符号来修饰函数是 Python的一个非常实用的功能,它既可以在被修饰函数的前面添加些额外的处理逻辑(比如权限检查),也可以在被修饰函数的后面添加一些额外的处理逻辑(比如记录日志),还可以在目标方法抛出异常时进行一些修复操作。这种改变不需要修改被修饰函数的代码,只要增加一个修饰即可。其实前面介绍的这种在被修饰函数之前、之后、拋出异常后增加某种处理逻辑的方式,就是其他编程语言中的AOP( Aspect Orient Programming,面向切面编程)。下面例子示范了如何通过函数装饰器为函数添加权限检查的功能。程序代码如下:示例代码:auth_demo.py
def auth(fn): def verify_auth(*args): # 用一条语句模拟执行权限检查 print("----模拟执行权限检查----") # 回调要装饰的目标函数 fn(*args) return verify_auth@authdef test(a, b,c,d): print(f"执行test函数,参数a: {a}, 参数b: {b}, 参数d: {c},参数d: {d}" )# 调用test()函数,其实是调用装饰后返回的verify_auth函数test(123, 55, 135,66)
上面程序使用@auth修饰了test()函数,这会使得 test()函数被替换成 auth函数所返回的 verify_auth函数,而 verify_auth函数的执行流程如下:(1)先执行权限检查;(2)回调被修饰的目标函数;也就是说,verify_auth函数就为被修饰函数添加了一个权限检查的功能。运行该程序,,可以看到如下输出结果:
----模拟执行权限检查----执行test函数,参数a: 123, 参数b: 55, 参数d: 135,参数d: 66
-----------支持作者请转发本文-----------往期回顾:Python编程思想(21):原来函数内部还可以定义函数(局部函数)Python编程思想(22):Lambda表达式Python编程思想(23):类和对象Python编程思想(24):类的实例方法对本文感兴趣,可以加李宁老师微信公众号(unitymarvel):
关注 极客起源 公众号,获得更多免费技术视频和文章。
python 静态方法_Python编程思想(25):方法深度解析相关推荐
- python class 是否存在某个变量_Python编程思想(29):使用type()函数定义类
----------支持作者请转发本文-----------李宁老师已经在「极客起源」 微信公众号推出<Python编程思想>电子书,囊括了Python的核心技术,以及Python的主要函 ...
- div不继承父类样式_Python编程思想(27):类的继承
-----------支持作者请转发本文-----------李宁老师已经在「极客起源」 微信公众号推出<Python编程思想>电子书,囊括了Python的核心技术,以及Python的主要 ...
- 《Go语言精进之路,从新手到高手的编程思想、方法和技巧1》读书笔记和分享
Go语言精进之路,从新手到高手的编程思想.方法和技巧 读书分享 1 本书定位 2 本书内容总览 3 选择本书的原因 4 小收获分享 第7-12条 真的不知道咋命名 第13-19条 能用--怎么用更好 ...
- 几种常用编程语言的编程思想和方法 转
搞软件的人,编程语言的掌握是基本功,如果单单是学习语法,最慢的一周之内也应该可以搞定(个人认为 语法层面c++是最复杂的).不幸的是,软件的本质是逻辑,解决方案的设计是要借助某种解决问题或编程的思想的 ...
- python静态方法,类方法,属性方法,实例方法
DAY 3. 静态方法,类方法,属性方法,实例方法 有四种方法,实例方法,类方法,静态方法,属性方法 实例方法 实例方法的第一个参数是self,他会指向类的实例化对象,只能被对象调用,如 class ...
- python的缩进规则是什么意思_Python编程思想(2):Python主要特性、命名规则与代码缩进...
目录 那么什么是动态语言呢? 那么什么是弱类型语言和强类型语言呢? Python命名规则 缩进原则 李宁老师的<Python编程思想>上线了,囊括了Python的核心技术,以及Python ...
- python 清空所有对象_Python编程思想(7):列表的增删改操作
李宁老师已经在「极客起源」 微信公众号推出<Python编程思想>电子书,囊括了Python的核心技术,以及Python的主要函数库的使用方法.读者可以在「极客起源」 公众号中输入 160 ...
- python静态方法_Python静态方法
python静态方法 Python静态方法 (Python static method) In this quick post, we will learn how to create and use ...
- atom配置python环境_Python编程:用VScode配置Python开发环境
前言 VScode是一个相当优秀的IDE,具备开源.跨平台.模块化.插件丰富.启动时间快.颜值高.可高度定制等等优秀的特质,不愧是微软爸爸的私生子.所以用VScode来编写Python,也是相当的好用 ...
最新文章
- 能和LoadRunner匹敌的VS2010/2012Web负载测试
- wps临时文件不自动删除_电脑:让 Windows 10 系统自动清理临时文件
- http://www.ajaxload.info/
- 游戏王决斗连接显示服务器错误,游戏王决斗链接
- 怎样才能使用域名访问网站?
- 服务器构建系统发育树
- CUDA+Pycharm-gpu版本+Anaconda安装
- echoServer回显服务器
- Apollo Routing拓扑地图生成源码学习
- U盘保存文件未完成时拔掉U盘导致数据丢失的解决办法
- Java中 String s = new String(“hello“)和String s = “hello“的区别
- 植物肉品牌v2进军中国市场,带来牛肉糜、猪肉糜及牛肉汉堡饼等
- 采油工计算机试题库,数字化采油工题库完整.pdf
- mex文件生成c语言,用C语言编写MEX文件.doc
- 图像空域增强技术及联合运用
- 基于单片机的六层电梯设计
- 众安保险今正式上市,读懂其背后的黑科技就读懂其何为金融科技第一股
- 【硬件设计】如何玩转智能窗帘机器人
- 这一年,这些月,这些天
- Cesium 图片标注
热门文章
- 装Oracle10时报错,win10系统安装oracle10g时出现未知错误的详细教程
- java登陆session用法_Java web 登录 使用shiro和基于session的方式有何不同?
- mysql rr gap nextkey_mysql中的各种锁把我搞糊涂啦~
- pytorch保存模型运行时状态,记录点checkpoint
- Mysql授权用户数据库GRANT ON 数据库名.* TO 用户名@localhost identified BY ‘密码‘,报错ERROR 1064 (42000)
- python复现感知机的二分类算法
- matlab第七章符号对象,MATLAB语言:第七章 MATLAB符号计算
- [区块链] 密码学——Merkle 树
- cookie session token 之间的区别
- Android 手机卫士--解析json与消息机制发送不同类型消息