在Python中使用**kwargs的正确方法

在Python中使用**kwargs的正确方法,python,keyword-argument,Python,Keyword Argument,我看了一眼,但它并没有完全回答我的问题。 举个例子,我用了一个简单的方法来打印我的名字 def call_me_by_name(first_name): print("Your name is {}".format(first_name)) 后来,我意识到,我还希望能够打印中间名和姓氏。我做了以下更改,以适应使用**kwargs的情况,担心将来可能会让我为名称本身添加更多字段(例如第三、第四、第五个名称等) 我决定使用**kwargs def call_me_by_name(first

我看了一眼,但它并没有完全回答我的问题。 举个例子,我用了一个简单的方法来打印我的名字

def call_me_by_name(first_name):
    print("Your name is {}".format(first_name))
后来,我意识到,我还希望能够打印中间名和姓氏。我做了以下更改,以适应使用**kwargs的情况,担心将来可能会让我为名称本身添加更多字段(例如第三、第四、第五个名称等)

我决定使用**kwargs

def call_me_by_name(first_name,**kwargs):

    middle_name = kwargs['middle_name'] if kwargs.get('middle_name') else ""
    last_name = kwargs['last_name'] if kwargs.get('last_name') else ""

    print("Your name is {} {} {}".format(first_name,middle_name,last_name))
这里我唯一关心的是,随着我继续实现对更多名称的支持,我最终会为每个关键字参数编写一行代码,这些关键字参数可能会出现,也可能不会出现。我想找到一个尽可能符合python的解决方案。有没有更好的方法来实现这一点

编辑1

我想使用关键字参数,因为这只是一个示例程序。实际用例是通过文件进行解析。现在的关键字参数将支持从解析文件

1) 文件中的特定字节。
2) 文件中的特定行号


在任何给定时间点只能设置这两个条件中的一个(因为不可能同时从文件中的特定字节偏移量和行号中读取)但是将来可能会有更多这样的条件,例如从第一个字符出现时解析文件等。我的方法应该支持10-20种不同的条件,但调用方在任何时候都只能设置其中一种条件。我不希望有20-30个不同的IF条件,除非没有其他选项。

如果函数特别关注关键字参数,那么这可能不是正确的工具。在这种情况下,您可以使用默认参数获得相同的效果:

def call_me_by_name(first_name, middle_name="", last_name=""):
    print("Your name is {} {} {}".format(first_name,middle_name,last_name))
当你想要一种“抓取袋”的选择时,它会更好。例如

def configure(**kwargs):
    if 'color' in kwargs:
        set_color(kwargs['color'])

等等。

如果您的函数特别关注关键字参数,那么这可能不是正确的工具。在这种情况下,您可以使用默认参数获得相同的效果:

def call_me_by_name(first_name, middle_name="", last_name=""):
    print("Your name is {} {} {}".format(first_name,middle_name,last_name))
当你想要一种“抓取袋”的选择时,它会更好。例如

def configure(**kwargs):
    if 'color' in kwargs:
        set_color(kwargs['color'])

等等。

在我看来,最好不要使用kwargs,甚至不要使用函数,您可以简单地执行以下操作:

print("Your name is", " ".join([first_name, middle_name, last_name]))
或者,如果您确实需要函数:

def call_me_by_name(*args):
     print("Your name is", " ".join(args))

在我看来,最好不要使用kwargs,甚至不要使用函数,您可以简单地执行以下操作:

print("Your name is", " ".join([first_name, middle_name, last_name]))
或者,如果您确实需要函数:

def call_me_by_name(*args):
     print("Your name is", " ".join(args))

您可以通过以下方式进行简化:

middle_name = kwargs.get('middle_name', '')

您可以通过以下方式进行简化:

middle_name = kwargs.get('middle_name', '')

我将把它作为一个答案发布:

您可以立即将kwargs值解压缩到如下格式函数:

"Your name is {} {} {}".format(first_name , *kwargs)

但是作为一个用户,@PM 2Ring提到的,你必须意识到这并不保证名称的顺序正确

我将把它作为答案发布:

您可以立即将kwargs值解压缩到如下格式函数:

"Your name is {} {} {}".format(first_name , *kwargs)

但是作为一个用户,@PM 2Ring提到的,你必须意识到这并不保证名称的顺序正确

我认为你叫我的名字并不是**夸尔格的好例子。但是,如果您想避免省略一些异国情调的、未经考虑的名称字段,请按以下方式命名:

def call_me_by_name(first_name, last_name, middle_name='', **kwargs):
    s = "Your name is {} {} {}".format(first_name,middle_name,last_name)
    if kwargs:
        s += " (" + ", ".join(["{}: {}".format(k,v) for k,v in kwargs.items()]) + ")"
    print(s)
测试:


我认为你叫我的名字并不是**kwargs的好例子。但是,如果您想避免省略一些异国情调的、未经考虑的名称字段,请按以下方式命名:

def call_me_by_name(first_name, last_name, middle_name='', **kwargs):
    s = "Your name is {} {} {}".format(first_name,middle_name,last_name)
    if kwargs:
        s += " (" + ", ".join(["{}: {}".format(k,v) for k,v in kwargs.items()]) + ")"
    print(s)
测试:


你有两个独立的问题,用两种不同的python方式回答这些问题

1-您首先关心的是,当格式化字符串时,您开始支持的参数越多,您就不希望继续添加新行。解决这一问题的方法是使用
defaultdict
,这样当您不提供特定的关键字参数时,就可以返回空字符串,并且
str.format\u map
接受dict作为输入关键字参数以格式化的方法。这样,您只需更新字符串和要打印的关键字参数:

from collections import defaultdict
def call_me_by_name(**kwargs):
    default_kwargs = defaultdict(str, kwargs)
    print("Your name is {first_name} {second_name} {third_name}".format_map(default_kwargs))
2-另一方面,在回答第二个问题时,如果您希望根据关键字参数提供不同的行为,如更改字符串的外观或提供不同的文件查找功能,而不使用If语句,则必须添加不同的函数/方法,并从该常用函数/方法调用它们。以下是两种方法:

面向对象:

模块:

def line_number(line_number):
    print('parsing with a line number: {}'.format(line_number))

def byte_position(byte_position):
    print('parsing with a byte position: {}'.format(byte_position))

def parse(**kwargs):
    return globals()[next(iter(kwargs))](**kwargs)

parse(byte_position=29)
parse(line_number=29)

你有两个独立的问题,用两种不同的python方式回答这些问题

1-您首先关心的是,当格式化字符串时,您开始支持的参数越多,您就不希望继续添加新行。解决这一问题的方法是使用
defaultdict
,这样当您不提供特定的关键字参数时,就可以返回空字符串,并且
str.format\u map
接受dict作为输入关键字参数以格式化的方法。这样,您只需更新字符串和要打印的关键字参数:

from collections import defaultdict
def call_me_by_name(**kwargs):
    default_kwargs = defaultdict(str, kwargs)
    print("Your name is {first_name} {second_name} {third_name}".format_map(default_kwargs))
2-另一方面,在回答第二个问题时,如果您希望根据关键字参数提供不同的行为,如更改字符串的外观或提供不同的文件查找功能,而不使用If语句,则必须添加不同的函数/方法,并从该常用函数/方法调用它们。以下是两种方法:

面向对象:

模块:

def line_number(line_number):
    print('parsing with a line number: {}'.format(line_number))

def byte_position(byte_position):
    print('parsing with a byte position: {}'.format(byte_position))

def parse(**kwargs):
    return globals()[next(iter(kwargs))](**kwargs)

parse(byte_position=29)
parse(line_number=29)

为什么不使用
*
解包dict?我的意思是,您可以直接将kwargs设置为
…format(*kwargs)
,但格式化字符串必须具有placeholders@Take_Care_在Python3.6之前,这并不保证名称的顺序正确。如果名字不见了怎么办?@PM 2Ring谢谢你的提醒。是的,用户必须意识到这一点:P@PM2Ring,我编辑了我的问题,以便更全面地解释我的用例。如果只能设置一个选项,为什么不设置