geekdoc-python-zh/docs/pythoncentral/fun-with-python-function-pa...

6.2 KiB
Raw Permalink Blame History

Python 函数参数的乐趣

原文:https://www.pythoncentral.io/fun-with-python-function-parameters/

事实上每种编程语言都有函数和过程一种从程序的不同位置分离出可以多次调用的代码块的方法以及一种向它们传递参数的方法。Python 也不例外,所以我们将快速浏览一下大多数语言都有的标准内容,然后看看 Python 提供的一些很酷的东西。

Python 中的位置函数参数

这是一个非常简单的函数:


def foo(val1, val2, val3):

return val1 + val2 + val3

使用时,我们会得到以下内容:


>>> print(foo(1, 2, 3))

6

该函数有 3 个位置参数(每个参数在被调用时获取传递给该函数的下一个值——val1获取第一个值(1)val2获取第二个值(2),依此类推)。

命名 Python 函数参数(带默认值)

Python 还支持命名的参数,这样当一个函数被调用时,参数可以通过名称显式赋值。这些通常用于实现默认值或可选值。例如:


def foo(val1, val2, val3, calcSum=True):

# Calculate the sum

if calcSum:

return val1 + val2 + val3

# Calculate the average instead

else:

return (val1 + val2 + val3) / 3

使用该函数可以得到以下结果:


>>> print(foo(1, 2, 3))

6

>>> print(foo(1, 2, 3, calcSum=False))

2

在这个例子中,calcSum是可选的——如果在调用函数时没有指定,它将获得默认值True

潜在的 Python 函数参数问题

要记住的一点是,默认值是在函数编译时计算的,如果值是可变的,这是一个重要的区别。下面的行为可能不是我们想要的:


def foo(val, arr=[]):

arr.append(val)

return arr

使用该功能时:


>>> print(foo(1))

[1]

>>> print(foo(2))

[1, 2]

发生这种情况是因为默认值(一个空列表)在函数编译时被求值一次,然后在每次调用函数时被重用。为了在每次调用中得到一个空列表,代码需要写成这样:


def foo(val, arr=None):

if arr is None:

arr = []

arr.append(val)
返回 arr 

使用该函数时,我们得到:


>>> print(foo(1))

[1]

>>> print(foo(2))

[2]

Python 函数参数顺序

与位置参数不同,命名参数的指定顺序无关紧要:


def foo(val1=0, val2=0):

return val1  val2

使用时,我们会得到以下内容:


>>> print(foo(val1=10, val2=3))

7

>>> # Note: parameters are in a different order

>>> print(foo(val2=3, val1=10))

7

不同寻常的是Python 还允许通过名称来指定位置参数:


def foo(val1, val2):

''' Note: parameters are positional, not named. '''

return val1  val2

使用时,我们会得到以下内容:


>>> # But we can still set them by name

>>> print(foo(val1=10, val2=3))

7

>>> # And in any order!

>>> print(foo(val2=3, val1=10))

7

这里有一个更复杂的例子:


def foo(p1, p2, p3, n1=None, n2=None):

print('[%d %d %d]' % (p1, p2, p3))

if n1:

print('n1=%d' % n1)

if n2:

print('n2=%d' % n2)

使用时,我们会得到以下内容:


>>> foo(1, 2, 3, n2=99)

[1 2 3]

n2=99

>>> foo(1, 2, n1=42, p3=3)

[1 2 3]

n1=42

这看起来确实令人困惑,但是理解它如何工作的关键是要认识到函数的参数列表是一个字典(一组键/值对)。Python 首先匹配位置参数,然后分配函数调用中指定的任何命名参数。

变量 Python 函数参数表

当您开始查看变量参数列表时Python 的酷就真正开始了。您甚至可以在不知道将传入什么参数的情况下编写函数!

在下面的函数中, vals 参数前面的星号表示任何其他位置参数


def lessThan(cutoffVal, *vals) :

''' Return a list of values less than the cutoff. '''

arr = []

for val in vals :

if val < cutoffVal:

arr.append(val)

return arr

使用该函数时,我们得到:


>>> print(lessThan(10, 2, 17, -3, 42))

[2, -3]

我们在函数调用(10)中指定的第一个位置值被赋予函数中的第一个参数(cutoffVal),然后所有剩余的位置值被放入一个元组中并被分配给 val。然后我们遍历这些值寻找任何小于临界值的值。

我们也可以用命名参数做同样的事情。下面 dict 参数前面的双星号表示任何其他命名的参数。这一次Python 将把它们作为字典中的键/值对提供给我们。


def printVals(prefix='', **dict):

# Print out the extra named parameters and their values

for key, val in dict.items():

print('%s [%s] => [%s]' % (prefix, str(key), str(val)))

使用该函数时,我们得到:


>>> printVals(prefix='..', foo=42, bar='!!!')

[foo] => [42]

[bar] => [!!!]

>>> printVals(prefix='..', one=1, two=2)

[two] => [2]

[one] => [1]

请注意,在最后一个示例中,这些值并没有按照在函数调用中指定的顺序打印出来。这是因为这些额外命名的参数是在字典中传递的,字典是一个无序的数据结构。

一个真实世界的例子

那么,你会用这些做什么呢?例如,程序通常会从一个模板生成消息,该模板具有占位符,用于在运行时插入值。例如:

您好{name}。您的帐户余额为{1},您还有{2}可用点数。

下面的函数使用这样一个模板和一组参数来替换占位符。


def formatString(stringTemplate, *args, **kwargs):

# Replace any positional parameters

for i in range(0, len(args)):

tmp = '{%s}' % str(1+i)

while True:

pos = stringTemplate.find(tmp)

if pos < 0:

break

stringTemplate = stringTemplate[:pos] + \

str(args[i]) + \

stringTemplate[pos+len(tmp):]
#替换 kwargs.items()中 keyval 的任何命名参数
:
tmp = ' { % s } ' % key
while True:
pos = string template . find(tmp)
if pos<0:
break
string template = string template[:pos]+\
str(val)+\
string template[pos+len(tmp):]
返回字符串模板

这就是它的作用:


>>> stringTemplate = 'pos1={1} pos2={2} pos3={3} foo={foo} bar={bar}'

>>> print(formatString(stringTemplate, 1, 2))

pos1=1 pos2=2 pos3={3} foo={foo} bar={bar}

>>> print(formatString(stringTemplate, 42, bar=123, foo='hello'))

pos1=42 pos2={2} pos3={3} foo=hello bar=123