有没有办法将属性添加到函数中作为函数定义的一部分?

2024-04-24 08:12:54 发布

您现在位置:Python中文网/ 问答频道 /正文

每次调用函数时,函数属性do_something.n都会递增。你知道吗

我在函数外声明了属性do_something.n=0,这让我很烦恼。你知道吗

Ianswered问题Using queue.PriorityQueue, not caring about comparisons使用“函数属性”为PriorityQueue提供一个唯一的计数器-有一个nicer solution by MartijnPieters

MCVE公司:

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

还有什么其他方法可以定义函数的“内部”属性,以便在忘记它时避免AttributeError: 'function' object has no attribute 'n'?你知道吗


从评论中编辑了大量其他方式:


Tags: oftheto函数no属性objectfunction
3条回答

使用内置的hasattr函数怎么样?你知道吗

def do_something():
    if not hasattr(do_something, 'n'):
        do_something.n = 1
    do_something.n += 1
    return do_something.n 

作为参考,这里讨论了hasattrtry-except

hasattr() vs try-except block to deal with non-existent attributes

当我把你提到my answer另一个问题时,我就是这么想的:

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

如果您更喜欢“pythonic”EAFP风格的编码,它会稍微快一点,那么可以这样写:

@with_this_arg
def do_something(this):
    try:
        this.n += 1
    except AttributeError:  # First call.
        this.n = 1
    return this.n

当然

这可以与@user2357112的answer(如果按正确的顺序进行)组合成这样,不需要检查或异常处理:

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

不完全是内部的,但是decorator使函数属性更加明显:

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

这可能比将属性初始化放在函数中的任何东西都要干净。你知道吗

相关问题 更多 >