Python-功能函数的使用(三),python-函数,使用可选的可变参数定
Python-功能函数的使用(三),python-函数,使用可选的可变参数定
使用可选的可变参数定义函数
当使用有一个问题可选参数与可变默认类型,这可能会导致意外行为。
说明
这个问题是因为函数的默认参数初始化一旦被该功能时,在点定义,并不能(像许多其他语言)当函数被称为的默认值存储在函数对象的内部__defaults__构件变量。
def f(a, b=42, c=[]): passprint(f.__defaults__)# Out: (42, [])
对于不可改变的类型因为没有办法变异的变量,这是没有问题的;它只能被重新分配,使原始值不变。因此,后续保证具有相同的默认值。然而,对于一个可变类型,原始值可以发生变异,通过向它的各种部件的功能调用。因此,对函数的连续调用不能保证具有初始默认值。
def append(elem, to=[]): to.append(elem) # This call to append() mutates the default variable "to" return toappend(1)# Out: [1]append(2) # Appends it to the internally stored list# Out: [1, 2]append(3, []) # Using a new created list gives the expected result# Out: [3]# Calling it again without argument will append to the internally stored list againappend(4) # Out: [1, 2, 4]
注意:当一个可变类型被指定为默认属性像PyCharm有些IDE将发出警告。
解
如果你想确保缺省参数总是你在函数定义指定的,那么解决的办法是始终用一个不变的类型作为默认参数。
当可变类型,需要作为默认的一个常见的成语来实现这一点,是使用None(不变)作为默认参数,然后实际的默认值赋给变量参数,如果它等于None。
def append(elem, to=None): if to is None: to = [] to.append(elem) return to
参数传递和可变性
首先,一些术语:
参数(实参):实际变量被传递给函数。参数(形式参数):即在一个函数中使用的接收变量。在Python中,参数通过传递分配(相对于其他语言,其中的参数可以通过值/引用/指针传递)。
对参数进行突变会使参数发生变化(如果参数的类型是可变的)。重新分配参数不会重新分配参数。在Python中,我们不会给变量赋值。
相反,我们认为变量名称(标识,标签,标签),这些约束(分配,附后)为对象。def foo(x): # The argument (y) is assigned to the parameter (x). x[0] = 9 # This mutates the list labelled by both x and y. x = [1, 2, 3] # x is now labelling a different list (y is unaffected). x[2] = 8 # This mutates x‘s list, not y‘s list. y = [4, 5, 6] # y is the argument, x is the parameter.foo(y) # Pretend that we wrote "x = y", then go to line 1.y# Out: [9, 5, 6]一成不变的:整数,字符串,元组,依此类推。所有操作都复印。可变:列表,字典,集合等。操作可能会或可能不会改变。
x = [3, 1, 9]y = xx.append(5) # Mutates the list labelled by both x and y.x.sort() # Mutates the list labelled by both x and y (in-place sorting).x = x + [4] # Does not mutate the list (makes a copy for x only, not y).z = xx += [6] # Mutates the list labelled by both x and z (uses the extend function).x = sorted(x) # Does not mutate the list (makes a copy for x only).x# Out: [1, 3, 4, 5, 6, 9]y# Out: [1, 3, 5, 9]z# Out: [1, 3, 5, 9, 4, 6]
关闭
python中的闭包是由函数调用创建的。在这里,呼吁makeInc创建一个绑定x是在函数内部引用inc。每次调用makeInc创建此函数的新实例,但每个实例有一个链接到不同的绑定x。
def makeInc(x): def inc(y): # x is "attached" in the definition of inc return y + x return incincOne = makeInc(1)incFive = makeInc(5)incOne (5) # returns 6incFive(5) # returns 10
请注意,在常规闭包中,封闭函数完全从其封闭环境继承所有变量,在这个结构中,封闭函数只具有对继承变量的读访问权,但不能对它们进行赋值。
def makeInc(x): def inc(y): # incrementing x is not allowed x += y return x return incincOne = makeInc(1)incOne(5) # UnboundLocalError: local variable ‘x‘ referenced before assignment
Python 3里提供的nonlocal声明(非局部变量与嵌套函数实现了全封闭)。
def makeInc(x): def inc(y): nonlocal x # now assigning a value to x is allowed x += y return x return incincOne = makeInc(1)incOne(5) # returns 6
从函数返回值
函数可以return一个值,你可以直接使用:
def give_me_five(): return 5print(give_me_five()) # Print the returned value# Out: 5
或保存该值以供以后使用:
num = give_me_five()print(num) # Print the saved returned value# Out: 5
或使用任何操作的值:
print(give_me_five() + 10)# Out: 15
如果return在功能遇到功能将被立即退出和随后的操作不会进行评估:
def give_me_another_five(): return 5 print(‘This statement will not be printed. Ever.‘)print(give_me_another_five())# Out: 5
你也可以return多个值(以一元组的形式):
def give_me_two_fives(): return 5, 5 # Returns two 5first, second = give_me_two_fives()print(first)# Out: 5print(second)# Out: 5
用函数没有return语句隐返回None。类似地,用函数return声明,但没有返回值或变量的回报None。
使用参数定义函数
参数在函数名后面的括号中定义:
def divide(dividend, divisor): # The names of the function and its arguments # The arguments are available by name in the body of the function print(dividend / divisor)
函数名和其的参数列表被称为签名的功能。每个命名参数实际上是函数的局部变量。
调用函数时,通过按顺序列出参数来提供参数的值。
divide(10, 2)# output: 5
或者使用函数定义中的名称以任意顺序指定它们:
divide(divisor=2, dividend=10)# output: 5
强制使用命名参数
在函数签名中的第一个星号后指定的所有参数都是仅限关键字的。
def f(*a, b): passf(1, 2, 3)# TypeError: f() missing 1 required keyword-only argument: ‘b‘
在Python 3中,可以在函数签名中放置一个星号,以确保剩余的参数只能使用关键字参数传递。
def f(a, b, *, c): passf(1, 2, 3)# TypeError: f() takes 2 positional arguments but 3 were givenf(1, 2, c=3)# No error
递归限制
可能的递归的深度有一个限制,这取决于Python的实现。当达到限制时,会引发RuntimeError异常:
def cursing(depth): try: cursing(depth + 1) # actually, re-cursing except RuntimeError as RE: print(‘I recursed {} times!‘.format(depth))cursing(0)# Out: I recursed 1083 times!
它可以通过使用改变递归深度限制sys.setrecursionlimit(limit),并检查由此限制sys.getrecursionlimit()。
sys.setrecursionlimit(2000)cursing(0)# Out: I recursed 1997 times!
在Python 3.5中,例外的是一个RecursionError,它是衍生自RuntimeError。
递归函数
递归函数是在其定义中调用自身的函数。例如,数学函数,阶乘,由定义factorial(n) = n*(n-1)*(n-2)*...*3*2*1。可编程为
def factorial(n): #n here should be an integer if n == 0: return 1 else: return n*factorial(n-1)
这里的输出是:
factorial(0)#out 1factorial(1)#out 1factorial(2)#out 2factorial(3)#out 6
如预期。注意,这个功能是递归的,因为在第二return factorial(n-1),函数调用自身在其定义中。
有些递归函数可用来实现lambda,使用lambda阶乘函数将是这样的:
factorial = lambda n: 1 if n == 0 else n*factorial(n-1)
该功能的输出与上述相同。
使用多个参数定义函数
可以给出一个函数作为一个想要的参数,唯一固定的规则是每个参数名称必须是唯一的,可选参数必须在非可选参数之后:
def func(value1, value2, optionalvalue=10): return ‘{0} {1} {2}‘.format(value1, value2, optionalvalue1)
调用该函数时,您可以给每个关键字不带名称,但顺序很重要:
print(func(1, ‘a‘, 100))# Out: 1 a 100print(func(‘abc‘, 14))# abc 14 10
或者结合给出参数与名称和没有。然后名字的人必须遵循那些没有,但名称的顺序无关紧要:
print(func(‘This‘, optionalvalue=‘StackOverflow Documentation‘, value2=‘is‘))# Out: This is StackOverflow Documentation
迭代和字典解包
函数允许您指定这些类型的参数:位置,命名,变量位置,关键字args(kwargs)。这里是每个类型的清晰和简洁的使用。
def unpacking(a, b, c=45, d=60, *args, **kwargs): print(a, b, c, d, args, kwargs)>>> unpacking(1, 2)1 2 45 60 () {}>>> unpacking(1, 2, 3, 4)1 2 3 4 () {}>>> unpacking(1, 2, c=3, d=4)1 2 3 4 () {}>>> unpacking(1, 2, d=4, c=3)1 2 3 4 () {}>>> pair = (3,)>>> unpacking(1, 2, *pair, d=4)1 2 3 4 () {}>>> unpacking(1, 2, d=4, *pair)1 2 3 4 () {}>>> unpacking(1, 2, *pair, c=3)Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: unpacking() got multiple values for argument ‘c‘>>> unpacking(1, 2, c=3, *pair)Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: unpacking() got multiple values for argument ‘c‘>>> args_list = [3]>>> unpacking(1, 2, *args_list, d=4)1 2 3 4 () {}>>> unpacking(1, 2, d=4, *args_list)1 2 3 4 () {}>>> unpacking(1, 2, c=3, *args_list)Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: unpacking() got multiple values for argument ‘c‘>>> unpacking(1, 2, *args_list, c=3)Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: unpacking() got multiple values for argument ‘c‘>>> pair = (3, 4)>>> unpacking(1, 2, *pair)1 2 3 4 () {}>>> unpacking(1, 2, 3, 4, *pair)1 2 3 4 (3, 4) {}>>> unpacking(1, 2, d=4, *pair)Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: unpacking() got multiple values for argument ‘d‘>>> unpacking(1, 2, *pair, d=4)Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: unpacking() got multiple values for argument ‘d‘>>> args_list = [3, 4]>>> unpacking(1, 2, *args_list)1 2 3 4 () {}>>> unpacking(1, 2, 3, 4, *args_list)1 2 3 4 (3, 4) {}>>> unpacking(1, 2, d=4, *args_list)Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: unpacking() got multiple values for argument ‘d‘>>> unpacking(1, 2, *args_list, d=4)Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: unpacking() got multiple values for argument ‘d‘>>> arg_dict = {‘c‘:3, ‘d‘:4}>>> unpacking(1, 2, **arg_dict)1 2 3 4 () {}>>> arg_dict = {‘d‘:4, ‘c‘:3}>>> unpacking(1, 2, **arg_dict)1 2 3 4 () {}>>> arg_dict = {‘c‘:3, ‘d‘:4, ‘not_a_parameter‘: 75}>>> unpacking(1, 2, **arg_dict)1 2 3 4 () {‘not_a_parameter‘: 75}>>> unpacking(1, 2, *pair, **arg_dict)Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: unpacking() got multiple values for argument ‘d‘>>> unpacking(1, 2, 3, 4, **arg_dict)Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: unpacking() got multiple values for argument ‘d‘# Positional arguments take priority over any other form of argument passing>>> unpacking(1, 2, **arg_dict, c=3)1 2 3 4 () {‘not_a_parameter‘: 75}>>> unpacking(1, 2, 3, **arg_dict, c=3)Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: unpacking() got multiple values for argument ‘c‘
嵌套函数
python中的函数是第一类对象。它们可以在任何范围内定义。
def fibonacci(n): def step(a,b): return b, a+b a, b = 0, 1 for i in range(n): a, b = step(a, b) return a
捕获它们的封闭范围的函数可以像任何其他类型的对象一样传递。
def make_adder(n): def adder(x): return n + x return adderadd5 = make_adder(5)add6 = make_adder(6)add5(10)#Out: 15add6(10)#Out: 16def repeatedly_apply(func, n, x): for i in range(n): x = func(x) return xrepeatedly_apply(add5, 5, 1)#Out: 26
递归Lambda使用分配的变量
创建递归lambda函数的一种方法包括将函数分配给变量,然后在函数本身内引用该变量。一个常见的例子是递归计算数字的阶乘,如下面的代码所示:
lambda_factorial = lambda i:1 if i==0 else i*lambda_factorial(i-1)print(lambda_factorial(4)) # 4 * 3 * 2 * 1 = 12 * 2 = 24
代码说明
在lambda功能,通过它的可变分配,传递一个值(4),它的计算结果,如果是0,否则它返回当前值返回1(i)*另外计算的值的lambda函数- 1(i-1)。这个过程持续到传递的值递减到0(return 1)。一个过程,可以看到:
Python-功能函数的使用(三)
相关内容
- python 读取中文CSV 'gbk' codec can't de
- python tkinter学习——布局,pythontkinter布局,目录一、pa
- Python第三方模块tesserocr安装,pythontesserocr,介绍在爬虫过
- python算两个时间之间的天数,将天数转成int型,python
- python3 中 and 和 or 运算规律,python3or,一、包含一个逻辑
- Python3红楼梦人名出现次数统计分析,python3统计分析,一
- 解决python安装错误问题,python安装错误,遇到的问题描述
- python编码iso-8859-9编码问题,pythoniso-8859-9,(2018-10-1
- python中提取位图信息(AttributeError: module 'struct&
- Python 使用 Matplotlib 做图时,如何画竖直和水平的分割线
评论关闭