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

很长一段时间以来,我一直试图找出向python函数传递标志的最佳方式。最直接的方法是:

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