1、函数
python
一、函数编程
函数是python中组织代码的最小单元
bash
函数是实现模块化编程的基本组件ide
Python使用def语句定义函数模块化
每一个Python函数都有一个返回值,默认为None,也可使用“return value”明肯定定义返回值函数
def语句会建立一个函数对象,并同时建立一个指向函数的对象引用测试
函数也是对象,能够存储在组合数据类型中,也能够做为参数传递给其它函数ui
callable()可用于测试对象是否可调用spa
函数经过def定义,接着函数名,函数名后面用一对小括号列出参数列表,使用一个冒号开始函数体。orm
函数体是正常的Python语句,能够组合任意结构
return语句表示函数的返回值
函数有输入(参数)和输出(返回值),函数实际上是一个代码单元,把输入转化为输出。
定义函数的时候并不会执行函数体,当调用函数时才会执行函数体
函数经过函数名来调用,函数名后面一对小括号里面传入实参
In [2]: def f1(): ...: print("hello") ...: In [3]: f1 Out[3]: <function __main__.f1> In [4]: f1() hello In [5]: a = f1 In [6]: b = f1() hello In [7]: a Out[7]: <function __main__.f1> In [8]: b In [9]: type(a) Out[9]: function In [10]: type(b) Out[10]: NoneType In [15]: callable(a) # 实现了__call__()方法就可调用 Out[15]: True
二、对于Python的函数,咱们须要记住的是
1)函数的默认返回值是None。
2)python是一个自上而下逐行解释并执行的语言。所以,函数的定义必须在函数被调用以前。同名的函数,后定义的会覆盖前面定义的。
3)程序执行的时候,遇到函数定义只会先将函数总体读进内存,并不马上执行。等到函数被调用的时候才执行函数体。
4)python函数的参数传递的是值传递仍是引用传递。
函数参数传递本质上和变量总体复制同样,只是两个变量分别为形参a和实参b。那么,a=b后,a变了,b值是否跟着变呢?这取决于对象内容可变不可变
值传递:
指在调用函数时,将实际参数复制一份传递给函数,函数对参数进行修改将不会影响到实际参数
适用于不可变对象(如int, str,tuples等)做为参数传递时,例如元组
引用传递:
指调用函数时,将实际参数的地址传递给函数,函数对参数进行修改,将影响实际参数
适用于可变对象(如list,dict,类的实例等)做为参数传递时,例如列表
浅复制:(也叫影子复制)
只复制父对象,不会复制对象的内部的子对象
深复制:
复制对象及其子对象
赋值是引用传递
In [74]: l1 = [1, 2, 3] In [75]: l2 = l1 In [76]: l2 Out[76]: [1, 2, 3] In [77]: l3 = l1.copy() In [78]: l3 Out[78]: [1, 2, 3] In [79]: id(l3) # l3和l1应用的是不一样内存对象 Out[79]: 140149284135624 In [80]: id(l1) Out[80]: 140149295996616 In [81]: id(l2) # l2和l1引用的是同一个内存对象 Out[81]: 140149295996616
2、函数的参数
对于函数,最重要的知识点莫过于参数了。
参数分为形式参数(形参)和实际参数(实参)。
def f1(a, b, c): pass f1(1, 2, 3)
其中,a,b,c就是形参,1,2,3就是实参,也就是实际要传递的参数。
In [27]: def add(x, y): ...: print(x + y) ...: return x + y ...: In [28]: add(3, 5) 8 Out[28]: 8 In [29]: add(3) --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-29-c9889e45a711> in <module>() ----> 1 add(3) TypeError: add() missing 1 required positional argument: 'y' In [30]: add(3, 5, 8) --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-30-0b52ebc12bc6> in <module>() ----> 1 add(3, 5, 8) TypeError: add() takes 2 positional arguments but 3 were given In [42]: add(3, "5") --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-42-d73b87d3f8c1> in <module>() ----> 1 add(3, "5") <ipython-input-31-4950d8722875> in add(x, y) 1 def add(x, y): ----> 2 ret = x + y 3 print('{} + {} = {}'.format(x, y, ret)) 4 return ret TypeError: unsupported operand type(s) for +: 'int' and 'str'
函数调用时,传入的实参必须和函数定义时的行参想匹配,若是不匹配会抛出TypeError.
Python中的形式参数有如下几种:
一、位置参数
一般在传递参数的时候咱们按照参数的位置,逐一传递,这叫“位置参数”。
In [31]: def add(x, y): ...: ret = x + y ...: print('{} + {} = {}'.format(x, y, ret)) ...: return ret ...: In [32]: add(3, 5) 3 + 5 = 8 Out[32]: 8
二、关键字参数
而有时候咱们会用“形参名”=“值”的方式传递参数,这叫“关键字参数或指定参数”。
In [33]: add(x=3, y=5) 3 + 5 = 8 Out[33]: 8 In [34]: add(y=3, x=5) # 关键字参数和顺序无关 5 + 3 = 8 Out[34]: 8
位置参数和关键字参数混用时关键字参数必须在位置参数后面
In [37]: add(3, y=5) 3 + 5 = 8 Out[37]: 8 In [38]: add(x=3, 5) File "<ipython-input-38-165b39de39ac>", line 1 add(x=3, 5) ^ SyntaxError: positional argument follows keyword argument In [39]: add(3, x=5) --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-39-b0f1746a3413> in <module>() ----> 1 add(3, x=5) TypeError: add() got multiple values for argument 'x'
三、默认参数
默认参数是为某些参数设定一个默认值,既能够减小参数传入量,也能够享受使用默认值的便利。
默认参数必须位于参数列表的最后部分!
默认参数是在函数定义时,指的是形参!
In [46]: def inc(base, x=1): ...: return base + x ...: In [47]: inc(3, 2) Out[47]: 5 In [48]: inc(3) Out[48]: 4 In [49]: inc(3, x=4) Out[49]: 7 In [56]: inc(base=4) Out[56]: 5 In [57]: inc(base=4, x=5) Out[57]: 9 In [50]: def inc(x=1, base): ...: return base + x ...: File "<ipython-input-50-ac010ba50fd9>", line 1 def inc(x=1, base): ^ SyntaxError: non-default argument follows default argument
四、可变(动态)参数
Python的动态参数有两种,分别是*args和**kwargs,这里面的关键是一个和两个星号,而不是args和kwargs,实际上你可使用*any或**whatever的方式,但就如self同样,潜规则咱们使用*args和**kwargs。
可变参数是在函数定义时,指的是形参!
*args:位置可变参数;函数定义时参数名前加一个星号
一个星号表示接受任意个动态参数。调用时,会将实际参数打包成一个元组传入函数。
此时只能经过位置参数传参
In [63]: def sum(*args): ...: ret = 0 ...: for i in args: ...: ret += i ...: return ret ...: In [64]: sum() Out[64]: 0 In [65]: sum(1) Out[65]: 1 In [66]: sum(1, 2, 3, 8) Out[66]: 14
**kwargs:关键字可变参数;函数定义时参数名前加两个星号
两个星表示接受键值对的动态参数,数量任意。调用的时候会将实际参数打包成字典。
此时只能经过关键字参数传参
例如:
In [73]: def connect(**kwargs): ...: print(type(kwargs)) ...: for k, v in kwargs.items(): ...: print('{} => {}'.format(k, v)) ...: In [74]: connect(host="localhost", port=3300) <class 'dict'> host => localhost port => 3300 In [79]: connect("localhost", port=3300) --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-79-6aeadd0e08a5> in <module>() ----> 1 connect("localhost", port=3300) TypeError: connect() takes 0 positional arguments but 1 was given
万能参数:
当*args和**kwargs组合起来使用,理论上能接受任何形式和数量的参数,在不少代码中咱们都能见到这种定义方式。须要注意的是,*args必须出如今**kwargs以前。
In [83]: def fn(*args, **kwargs): ...: print(args) ...: print(kwargs) ...: In [84]: fn(2, 3, 5, x=11, y="xxj") (2, 3, 5) {'x': 11, 'y': 'xxj'} In [85]: def fn(**kwargs, *args): ...: print(args) ...: print(kwargs) File "<ipython-input-85-ae6e58836952>", line 1 def fn(**kwargs, *args): ^ SyntaxError: invalid syntax
可变参数和普通参数混合使用:
In [91]: def fn(x, y, *args, **kwargs): ...: print(x) ...: print(y) ...: print(args) ...: print(kwargs) ...: In [92]: fn(2, 3, 4, 5, 6, a=1,b=2) 2 3 (4, 5, 6) {'a': 1, 'b': 2} In [95]: fn(2, 3) 2 3 () {} In [97]: fn(2, y=3) 2 3 () {} In [99]: fn(2, 3, 4) 2 3 (4,) {} In [100]: fn(2, 3, a=23) 2 3 () {'a': 23} In [107]: def fn(*args, x): # 位置可变参数是否能够在普通参数以前 ...: print(args) ...: print(x) ...: In [108]: fn(1, 2, 3) --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-108-9ab6b0a400c3> in <module>() ----> 1 fn(1, 2, 3) TypeError: fn() missing 1 required keyword-only argument: 'x' In [109]: fn(1, 2, x=3) (1, 2) 3 In [110]: fn(1, x=3) (1,) 3 In [111]: fn(x=3) () 3 In [112]: def fn(**kwargs, x): # 关键字可变参数是否能够在普通参数以前 ...: print(kwargs) ...: print(x) ...: File "<ipython-input-112-3226e57525e0>", line 1 def fn(**kwargs, x): ^ SyntaxError: invalid syntax
位置可变参数也能够在普通参数以前,可是在位置可变参数以后的普通参数变成了keyword-only参数(只能以关键字参数登入)
关键字可变参数不能够在普通参数以前(为何?)
可变参数和默认参数混合使用:
In [113]: def fn(x=5, *args): ...: print(x) ...: print(args) ...: In [114]: fn(1) 1 () In [115]: fn(1,2) 1 (2,) In [116]: fn(1,2,3,4) 1 (2, 3, 4) In [117]: fn(x=3, 4) File "<ipython-input-117-2d95cecddace>", line 1 fn(x=3, 4) ^ SyntaxError: positional argument follows keyword argument In [121]: def fn(*args, x=5): # 位置参数在默认参数以前没限制 ...: print(x) ...: print(args) ...: In [122]: fn() 5 () In [123]: fn(1, 2) 5 (1, 2) In [124]: fn(1) 5 (1,) In [125]: fn(1, x=3) 3 (1,) In [127]: def fn(**kwargs, x=5): ...: print(x) ...: print(kwargs) ...: File "<ipython-input-127-069a751edec8>", line 1 def fn(**kwargs, x=5): ^ SyntaxError: invalid syntax In [128]: def fn(x=5, **kwargs): ...: print(x) ...: print(kwargs) ...: ...: In [129]: fn() 5 {} In [130]: fn(1) 1 {} In [131]: fn(1, a=2) 1 {'a': 2} In [132]: fn(x=1, a=2) 1 {'a': 2}
可变位置参数在默认参数以后,默认参数不能使用关键字传参
可变关键字参数不能在默认参数以前
当默认参数和可变参数一块儿出现时,默认参数至关于普通参数
小结:
函数的参数规则这么多,头都大了;这里咱们建议的函数参数使用用法:
1)默认参数靠后
2)可变参数靠后
3)默认参数和可变参数不一样时出现
不遵照不必定错,遵照代码可读性高
当咱们须要同时使用默认参数和可变参数时怎么办?
咱们一般这样处理:
In [139]: def connect(host='127.0.0.1', port=3306, user='root', password='', **kwargs): ...: pass ...: In [140]: def connect(**kwargs): ...: host = kwargs.pop('host', '127.0.0.1') ...:
3、参数解构
一、参数解构
调用函数时,传入实参时加一个星号,能够把iterable解构成位置参数
调用函数时,传入实参时加两个个星号,能够把dict解构成关键字参数
In [141]: def add(x, y): ...: ret = x + y ...: print('{} + {} = {}'.format(x, y, ret)) ...: In [142]: add(1, 2) 1 + 2 = 3 In [145]: t = [1, 2] In [146]: add(*t) 1 + 2 = 3 In [143]: t = [1, 2, 3] In [144]: add(*t) --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-144-d90b03560d6e> in <module>() ----> 1 add(*t) TypeError: add() takes 2 positional arguments but 3 were given In [147]: t = [(1, 2), (3, 4)] In [148]: add(*t) In [148]: add(*t) (1, 2) + (3, 4) = (1, 2, 3, 4) # 字典解构成关键字参数 In [153]: d = {'x':1, 'y':2} In [154]: add(**d) 1 + 2 = 3 In [155]: add(*d) x + y = xy
二、参数解构和可变参数混用
In [161]: def sum(*args): ...: ret = 0 ...: for i in args: ...: ret += i ...: return ret ...: In [162]: sum(*(1, 2)) Out[162]: 3 In [163]: sum(*[1, 2]) Out[163]: 3 In [165]: sum(*range(5)) Out[165]: 10
三、参数解构的限制
关键字参数解构,key必须是str
In [167]: def fn(**kwargs): ...: print(kwargs) ...: In [168]: fn(**{'a':1}) {'a': 1} In [170]: fn(**{12:1}) --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-170-99986e5a722a> in <module>() ----> 1 fn(**{12:1}) In [211]: def fn(*args, **kwargs): ...: print(args) ...: print(kwargs) ...: In [212]: fn(*[1, 2, 3]) (1, 2, 3) {} In [214]: fn(*[1, 2, 3], **{'a':1, 'b':2}) (1, 2, 3) {'a': 1, 'b': 2}
四、keyword-only参数
星号以后的参数只能经过关键字参数传入
可变位置参数以后的参数也是keyword-only参数
只能经过关键字参数传入的参数就交keyword-only参数
keyword-only参数能够有默认值
In [179]: def fn(*, x): ...: print(x) ...: In [180]: fn(1) --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-180-cb5d79cf2c77> in <module>() ----> 1 fn(1) TypeError: fn() takes 0 positional arguments but 1 was given In [181]: fn(x=1) 1 In [182]: fn(1, x=2) --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-182-8eb9b719c886> in <module>() ----> 1 fn(1, x=2) TypeError: fn() takes 0 positional arguments but 1 positional argument (and 1 keyword-only argument) were given In [183]:
keyword-only参数与其它参数混用:
In [188]: def fn(x, *, y): ...: print(x) ...: print(y) ...: In [189]: fn(1, y=2) 1 2 In [193]: def fn(x=1, *, y=2): ...: print(x) ...: print(y) ...: ...: In [194]: fn() 1 2 In [199]: def fn(x=1, *, y): # ...: print(x) ...: print(y) ...: ...: In [200]: fn(y=3) 1 3 In [201]: fn(3) --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-201-f005f2a6106f> in <module>() ----> 1 fn(3) TypeError: fn() missing 1 required keyword-only argument: 'y' In [202]: In [205]: def fn(*, x, y): # *号后能够有多个keyword-only参数 ...: print(x) ...: print(y) ...: In [206]: fn(x=1, y=2) 1 2 In [207]: def fn(x, y, *): # *号不能写在最后 ...: print(x) ...: print(y) ...: File "<ipython-input-207-6c060b52ac76>", line 1 def fn(x, y, *): ^ SyntaxError: named arguments must follow bare *