使用函数属性是好习惯吗?
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.index
在 f
的所有已创建实例之间共享,这使得调试甚至难以正常工作,这就是不推荐的原因使用函数属性,除非它们是常量。
你试图用函数属性实现的是存储数据,而这正是 classes 的目的,你可以重载 __call__
运算符以像函数一样工作.
并且为了分离 index
和 state
的内部状态,您可以创建一个内部 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,但它仍然容易出错,我会向它添加大量错误处理,但至少它现在是线程安全的,所以您可以在任何线程上创建大量组合锁,您将确保它们都按预期工作。
我最近在 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.index
在 f
的所有已创建实例之间共享,这使得调试甚至难以正常工作,这就是不推荐的原因使用函数属性,除非它们是常量。
你试图用函数属性实现的是存储数据,而这正是 classes 的目的,你可以重载 __call__
运算符以像函数一样工作.
并且为了分离 index
和 state
的内部状态,您可以创建一个内部 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,但它仍然容易出错,我会向它添加大量错误处理,但至少它现在是线程安全的,所以您可以在任何线程上创建大量组合锁,您将确保它们都按预期工作。