-----------支持作者请转发本文-----------李宁老师已经在「极客起源」 微信公众号推出《Python编程思想》电子书,囊括了Python的核心技术,以及Python的主要函数库的使用方法。读者可以在「极客起源」 公众号中输入 160442 开始学习。-----------正文-----------方法是类或对象行为的抽象,但 Python的方法本章上也是函数,其定义方式、调用方式和函数都非常相似,因此 Python的方法并不仅仅是单纯的方法,它与函数也有莫大的关系。1.  在类中调用实例方法在前面的文章讲过,在 Python的类体中定义的方法默认都是实例方法,前面也示范了通过对象来调用实例方法。但要提醒大家的是,Python的类在很大程度上是一个命名空间。当程序在类体中定义变量、定义方法时,与前面介绍的定义变量、定义函数其实并没有太大的不同。对比如下代码。示例代码:class_demo1.py

# 定义全局空间的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):方法深度解析相关推荐

  1. python class 是否存在某个变量_Python编程思想(29):使用type()函数定义类

    ----------支持作者请转发本文-----------李宁老师已经在「极客起源」 微信公众号推出<Python编程思想>电子书,囊括了Python的核心技术,以及Python的主要函 ...

  2. div不继承父类样式_Python编程思想(27):类的继承

    -----------支持作者请转发本文-----------李宁老师已经在「极客起源」 微信公众号推出<Python编程思想>电子书,囊括了Python的核心技术,以及Python的主要 ...

  3. 《Go语言精进之路,从新手到高手的编程思想、方法和技巧1》读书笔记和分享

    Go语言精进之路,从新手到高手的编程思想.方法和技巧 读书分享 1 本书定位 2 本书内容总览 3 选择本书的原因 4 小收获分享 第7-12条 真的不知道咋命名 第13-19条 能用--怎么用更好 ...

  4. 几种常用编程语言的编程思想和方法 转

    搞软件的人,编程语言的掌握是基本功,如果单单是学习语法,最慢的一周之内也应该可以搞定(个人认为 语法层面c++是最复杂的).不幸的是,软件的本质是逻辑,解决方案的设计是要借助某种解决问题或编程的思想的 ...

  5. python静态方法,类方法,属性方法,实例方法

    DAY 3. 静态方法,类方法,属性方法,实例方法 有四种方法,实例方法,类方法,静态方法,属性方法 实例方法 实例方法的第一个参数是self,他会指向类的实例化对象,只能被对象调用,如 class ...

  6. python的缩进规则是什么意思_Python编程思想(2):Python主要特性、命名规则与代码缩进...

    目录 那么什么是动态语言呢? 那么什么是弱类型语言和强类型语言呢? Python命名规则 缩进原则 李宁老师的<Python编程思想>上线了,囊括了Python的核心技术,以及Python ...

  7. python 清空所有对象_Python编程思想(7):列表的增删改操作

    李宁老师已经在「极客起源」 微信公众号推出<Python编程思想>电子书,囊括了Python的核心技术,以及Python的主要函数库的使用方法.读者可以在「极客起源」 公众号中输入 160 ...

  8. python静态方法_Python静态方法

    python静态方法 Python静态方法 (Python static method) In this quick post, we will learn how to create and use ...

  9. atom配置python环境_Python编程:用VScode配置Python开发环境

    前言 VScode是一个相当优秀的IDE,具备开源.跨平台.模块化.插件丰富.启动时间快.颜值高.可高度定制等等优秀的特质,不愧是微软爸爸的私生子.所以用VScode来编写Python,也是相当的好用 ...

最新文章

  1. 能和LoadRunner匹敌的VS2010/2012Web负载测试
  2. wps临时文件不自动删除_电脑:让 Windows 10 系统自动清理临时文件
  3. http://www.ajaxload.info/
  4. 游戏王决斗连接显示服务器错误,游戏王决斗链接
  5. 怎样才能使用域名访问网站?
  6. 服务器构建系统发育树
  7. CUDA+Pycharm-gpu版本+Anaconda安装
  8. echoServer回显服务器
  9. Apollo Routing拓扑地图生成源码学习
  10. U盘保存文件未完成时拔掉U盘导致数据丢失的解决办法
  11. Java中 String s = new String(“hello“)和String s = “hello“的区别
  12. 植物肉品牌v2进军中国市场,带来牛肉糜、猪肉糜及牛肉汉堡饼等
  13. 采油工计算机试题库,数字化采油工题库完整.pdf
  14. mex文件生成c语言,用C语言编写MEX文件.doc
  15. 图像空域增强技术及联合运用
  16. 基于单片机的六层电梯设计
  17. 众安保险今正式上市,读懂其背后的黑科技就读懂其何为金融科技第一股
  18. 【硬件设计】如何玩转智能窗帘机器人
  19. 这一年,这些月,这些天
  20. Cesium 图片标注

热门文章

  1. 装Oracle10时报错,win10系统安装oracle10g时出现未知错误的详细教程
  2. java登陆session用法_Java web 登录 使用shiro和基于session的方式有何不同?
  3. mysql rr gap nextkey_mysql中的各种锁把我搞糊涂啦~
  4. pytorch保存模型运行时状态,记录点checkpoint
  5. Mysql授权用户数据库GRANT ON 数据库名.* TO 用户名@localhost identified BY ‘密码‘,报错ERROR 1064 (42000)
  6. python复现感知机的二分类算法
  7. matlab第七章符号对象,MATLAB语言:第七章 MATLAB符号计算
  8. [区块链] 密码学——Merkle 树
  9. cookie session token 之间的区别
  10. Android 手机卫士--解析json与消息机制发送不同类型消息