- 主题:[求助]这段effective python代码中*args, **kwargs的解析原理是
最近在看effective python原版第2版,看到元类最后一个关于引入类装饰器的例子,代码如下:
我原本一直以为自己了解*args, **kwargs是怎么解析的,但看到这个运行结果后就迷惑了……
比如这句:trace_dict = TraceDict([('hi', 1)])
应该是触发初始化__init__,kwargs为空字典,但args最后打印出来怎么变成这个元组了:({'hi': 1}, [('hi', 1)]),我理解的应该只包含[('hi', 1)],前面那个元素{'hi': 1}估计是从super().__init__中解析出来的,直观上应该是dict类输入一个[(key1,value1),(key2,value2),...]这样的列表,然后dict类整合成一个字典数据结构,可我不明白args怎么变了……
from functools import wraps
def trace_func(func):
if hasattr(func, 'tracing'):
return func
@wraps(func)
def wrapper(*args, **kwargs):
result = None
try:
result = func(*args, **kwargs)
return result
except Exception as e:
result = e
raise
finally:
print(f'{func.__name__}({args!r}, {kwargs!r}) -> {result!r}')
wrapper.tracing = True
return wrapper
class TraceDict(dict):
@trace_func
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@trace_func
def __setitem__(self, *args, **kwargs):
return super().__setitem__(*args, **kwargs)
@trace_func
def __getitem__(self, *args, **kwargs):
return super().__getitem__(*args, **kwargs)
trace_dict = TraceDict([('hi', 1)])
trace_dict['there'] = 2
trace_dict['hi']
try:
trace_dict['does not exist']
except KeyError:
pass
else:
assert False
--
FROM 113.247.67.*
那个字典是 self 。。。
【 在 gzq830510 (圡圡的包子——月如挚爱) 的大作中提到: 】
: 最近在看effective python原版第2版,看到元类最后一个关于引入类装饰器的例子,代码如下:
: 我原本一直以为自己了解*args, **kwargs是怎么解析的,但看到这个运行结果后就迷惑了……
: 比如这句:trace_dict = TraceDict([('hi', 1)])
: ...................
--
FROM 114.242.94.*
那个 TraceDict([('hi', 1)]) 的调用,本质上传了两个参数:
一个是 self
一个是 [('hi', 1)]
在 wrapper 看来,args 就是 (self, [('hi', 1)])
在 wrapper 里调用 func 参数也是 (self, [('hi', 1)])
到了 func 也就是 __init__ 里,self 就是那个 self,args 只剩下 ([('hi', 1)],) 了
你可以加上绿的那句话看看
然后由于 finally 里 print 的时候这个 TraceDict 已经构造完了,所以打出来的 self
就有值了
【 在 gzq830510 (圡圡的包子——月如挚爱) 的大作中提到: 】
from functools import wraps
def trace_func(func):
if hasattr(func, 'tracing'):
return func
@wraps(func)
def wrapper(*args, **kwargs):
result = None
try:
result = func(*args, **kwargs)
return result
except Exception as e:
result = e
raise
finally:
print(f'{func.__name__}({args!r}, {kwargs!r}) -> {result!r}')
wrapper.tracing = True
return wrapper
class TraceDict(dict):
@trace_func
def __init__(self, *args, **kwargs):
# print(f'{args!r})
super().__init__(*args, **kwargs)
@trace_func
def __setitem__(self, *args, **kwargs):
return super().__setitem__(*args, **kwargs)
@trace_func
def __getitem__(self, *args, **kwargs):
return super().__getitem__(*args, **kwargs)
trace_dict = TraceDict([('hi', 1)])
trace_dict['there'] = 2
trace_dict['hi']
try:
trace_dict['does not exist']
except KeyError:
pass
else:
assert False
--
FROM 114.242.94.*
谢谢指点,确实是这样的~我把关注的焦点放到了*args的解析原理上,以为是有什么特殊的没注意到,没想到是因为wrapper中的args和 __init__中的args并不相同,前者中的args其实相当于self + 后者的args
【 在 wincss 的大作中提到: 】
: 那个 TraceDict([('hi', 1)]) 的调用,本质上传了两个参数:
: 一个是 self
: 一个是 [('hi', 1)]
: ...................
--
FROM 113.247.67.*
print(f'{args!r})
!r 是什么?第一次见到
--
FROM 113.111.180.*
f-string
【 在 mv008 (mv008) 的大作中提到: 】
: print(f'{args!r})
: !r 是什么?第一次见到
--
FROM 123.122.94.9
!r相当于调用repr()
【 在 mv008 的大作中提到: 】
: print(f'{args!r})
: !r 是什么?第一次见到
--
FROM 36.157.228.*