百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

Python之函数高级:函数深度剖析,一次性搞懂函数对象

off999 2024-09-21 20:49 46 浏览 0 评论

引言

在之前的系列文章中,我们介绍过了函数的常见用法,以及Python中一切皆对象,函数也是对象的概念。在函数高级的前两篇文章中,我们回顾并补充论述了函数对象是一等公民,以及Python中的高阶函数的概念。

为了为后续对Python中闭包内容的介绍打基础,今天的文章中,我打算换个角度,深入剖析下函数对象的内部构成。

本文的主要内容有:

1、函数对象的主要属性

2、函数对象的主要方法

3、函数对象中的代码在哪里


函数对象的主要属性

函数在Python中是作为对象的存在的,对象一般会有相应的属性和方法,我们首先来看下Python中有哪些主要的属性,从而更加清晰地理解函数对象。

首先看下函数对象所属类的定义:

从定义中可以看出,Python中的函数对象有这么几个属性,简单列举说明一下:

1、__name__:字符串类型,存储的是函数对象的名称。

2、__qualname__:字符串类型,存储的是方法对应的函数对象的全限定名。

3、__module__:函数对象所在的模块的名称

3、__defaults__:以元组形式存储函数对象中位置参数的默认值。

4、__kwdefaults__:以字典形式存储函数对象中的强制关键字参数的默认值。

5、__globals__:property属性,存储函数对象所在的全局命名空间的名字绑定的字典。

6、__closure__:property属性,存储函数对象构建的闭包中的自由元素(自由变量、内部函数对象)。

7、__code__:存储函数编译后的字节码和其他相关信息。

接下来演示下相关函数对象的属性,直接看代码:

首先看入口文件中定义的函数对象的相关属性情况:

from rich.pretty import pprint as print

a = 20


def add(n=1000, *, m=23000):
    b = 10
    c = 20
    return a + n


print(add.__name__)
print(add.__qualname__)
print(add.__module__)
print(add.__defaults__)
print(add.__kwdefaults__)
print(add.__code__)
print(add.__closure__)
print(add.__globals__)
# 与globals()返回的全局命名空间中的名字对象绑定的字典对象是同一个对象
print(add.__globals__ is globals())

执行结果:

然后,我们定义一个名为m1.py的模块:

a = 8888


def add(a, b):
		return a + b


class Test:
    def hello(self):
        print(self)

然后,我们在入口文件导入该模块,查看m1模块中的add()函数的属性:

import m1

a = 100

print(m1.add.__name__)
print(m1.add.__qualname__)
print(m1.add.__module__)
print(m1.add.__defaults__)
print(m1.add.__kwdefaults__)
print(m1.add.__code__)
print(m1.add.__closure__)
# 与globals()返回的全局命名空间中的名字对象绑定的字典对象是同一个对象
print(m1.add.__globals__ is globals())
# __globals__中的内容有点多,只看下我们关心的内容
print({kk: vv for kk, vv in m1.add.__globals__.items() if not kk.startswith('_')})
# globals()中的内容,只看我们关心的内容
print({kk: vv for kk, vv in globals().items() if not kk.startswith('_')})

执行结果:

最后我们再看一下特殊的函数对象,即类中方法的相关属性:

import m1

a = 100

test = m1.Test()
print(test.hello.__name__)
print(test.hello.__qualname__)
print(test.hello.__module__)
print(test.hello.__defaults__)
print(test.hello.__kwdefaults__)
print(test.hello.__code__)
print(test.hello.__closure__)
# 与globals()返回的全局命名空间中的名字对象绑定的字典对象是同一个对象
print(test.hello.__globals__ is globals())
# __globals__中的内容有点多,只看下我们关心的内容
print({kk: vv for kk, vv in test.hello.__globals__.items() if not kk.startswith('_')})
# globals()中的内容,只看我们关心的内容
print({kk: vv for kk, vv in globals().items() if not kk.startswith('_')})

执行结果:


从入口文件中定义的函数、导入模块中的函数,以及类中的方法,这三种不同的函数对象的实际代码演示,我们再稍微总结一下函数对象中的属性相关内容:

1、__name__在三种函数对象中都是函数定义时的名称

2、__qualname__只有在类中定义的方法中,变为“类名.方法名”的形式,其他情况都与__name__属性相同。

3、__defaults__和__kwdefaults__的区别在于,前者存储位置参数的默认值,是一个元组形式,而后者存储的是函数定义中,在*之后定义的强制关键字形式传递的参数的默认值,是以字典形式存在的。

4、__globals__属性,是定义该函数对象的全局命名空间对应的字典对象,所以,入口文件中定义的函数的__globals__属性与入口文件中的globals()返回的字典是同一个对象。而模块中定义的函数的__global__属性存储的是模块对应的全局命名空间所对应的字典对象,与入口文件的globals()返回的字典对象不同。

5、__closure__属性,会用于存储闭包中的自由变量及内部函数对象,从而使得闭包得以建立,这个会在后面的闭包内容中进一步展开。

6、__code__属性,存储函数定义相关代码编译为的字节码对象,本文会稍后进一步展开。


函数对象的主要方法

看完了函数对象中的比较重要的属性,接下来,我们看下函数对象的两个方法:__init__()和__call__()方法。

首先看下__init__()方法的描述:

从函数对象的__init__()初始化方法的相关定义,我们是否能通过别的方式初始化一个函数对象呢?

接下来,我们尝试基于一个已经定义好的函数的相关属性,作为参数,重新初始化一个新的函数对象。

直接看代码:

a = 10
b = 20


def add(n1, n2):
		return a + b + n1 + n2


# 通过函数对象的__class__属性获取函数类,然后进行对象的实例化
# 也可以通过type(add)获取函数对象的类,进行对象的实例化,效果是一样的
# new_add = type(add)(code=add.__code__, globals={'a': 100, 'b': 200}, name='new_add')
new_add = add.__class__(code=add.__code__, globals={'a': 100, 'b': 200}, name='new_add')
print(add)
print(add.__name__)
print(add.__code__)
print(add(1, 2))
print(new_add)
print(new_add.__name__)
print(new_add.__code__)
print(new_add(1, 2))

执行结果:

从执行结果可以看出:

1、除了通过def关键字实例化函数对象,我们也可以通过函数对象所属类进行一个函数对象的实例化。

2、两个函数对象可以指向通过一个字节码对象,表示执行相同的计算逻辑。

3、通过def关键字实例化的函数对象的__globals__属性,即为函数定义当前的全局命名空间对应的字典对象,无法修改。

4、通过手动实例化函数对象的方式,我们可以通过globals关键字传参,来手工指定函数对象的__globals__属性,从而实现,函数对象的计算逻辑在不同的命名空间中执行的效果。


函数对象中还有一个__call__()方法,这个方法之前其实已经介绍过,我们调用函数,其实有两种方式,一种是函数名()来进行调用。另外一种可以通过函数名.__call__()的方式进行调用。

这两种方式本质上是一样的。就不再展开了,感兴趣的同学可以自行尝试。


函数对象中的代码在哪里

通过前面内容的介绍,我们可以发现,函数对象的核心在于存储计算逻辑的__code__属性,以及存储函数执行的上下文环境对应的__globals__属性。两者的不同组合,可以实现函数对象的实际执行的多样性。

接下来我们来进一步看一下存储函数对象代码的__code__属性。

首先看代码:

a = 20


def add(n=1000, *, m=23000):
    b = 10
    c = 20
    return a + n


code = add.__code__
print(code.__class__)
print(code.co_name)
print(code.co_argcount)
print(code.co_kwonlyargcount)
print(code.co_nlocals)
print(code.co_varnames)
print(code.co_names)
print(code.co_consts)
print(code.co_stacksize)
print(code.co_code)

执行结果:

简单解释一下code对象的相关属性:

1、co_name:存储函数的名字,通常情况下与函数对象的__name__相同。

2、co_argcount:存储函数的位置参数的个数,代码示例中只有一个n。

3、co_kwonlyargcount:存储函数的强制关键字传参的参数个数,代码中只有一个m。

4、co_nlocals:存储函数中的局部变量的个数,代码示例中为4个,局部变量包括函数的参数及函数内部定义的局部变量。

5、co_varnames:存储函数中的局部变量的名称的元组,这里是n, m, b, c。

6、co_names:存储函数中使用的全局变量的名称的元组,这里只有a。

7、co_consts:存储函数中使用的常量的元组,这里有None、10、20。

8、co_stacksize:存储函数执行所需要的栈空间,这里是2。

9、co_code:存储函数执行的代码所编译为的字节码。


总结

本文重点介绍了函数对象中的比较重要的属性,以及通过函数类进行函数对象的实例化,然后展开介绍了函数属性中的__code__属性中的相关属性,从而对Python中的函数对象有了更深入的理解。


感谢您的拨冗阅读,希望对您学习Python能有些许帮助。

相关推荐

安全教育登录入口平台(安全教育登录入口平台官网)

122交通安全教育怎么登录:122交通网的注册方法是首先登录网址http://www.122.cn/,接着打开网页后,点击右上角的“个人登录”;其次进入邮箱注册,然后进入到注册页面,输入相关信息即可完...

大鱼吃小鱼经典版(大鱼吃小鱼经典版(经典版)官方版)

大鱼吃小鱼小鱼吃虾是于谦跟郭麒麟的《我的棒儿呢?》郭德纲说于思洋郭麒麟作诗的相声,最后郭麒麟做了一首,师傅躺在师母身上大鱼吃小鱼小鱼吃虾虾吃水水落石出师傅压师娘师娘压床床压地地动山摇。...

谷歌地球下载高清卫星地图(谷歌地球地图下载器)
  • 谷歌地球下载高清卫星地图(谷歌地球地图下载器)
  • 谷歌地球下载高清卫星地图(谷歌地球地图下载器)
  • 谷歌地球下载高清卫星地图(谷歌地球地图下载器)
  • 谷歌地球下载高清卫星地图(谷歌地球地图下载器)
哪个软件可以免费pdf转ppt(免费的pdf转ppt软件哪个好)
哪个软件可以免费pdf转ppt(免费的pdf转ppt软件哪个好)

要想将ppt免费转换为pdf的话,我们建议大家可以下一个那个wps,如果你是会员的话,可以注册为会员,这样的话,在wps里面的话,就可以免费将ppt呢转换为pdfpdf之后呢,我们就可以直接使用,不需要去直接不需要去另外保存,为什么格式转...

2026-02-04 09:03 off999

电信宽带测速官网入口(电信宽带测速官网入口app)

这个网站看看http://www.swok.cn/pcindex.jsp1.登录中国电信网上营业厅,宽带光纤,贴心服务,宽带测速2.下载第三方软件,如360等。进行在线测速进行宽带测速时,尽...

植物大战僵尸95版手机下载(植物大战僵尸95 版下载)

1可以在应用商店或者游戏平台上下载植物大战僵尸95版手机游戏。2下载教程:打开应用商店或者游戏平台,搜索“植物大战僵尸95版”,找到游戏后点击下载按钮,等待下载完成即可安装并开始游戏。3注意:确...

免费下载ppt成品的网站(ppt成品免费下载的网站有哪些)

1、Chuangkit(chuangkit.com)直达地址:chuangkit.com2、Woodo幻灯片(woodo.cn)直达链接:woodo.cn3、OfficePlus(officeplu...

2025世界杯赛程表(2025世界杯在哪个国家)

2022年卡塔尔世界杯赛程公布,全部比赛在卡塔尔境内8座球场举行,2022年,决赛阶段球队全部确定。揭幕战于当地时间11月20日19时进行,由东道主卡塔尔对阵厄瓜多尔,决赛于当地时间12月18日...

下载搜狐视频电视剧(搜狐电视剧下载安装)

搜狐视频APP下载好的视频想要导出到手机相册里方法如下1、打开手机搜狐视频软件,进入搜狐视频后我们点击右上角的“查找”,找到自已喜欢的视频。2、在“浏览器页面搜索”窗口中,输入要下载的视频的名称,然后...

pubg免费下载入口(pubg下载入口官方正版)
  • pubg免费下载入口(pubg下载入口官方正版)
  • pubg免费下载入口(pubg下载入口官方正版)
  • pubg免费下载入口(pubg下载入口官方正版)
  • pubg免费下载入口(pubg下载入口官方正版)
永久免费听歌网站(丫丫音乐网)

可以到《我爱音乐网》《好听音乐网》《一听音乐网》《YYMP3音乐网》还可以到《九天音乐网》永久免费听歌软件有酷狗音乐和天猫精灵,以前要跳舞经常要下载舞曲,我从QQ上找不到舞曲下载就从酷狗音乐上找,大多...

音乐格式转换mp3软件(音乐格式转换器免费版)

有两种方法:方法一在手机上操作:1、进入手机中的文件管理。2、在其中选择“音乐”,将显示出手机中的全部音乐。3、点击“全选”,选中所有音乐文件。4、点击屏幕右下方的省略号图标,在弹出菜单中选择“...

电子书txt下载(免费的最全的小说阅读器)

1.Z-library里面收录了近千万本电子书籍,需求量大。2.苦瓜书盘没有广告,不需要账号注册,使用起来非常简单,直接搜索预览下载即可。3.鸠摩搜书整体风格简洁清晰,书籍资源丰富。4.亚马逊图书书籍...

最好免费观看高清电影(播放免费的最好看的电影)

在目前的网上选择中,IMDb(互联网电影数据库)被认为是最全的电影网站之一。这个网站提供了各种类型的电影和电视节目的海量信息,包括剧情介绍、演员表、评价、评论等。其还提供了有关电影制作背后的详细信息,...

孤单枪手2简体中文版(孤单枪手2简体中文版官方下载)

要将《孤胆枪手2》游戏的征兵秘籍切换为中文,您可以按照以下步骤进行操作:首先,打开游戏设置选项,通常可以在游戏主菜单或游戏内部找到。然后,寻找语言选项或界面选项,点击进入。在语言选项中,选择中文作为游...

取消回复欢迎 发表评论: