函数参数中裸星号的用途是什么?

28 投票
2 回答
17749 浏览
提问于 2025-04-18 02:33

我看到这个StackOverflow的问题(这不是重复的问题):Python中函数参数的裸星号

在python-3.x中,你可以在函数参数中加一个裸的*,这意味着(引用自文档):

在“*”或“*标识符”之后的参数是仅限关键字的参数,只能通过关键字参数传递。

好吧,我定义了一个函数:

>>> def f(a, b, *, c=1, d=2, e=3):
...     print('Hello, world!')
... 

我只能通过指定关键字来传递cde的值:

>>> f(1, 2, 10, 20, 30)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f() takes 2 positional arguments but 5 were given
>>> f(1, 2, c=10, d=20, e=30)
Hello, world!

问题是:

  • 这种限制/语法糖的动机是什么?
  • 它适用于哪些场景?
  • 在切换到python3的第三方库中真的有使用吗?

一些“现实世界”的例子会很有帮助。提前谢谢你。

2 个回答

4

对于那些来自或使用过 ruby 的朋友

下面这个在 Python 中的表达式

def f(a, b, *, c=1, d=2, e=3):

和 Ruby 中的这个

def f(a,b, options={})
  c = options[:c] || 1
  d = options[:d] || 2
  e = options[:e] || 3
end

是类似的。

因为 Python 这个语言讲究的是明确比隐含好,所以在参数中需要用到*(也叫 splat) 操作符。

PS:我从来没用过 Python,如果我说错了,请纠正我。

28

PEP 3102 这个文档解释得很清楚:它的目的是让函数能够接受各种“选项”,这些选项之间其实是相互独立的。把这些选项放在参数的位置上既麻烦又不方便,因为它们之间没有明显的“优先级”,也就没有固定的顺序。

在很多库里,有很多函数都能从中受益。比如,pandas.read_csv 这个函数的调用方式是:

def parser_f(filepath_or_buffer,
                 sep=sep,
                 dialect=None,
                 compression=None,

                 doublequote=True,
                 escapechar=None,
                 quotechar='"',
                 quoting=csv.QUOTE_MINIMAL,
                 skipinitialspace=False,
                 lineterminator=None,

                 header='infer',
                 index_col=None,
                 names=None,
                 prefix=None,
                 skiprows=None,
                 skipfooter=None,
                 skip_footer=0,
                 na_values=None,
                 na_fvalues=None,
                 true_values=None,
                 false_values=None,
                 delimiter=None,
                 converters=None,
                 dtype=None,
                 usecols=None,

                 engine='c',
                 delim_whitespace=False,
                 as_recarray=False,
                 na_filter=True,
                 compact_ints=False,
                 use_unsigned=False,
                 low_memory=_c_parser_defaults['low_memory'],
                 buffer_lines=None,
                 warn_bad_lines=True,
                 error_bad_lines=True,

                 keep_default_na=True,
                 thousands=None,
                 comment=None,
                 decimal=b'.',

                 parse_dates=False,
                 keep_date_col=False,
                 dayfirst=False,
                 date_parser=None,

                 memory_map=False,
                 nrows=None,
                 iterator=False,
                 chunksize=None,

                 verbose=False,
                 encoding=None,
                 squeeze=False,
                 mangle_dupe_cols=True,
                 tupleize_cols=False,
                 infer_datetime_format=False):

除了文件路径,其他的选项都是独立的,它们指定了如何解析 CSV 文件的不同方面。没有特别的理由让它们按照某种特定的顺序传递。如果要记住这些参数的顺序,你会觉得很头疼。把它们作为关键字参数传递会更合理。

现在你可以看到,pandas 实际上并没有把这些参数定义为仅限关键字的参数,可能是为了保持与 Python 2 的兼容性。我想很多库出于同样的原因也没有使用这种语法。我不太清楚目前有哪些库(如果有的话)已经开始使用它。

撰写回答