Python函数定义中的点表示法
Posted
技术标签:
【中文标题】Python函数定义中的点表示法【英文标题】:dot notation in Python's function definition 【发布时间】:2021-03-04 20:57:51 【问题描述】:我知道 Python 支持面向对象的结构,它使用点表示法。 但是,我对下面的代码感到困惑,其中点符号出现在没有定义类的函数定义中。 那是在 Python 中定义为函数属性 [我猜] 的某些特性吗?
def count(f):
def counted(*args):
counted.call_count += 1
return f(*args)
counted.call_count = 0
return counted
第二个问题:上面的代码是否可以改写为使用nonlocal语句而不是点符号来记录call_count?
【问题讨论】:
是的。函数也是可以具有属性的对象 函数属性被添加到PEP 232 并且功能与任何类相同。要使用非本地,只需创建一个call_count
变量并将nonlocal call_count
放在counted
函数的开头即可。
酷,这很有帮助,谢谢你们!
【参考方案1】:
如果您作为调用者不需要直接访问call_count
(例如,它仅由装饰器在内部使用),那么@chepner 显示的将是可行的方法。
问题在于,call_count
无法从外部访问。一些选项:
把它作为函数的一个属性。
但这不是一个好主意,因为只有一个函数对象在各处共享。如果你想在两个不同的地方独立计算同一个函数的调用,你会遇到问题。Pass 是一个可变容器,会被装饰器改变:
def count(count_container):
count_container[0] = 0
def inner(f):
def counted(*args):
count_container[0] += 1
return f(*args)
return counted
return inner
l = [0]
@count(l)
def f():
print("Test")
>>> l
[0]
>>> f()
Test
>>> f()
Test
>>> l
[2]
当然,这样做的缺点是,eww。即使您将列表替换为自定义 dataclass
之类的专用对象,这仍然很糟糕。
放弃使用@
表示法将其用作装饰器的想法。这为您提供了更多选择。
您可以保留当前代码,并手动传入函数:
def count(f):
def counted(*args):
counted.call_count += 1
return f(*args)
counted.call_count = 0
return counted
>>> counted = count(f)
>>> counted()
Test
>>> counted()
Test
>>> counted.call_count
2
这要好得多,因为对count
的每次显式调用都会返回一个new 函数,而不是像以前那样为单个全局函数赋予属性。如果您想同时跟踪两个单独的调用实例,您只需调用两次count
,然后保留每个返回的函数。
你也可以返回一个getter。使用@chepner 代码的修改版本:
def count(f):
call_count = 0
def counted(*args):
nonlocal call_count
call_count += 1
return f(*args)
return counted, lambda: call_count
>>> counted, counter_getter = count(f)
>>> counted()
Test
>>> counted()
Test
>>> counter_getter()
2
这里的主要好处是它允许调用者在他们想要阅读它时访问call_count
,但是它不给他们修改它的能力。
对不起,如果我在某处做了一些缩进。尝试在嵌套点列表中格式化代码是难以置信令人沮丧的。
【讨论】:
我在您的第 3 项中尝试了两种不同的方法,它们都有效。具有两个函数的元组作为返回的非本地函数看起来很有趣,它解决了我的问题。阅读您的代码我没有任何问题。非常感谢!【参考方案2】:闭包比函数属性更健壮。可以想象,您可以将counted
绑定到其他东西,然后counted.call_count
将不再是您想要的属性。
def count(f):
call_count = 0
def counted(*args):
nonlocal call_count
call_count += 1
return f(*args)
return counted
每次调用count
,都会创建一个新变量call_count
。在count
返回后,对这个变量的唯一引用是在counted
的主体内,而不是(很容易)对任何引用counted
的东西可见。
【讨论】:
我在调用 count(f) 后无法获取 call_count 信息。请问执行后如何获取call_count?以上是关于Python函数定义中的点表示法的主要内容,如果未能解决你的问题,请参考以下文章