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

问题描述 投票:1回答:6

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

def call_me_by_name(first_name):
    print("Your name is {}".format(first_name))

后来,我意识到,除此之外,我还希望能够打印中间名和姓。我做了以下更改,以适应** kwargs担心将来,我可能会为名称本身添加更多字段(例如第3,第4,第5名等)

我决定使用** 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))

我唯一担心的是,当我继续实现对更多名称的支持时,我最终为每个关键字参数编写了一行代码,这些代码可能会也可能不会出现。我想找到一个尽可能pythonic的解决方案。有没有更好的方法来实现这一目标?

编辑1

我想使用关键字参数,因为这只是一个示例程序。实际用例是解析文件。截至目前的关键字参数将支持从中解析文件

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

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

python kwargs
6个回答
1
投票

你有两个独立的问题,有两种不同的pythonic方式来回答这些问题。

1-您首先要注意的是,在格式化字符串时,您不希望继续添加新行。解决这个问题的方法是使用defaultdict,这样当你不提供特定的关键字参数时你就能返回一个空字符串,而接受一个dict的str.format_map作为输入格式化关键字参数的方法。这样,您只需要更新字符串以及要打印的关键字参数:

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语句,你必须添加不同的函数/方法并从这个通用函数/方法中调用它们。这有两种方法:

OPEN:

class FileLookup:

    def parse(self, **kwargs):
        return getattr(self, next(iter(kwargs)))(**kwargs)

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

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

fl = FileLookup()
fl.parse(byte_position=10)
fl.parse(line_number=10)

模块:

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)

1
投票

对我来说,你最好不要使用kwargs,甚至不使用函数,你可以简单地做这样的事情:

print("Your name is", " ".join([first_name, middle_name, last_name]))

或者如果你想要一个功能:

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

1
投票

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

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'])

等等


1
投票

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

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

0
投票

我会将其作为答案发布:

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

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

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


0
投票

我认为你的call_me_by_name不是** kwargs的好例子。但是如果你想避免忽略一些奇特的,未经考虑的名字字段,call_me_by_name可能看起来像:

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)

测试:

name = {'first_name': 'Henry', 'last_name': 'Ford', 'ordinal': 'II', 'nickname': 'Hank the Deuce'}
call_me_by_name(**name)
>>> Your name is Henry  Ford (ordinal: II, nickname: Hank the Deuce)
© www.soinside.com 2019 - 2024. All rights reserved.