image.png

Parameters and Arguments?

Parameters、 Arguments两个单词虽然都翻译成参数的含义,但是其实这两个单词是有区别的,大概就是形参与实参的区别:

  • A parameter is the variable defined within the parentheses during function definition.
  • An argument is a value that is passed to a function when it is called. It might be a variable, value or object passed to a function or method as input.

python的输入参数主要分为位置参数(Positional Arguments)和关键词参数(Keyword Arguments)。

也就是说python在定义函数时的参数(parameter)是不分位置参数和关键词参数的,只有在调用时才会区别区分这两种参数,或者理解成以位置/关键词参数的形式传递参数

位置参数

位置参数是我们在定义函数时最经常用的参数,即声明一系列变量名称来作为接受参数,参数接受顺序按照函数的输入顺序来决定。

使用*收集位置参数

当我们对需要输入的位置参数个数不确定时,我们可以利用位置参数来进行收集参数,"*+变量名称"的变量会作为未知参数的接受变量,需要注意的是python会默认将接受的参数转化为元组。

def ppp(*pavg):
for item in pavg:
print(item)
ppp("xiaoming","xiaownag","xiaohong")

关键词参数

位置参数固然好用,但一个问题是当函数的传递参数过多时我们无法记住所有输入参数的输入顺序,这会给我们函数的使用带来很多困难。于是python还有另外一种叫做关键词参数的输入参数,该参数在函数声明时一般会用在变量名字后跟一个等号,写成类似于"a=‘sh’"的形式,这种定义方式的一个好处是不会按照输入顺序来决定变量的值。且如果不给相应的关键词参数赋值的话,会使用函数定义时传入的值作为默认值(切记不要把可变的数据类型(列表或者字典)当做默认值,对应的默认值会随着调用不断变化)。

def f(a, L=[]):
print(f"{L}的地址是{id(L)}")
L.append(a)
return None
L=[]
#与函数定义中的L不是同一个变量,地址不同
print(id(L))
f(1)
f(2)

对于以上代码,函数中的L是可变参数,会在函数定义时创建该变量,接着在两次调用函数后,函数中L的值会不断变化。
另外需要注意的是关键词参数的传递在位置参数之后

用**收集关键词参数

与*类似,**收集关键词参数对变量赋值时会将输入的关键词转化为字典存储在变量中:

def ppp(**pavg):
return pavg
a=ppp(a="xiaoming",b="xiaownag",c="xiaohong")
print(a)

通常情况下,我们传递参数时可以自己选择以位置参数还是关键词参数的形式传入,即大多数函数在定义时传入的参数是positional-or-keyword的形式,这也是为什么在开始时要区分Parameters和Arguments,不过需要需要注意的有三点:

  • 位置参数的传递必须放在关键词参数传递之前
  • 位置参数可以按照关键词参数的形式传递,但必须保证传入的关键词确实在函数定义中有所声明
  • 关键词参数可以按照位置参数的形式传递,但必须保证传入的位置参数的顺序与函数定义中的顺序一致

总的来说,函数定义时参数的传递是非常灵活的,当我们想要指定参数的传递方式时,则需要考虑以下的方法:

Special parameters

一般来说,使用关键词参数和位置参数可以满足我们所有定义函数的需求。但在实际应用过程中,为了代码的可读性,我们可能需要对函数传递参数的方式进行限制,也就是只接受关键词参数或者位置参数,这时就需要用到/*参数

def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
----------- ---------- ----------
| | |
| Positional or keyword |
| - Keyword only
-- Positional only

代码中两个符号都是可选的,其中/前的参数必须是按照位置参数传递的形式,*后的参数必须是关键词参数传递的形式。
As guidance:

  • Use positional-only if you want the name of the parameters to not be available to the user. This is useful when parameter names have no real meaning, if you want to enforce the order of the arguments when the function is called or if you need to take some positional parameters and arbitrary keywords.
  • Use keyword-only when names have meaning and the function definition is more understandable by being explicit with names or you want to prevent users relying on the position of the argument being passed.
  • For an API, use positional-only to prevent breaking API changes if the parameter’s name is modified in the future.

设定只接受关键词参数传递的参数

将强制关键词参数放在*,后面即可:

def h(x=1,*,y=1):
print(x+y)
return 0
#h(1,2)#报错
h(1,y=2)

这个原则背后的逻辑是因为单个*后跟的其他参数只能是关键词参数,所有传入的位置参数都会收入*后边。详细解答

这块可以参考Python中’*'的用法,其实可以视作Python容器的迭代运算符号

文档字符串

在定义函数后,我们可以为定义的函数创建帮助文档,方法为在定义函数的区域使用"’ 注释内容’"来写帮助文档。函数外查看帮助文档有两个方法:

  • help(func_name):返回函数的参数列表和文档
  • fun_name.doc:返回文档字符串

函数传递及内部函数

在python语法中,函数被当做一个普通对象。我们可以将函数本身或者函数的返回值赋给其他变量,将函数赋给某一变量的时候记得不要在函数名称后加括号不然会自动调用函数,赋给变量的就是函数的返回值了。
除此之外,我们还可以在函数内部继续定义新的函数,内部函数可以直接使用函数内的变量,可以修改变量的值。具体丰富的应用参考装饰器的使用方法。