使用函数属性是好习惯吗?

Is it good practice to use function attributes?

我最近在 python 中发现了函数属性。在闭包和嵌套函数中使用这些属性是一种好习惯,尤其是从内部函数更改这些属性吗? 'better' 比使用 nonlocal 好吗?

例如-

def combination_lock(*args):
    combination_lock.index = 0
    code = [*args]
    combination_lock.state = True
    def inner(num):
        if code[combination_lock.index] != num:
            combination_lock.state = False
        if combination_lock.index == len(code) - 1:
            return combination_lock.state
        else:
            combination_lock.index += 1
        return inner
    return inner
f=combination_lock(1,2,3,4)
f(1)(2)(3)(4)  # -> will return True
f(2)(1)(3)(4)  # -> will return False
f(1)(1)(1)(1)  # -> will return False

函数combination_lock接收整数序列,returns函数一次获取一个整数(整数个数与序列长度完全相同),并检查它们是否匹配初始序列。

如您所见,我使用了一个布尔标志来指示当前 int 是否与序列匹配,以及增加每次调用内部函数的索引属性。

是否有更 Pythonic 的方式来做到这一点?

简而言之答案是NO,使用函数属性不是pythonic,除非它们是在整个程序中不会改变的常量,例如数学常量或错误代码或文档。

主要问题是您的内部函数返回函数或布尔值...这非常令人困惑并且会导致错误

f=combination_lock(1,2,3,4)
f(1)(2)(3)(4)  # -> will return True
f(2)(1)(3)(4)  # -> will raise error because (2) returns bool
f(1)(1)(1)(1)  # -> will raise error because (1) returns bool

第二个问题主要与内存有关,因为您的 combination_lock.indexf 的所有已创建实例之间共享,这使得调试甚至难以正常工作,这就是不推荐的原因使用函数属性,除非它们是常量。

你试图用函数属性实现的是存储数据,而这正是 classes 的目的,你可以重载 __call__ 运算符以像函数一样工作.

并且为了分离 indexstate 的内部状态,您可以创建一个内部 class 来跟踪它们,当您调用 main class,另一个 class 将处理后续调用。

class combination_lock: # class to hold the code

    class evaluator: # inner class to hold index and state
        def __init__(self,code):
            self.code = code
            self.index = 0
            self.state = True

        # will be called every successive time after the first.
        def __call__(self, num): 
            if self.code[self.index] != num:
                self.state = False
            if self.index == len(self.code) - 1:
                return self.state
            else:
                self.index += 1
            return self

    def __init__(self,*args):
        self.code = [*args]

    def __call__(self,num): # will be called only the first time
        evaluator = self.evaluator(self.code)
        return evaluator(num)

f=combination_lock(1,2,3,4)
print(f(1)(2)(3)(4))  # -> will print True
print(f(2)(1)(3)(4))  # -> will print False
print(f(1)(1)(1)(1))  # -> will print False

它的代码比你的多很多,但它稍微更清晰和可调试,并且可以说是 pythonic,但它仍然容易出错,我会向它添加大量错误处理,但至少它现在是线程安全的,所以您可以在任何线程上创建大量组合锁,您将确保它们都按预期工作。