Python 函数自定义属性 及 __code__

函数进阶

Python 是面向对象的语言,在 Python中一切皆对象。函数自然也不例外。

它有属于对象的属性,除此之外,函数还可以自定义属性。注意,属性是和对象相关的,和作用域无关

注意:这里说的是函数(function类型)的特殊属性,而非方法(method类型)的特殊属性。

自定义属性

函数自定义属性的方式很简单,假设函数名为 myfunc

# 设置属性
myfunc.version = 'V1.0.1'

# 访问属性
print(myfunc.version)

这个属性 version 可以像全局变量一样被访问,修改。但它并不是全局变量

查看函数对象属性

# 查看函数全部属性
dir(myfunc)

['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
  • __doc__:用于获取函数的说明文档,没有则返回 None
  • __name__:获取函数的名称
  • __defaults__:以元组形式返回函数的默认参数,没有则返回 None
  • __dict__:以字典的形式返回函数中自定义的属性
  • __code__:返回已编译的函数对象

_code_

print(myfunc.__code__)

# <code object test at 0x00000000021491E0, file "demo.py", line 3>

上面的输出结果已经指明了 __code__ 也是对象,在这个函数对象里,我们可以看到字节码,元数(也就是参数数量)和一些与函数相关的其他东西。

print(dir(myfunc.__code__))

# [... , 'co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_kwonlyargcount', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_stacksize', 'co_varnames']

现在就可以看到函数对象相关的属性,其中有一类属性都以 co_ 开头,表示字节码的意思。实际上,并非只有函数具有这些属性,所有的代码块(code block)都有这些属性

def myfunc(a, b=2):
    a = 'hello'
    b = 'world'

# 打印这些以 co 开头的属性的值

for attr in dir(myfunc.__code__):
    if attr.startswith('co_'):
        print(f'{attr}: {getattr(test.__code__, attr)}')

# co_argcount: 2
# co_cellvars: ()
# co_code: b'd\x01}\x00d\x02}\x01d\x00S\x00'
# co_consts: (None, 'hello', 'world')
# co_filename: C:/Users/Administrator/Desktop/demo.py
# co_firstlineno: 3
# co_flags: 67
# co_freevars: ()
# co_kwonlyargcount: 0
# co_lnotab: b'\x00\x01\x04\x01'
# co_name: myfunc
# co_names: ()
# co_nlocals: 2
# co_stacksize: 1
# co_varnames: ('a', 'b')
# 使用 dis 模块的 show_code() 函数来输出这些信息的整理

import dis
dis.show_code(myfunc)

# Name:              myfunc
# Filename:          C:/Users/Administrator/Desktop/demo.py
# Argument count:    2
# Kw-only arguments: 0
# Number of locals:  2
# Stack size:        1
# Flags:             OPTIMIZED, NEWLOCALS, NOFREE
# Constants:
#    0: None
#    1: 'hello'
#    2: 'world'
# Variable names:
#    0: a
#    1: b

研究 __code__ 是了解 Python 函数如何运行的最好办法。例如,函数 foo 的元数是由 foo.__code__.co_argcount获得,而字码节存在于 foo.__code__.co_code

__code__对象的属性是只读,但是 __code__属性本身不是!我们可以使用下面的代码整蛊一下朋友

def cat():
    print('I am a cat!')
          
def dog():
    print('I am a dog!')
          
cat.__code__ = dog.__code__

现在,当我们运行 cat() 时,实际上运行的是 dog 的代码,于是我们会得到:

I am a dog!
  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值