Python:向函数传递标志
很长一段时间以来,我一直试图找出向python函数传递标志的最佳方式。最直接的方法是:Python:向函数传递标志,python,Python,很长一段时间以来,我一直试图找出向python函数传递标志的最佳方式。最直接的方法是: def func(data, flag1, flag2, flag3): ... func(my_data, True, False, True) func(my_data, flag1, flag3) 这真的很好,很简洁,但是很难理解,因为单词“真”或“假”并没有告诉你设置了什么标志,你必须仔细地从左边开始计算参数。您可以将它们设置为关键字参数: def func(data, flag1=Fa
def func(data, flag1, flag2, flag3):
...
func(my_data, True, False, True)
func(my_data, flag1, flag3)
这真的很好,很简洁,但是很难理解,因为单词“真”或“假”并没有告诉你设置了什么标志,你必须仔细地从左边开始计算参数。您可以将它们设置为关键字参数:
def func(data, flag1=False, flag2=False, flag3=False):
...
func(my_data, flag1=True, flag3=True)
但这有点多余,因为“真”根本没有任何意义。我可以将其作为列表传递:
func(mydata, ['flag1', 'flag3'])
或
但是第一种感觉相当脏,使用字符串作为标志,第二种感觉仍然有些重复。理想情况下,我想说:
def func(data, flag1, flag2, flag3):
...
func(my_data, True, False, True)
func(my_data, flag1, flag3)
以最小的冗余度和冗余度将标志传递给函数。在python中有没有类似的方法
编辑:
我最终选择了:
func(mydata, flagA=1, flagB=1)
主要是因为上面提到的原因:编译时检查(相对于传入字符串)、无命名空间污染(相对于使用全局“ENUM”和最小样板文件(=1或=0仅为2个字符,而=True或=False为5或6个字符)。它还使设置标志的默认值变得非常容易:
def func(data, flagA=1, flagB=0, flagC=1):
...
这比跳圈提取和指定**kwarg风格旗帜的默认值要清晰和容易得多。标记基本上是静态检查的,写起来非常清晰/干净。现在,如果我能用*args删除最后两个字符就好了…:
def some_func(data, *args):
# do something
return args # this is just to show how it works
>>> print some_func(12, 'test', 'test2', 'test3')
('test', 'test2', 'test3')
要理解*args和**kwargs的工作原理,这是一个很好的问题:您可以将
flag1
..flagN
定义为全局变量,并使用func(*args)
通过单独定义标志,而不是使用字符串,可以避免标志名称中的打字错误和调试时的一些头痛问题我更喜欢没有标志的函数。而是这样做:
def func_flag1(arg):
pass # something useful
def func_flag2(arg):
pass # something for flag 2.
但“flagX”实际上是一些有意义的东西,比如“douuxuwithuoption”
我更喜欢这样做,因为这样更清晰,函数更简单(bug更少),并且不必将一些常量带入其他模块(在标志实际上是某种枚举的情况下)。一些Python标准库使用以下方法:
re.match(pattern, str, re.MULTILINE | re.IGNORECASE)
您可以使用*args调整此方法:
my.func(a, b, c, my.MULTLINE, my.IGNORECASE)
我真的建议使用flag1=True:
- 它是可读的
- 在编译时检查标志名称(除非使用**kwargs)
- 您可以使用flag=1和flag=0而不是True和False来减少噪声
- 您可以临时将LONG\u FLAG\u NAME\u you\u DONT\u memory=True更改为False,而无需在需要更改回时重新键入LONG\u NAME
把它翻过来怎么样
flag1, flag2, flag3, flag4, flag5, flag6 = range(6)
def func(enable=[], disable=[],
enabled_by_default=[flag5, flag6]):
enabled = set(enabled_by_default + enabled) - set(disabled)
if flag1 in enabled:
...
if flag2 in enabled:
...
func(enable = [flag1, flag2, flag3],
disable = [flag6])
我怀念那些好的旧国旗:
首先,你为什么想要/需要传递旗帜?也许您应该重新考虑您的接口…这些标志将用于在数据结构中设置布尔值,从而控制在数据结构上操作的函数的未来行为。这是一种完全非面向对象的方法,但我选择它是出于简单性;不管怎样,即使我采用OO风格,行为上的变化也相当微妙,可能不值得创建一个完整的类家族来处理?一个
set
标志,或者一个dict
将标志名称映射到bools…我建议使用def func(data,*,flagA=1,flagB=0,flagC=1),这意味着这些都是纯关键字参数。也就是说,您可以编写func(x,flagB=1),但不能编写func(x,1)。我同意上一条注释中的仅关键字参数解决方案。在Python3中,它是由语言提供的,在Python2的遗留代码中,它可以用类似的东西进行模拟。但是,在某些情况下,您必须通过几个级别的深层调用堆栈多次传递标志,将标志打包到单个值([bit]标志)中是实用且易于阅读的。我通常使用类型安全标志实现来实现这一点:这通过str()
和repr()
提供了类型安全和简单的调试;因此,需要O(n)标志的内容将需要O(2^n)函数来模拟。我现在有2个旗子,需要4个函数,即使是3个或4个旗子也会很快失控谢谢你展示这一点。我在谷歌搜索了半个小时的“python位标志”。
a = 1
b = 2
c = 4
d = 8
def func( data, flags ):
print( ( flags & a) == a )
print( ( flags & b) == b )
print( ( flags & c) == c )
print( ( flags & d) == d )
>>>> func("bla", a|c|d)
>>>> True
>>>> False
>>>> True
>>>> True