Is there a way to add an attribute to a function as part of the function definition?
每次调用函数时,函数属性
我在函数之外声明了属性
我使用queue.priorityqueue回答了这个问题,不关心使用"函数属性"进行比较,为priorityqueue的使用提供了一个独特的计数器-MartijnPieers提供了更好的解决方案)
MCVE:
1 2 3 4 5 6 7 8 9 10 11 | def do_something(): do_something.n += 1 return do_something.n # need to declare do_something.n before usign it, else # AttributeError: 'function' object has no attribute 'n' # on first call of do_something() occures do_something.n = 0 for _ in range(10): print(do_something()) # prints 1 to 10 |
还有什么其他方法可以定义函数"内部"的属性,以便在忘记它时避免使用
从评论中编辑了很多其他方式:
- 函数中静态变量的python等价物是什么?@熊熊
- 不使用martineau的"global"访问函数外部的函数变量
不完全在内部,但装饰器使函数属性更明显:
1 2 3 4 5 6 7 8 9 10 | def func_attr(**attrs): def wrap(f): f.__dict__.update(attrs) return f return wrap @func_attr(n=0) def do_something(): do_something.n += 1 return do_something.n |
这可能比将属性初始化放在函数中的任何内容都要干净。
使用内置的
1 2 3 4 5 | def do_something(): if not hasattr(do_something, 'n'): do_something.n = 1 do_something.n += 1 return do_something.n |
以下是关于
hasattr()vs try except块处理不存在的属性
还有两种方法。第一个类使用一些人称之为"functor"的类来创建一个具有所需属性的可调用类,这些属性都来自于类内。
这种方法不需要处理异常,因此唯一的运行时开销来自一次性创建它的单个实例。
1 2 3 4 5 6 7 8 9 10 11 12 13 | class do_something: def __init__(self): self.n = 0 def __call__(self, *args, **kwargs): do_something.n += 1 return do_something.n do_something = do_something() # Allow only one instance to be created. for _ in range(10): print(do_something()) # Prints 1 to 10. |
第二种方法——非常"Python式的"——是把功能放在一个模块中(实际上是单子模块)。这就是我的意思:
文件
1 2 3 4 5 6 | n = 0 def do_something(): global n n += 1 return n |
示例用法(在某些其他脚本中):
1 2 3 4 | from do_something import do_something for _ in range(10): print(do_something()) # Prints 1 to 10. |
当我把我对另一个问题的回答提给你时,我的脑海里就有这样的想法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | def with_this_arg(func): def wrapped(*args, **kwargs): return func(wrapped, *args, **kwargs) return wrapped @with_this_arg def do_something(this): if not getattr(this, 'n', None): this.n = 0 this.n += 1 return this.n for _ in range(10): print(do_something()) # prints 1 to 10 |
如果您更喜欢更"Python式"的EAFP编码方式,它的速度会稍微快一点,那么可以编写成thusly:
1 2 3 4 5 6 7 | @with_this_arg def do_something(this): try: this.n += 1 except AttributeError: # First call. this.n = 1 return this.n |
当然。。。
这可以与@user2357112的回答(如果按正确的顺序进行)结合成这样的内容,不需要检查或异常处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | def func_attr(**attrs): def wrap(f): f.__dict__.update(attrs) return f return wrap def with_this_arg(func): def wrapped(*args, **kwargs): return func(wrapped, *args, **kwargs) return wrapped @func_attr(n=0) @with_this_arg def do_something(this): this.n += 1 return this.n for _ in range(10): print(do_something()) # prints 1 to 10 |
我唯一能想到的方法是,遵循Python请求宽恕而不是许可的方法是:
1 2 3 4 5 6 7 | def do_something(): try: do_something.n += 1 except AttributeError: do_something.n = 1 return do_something.n |
这将在第一次调用时自动生成属性,之后,
有一些开销是由于