函数就是一个函数对象,函数的定义就是将函数名和函数内存中的函数地址对应起来
函数的数学定义是:y=f(x) ,y是函数名,x是自变量,自变量也可以是多个:y=f(x0,x1,x2,x3 ... xn)
python函数:python的函数的组成有:语句块、函数名、参数列表,返回值。
python中的函数的,目的是完成一定的功能,是结构化编程对代码的最基本的封装,一般按照功能组织一段代码,封装是为了复用,减少代码的冗余,使代码更美观可读。
pythonh中的函数分为:内建函数和库函数
python函数是通过 def 关键字定义的,具体的定义语法如下:
def add(x, y):
res = x + y
return res
def 是函数定义的关键字,x,y是函数的形式参数,上面的 add 就是定义的函数名,
实际上python中的函数名就是一个标识符(变量名)。定义一个函数后,就在内存中创建了一个函数对象,变量名指向的这个函数对象的内存地址。
python中的函数如果没有显示的return语句,默认就会有一个隐式的return None.
定义一个函数只是声明一个函数,并没有执行该函数,我们只有在调用函数后才能发挥函数的功能。
函数的调用方式是在函数名的后面加上小括号,并加上必要的参数。
我们在调用函数的时候传入的参数叫实参。
函数调用的示例
add(1,3)
查看对象是否可调用对象可以使用callable()内建函数
callable(add)
=========================
In [5]: def add(x,y):
...: res = x + y
...: return res
...:
In [6]: callable(add)
Out[6]: True
返回 True 表示是一个可调用对象
我们通过print()返回的是函数的内存地址
In [7]: print(add)
<function add at 0x7fefc90e5730>
或者直接在ipython中执行add,返回是add的一种可见的字符串模式
In [8]: add
Out[8]: <function __main__.add(x, y)>
函数是可以被其他函数调用的,函数本身也可以调用其他函数
def add(x, y):
res = x + y
raturn res
def new_add():
return add(6, 9)
a = new_add()
执行的结果是
15
函数必须先定义后调用
其实很容易理解,没有定义怎么调用?
def new_add():
return add(6, 9)
a = new_add()
=================================
In [5]: def new_add():
...: return add(6,9)
...:
In [6]: a = new_add()
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-6-3072819d1adb> in <module>
----> 1 a = new_add()
<ipython-input-5-97d8213b487f> in new_add()
1 def new_add():
----> 2 return add(6,9)
3
NameError: name ‘add‘ is not defined
# 定义
def fn(x,y,z) # 没有设置默认值
def fn(x,y,z=5) # 定义的时候,关键字设置的参数值叫做缺省值,要在放在位置之后。
# 调用
fn(1,2,3) # 适用于上面两种定义方法的调用,位置参数的位置顺序是一一对应的
fn(1,2) # 只适用于上面有默认值定义方法的调用,这里没有为z传参,使用的是默认的5
fn(x=1,y=2,z=3) # 也可以全部使用关键字为位置参数传参,此时传参的顺序没有限制。
fn(1,2,z=3,x=4) # 这种就是为x重复传参,前面已经 x = 1 了,后面又来了 x = 5.
参数的默认值的作用:
默认参数的定义和调用的典型示例
# 定义
def longin(host="127.0.0.1",port=80,username=‘test‘,password=‘youdonotknow‘):
# 调用
login() # 全部使用默认参数
login(host=‘192.168.200.1‘) # 只有host使用自定义的参数,其他使用默认参数
定义
def add(*args)
total = 0
for i in args:
tatal += i
return total
传递
add(1,2,3) # 1,2,3传递进函数之后会被 *args 全部接受并组成一个元组(1,2,3)
定义
def fn(**kwargs):
for k,v in kwargs.items():
print(k,v)
传参
fn(host=‘127.0.0.1‘,port=80,username=‘test‘,password=‘test‘)
def fn(username, password, **kwargs):
def fn(username, *args, **kwargs):
def fn(username, **kwargs, *args): # 错误的写法,*args 不能写在 **kwargs之后。
def fn(x,y,*args,**kwargs):
fn(3,5,7,9,10,a=1,b="python")
fn(3,5)
fn(3,5,7)
fn(x=3,y=4,5,6,a=2,b="test") # 错误的传参,5,6不能放在x=3,y=4之后
fn(7,9,y=5,x=3,a=3,b=‘test‘) # 错误的传参,7,9分别赋值给了x,y,但是y=5,x=3又重复赋值了。
定义
def fn(*args,x=1,y,**kwargs): # x和y都是keyword-only参数,keyword-only参数可以设置默认值。
传参
def dn(*args,x):
# args可以看作是已经截获了所有的位置参数,x不是用关键字参数就不可能拿到实参。
思考:下面的定义方式是否可以?
def fn(**kwargs,y):
上面的定义是不可以的,因为在一个 * 号之后的都是keyword 类型的参数,也就是说 y 也是一个keyword参数。
所以实际上,传参的时候应该是 y=1 这样的,但是这样传参后 y=1就会被 **keyword截获,y 还是拿不到值。所以语法是错误的。
keYword-only参数的另一种形式
def fn(*, x,y):
print(x,y)
fn(x=t=5,y=6)
* 号之后,普通的参数都变成了keyword-only参数
下面是几种函数可变参数以及参数默认值的定义以及传参的示例
def fn(*args,x=5):
print(x)
print(args)
fn() # 等价于fn(x=5), x=5 args=()
fn(5) # 等价于fn(x=5), 传参后,x=5 args=()
fn(x=6) # 传参后,x=6 args=()
fn(1,2,3,x=10) # 传参后,x=10 args=(1,2,3)
====================================================
def fn(y,*args,x=5):
print(‘x={},y={}‘.format(x,y))
print(args)
fn() # y 是一个普通的位置参数,必须传入一个
fn(5) # y=5, x=5,
fn(x=6) # 没有为 y 设置变量
fn(1,2,3,x=10) # y=1,x=10 ,args = (2,3)
fn(1,2,y=3,x=10) # y 重新赋值了
=====================================================
def fn(x=5,**kwargs):
print(‘x={}‘.format(x))
print(kwargs)
fn() # x=5, kwargs = {}
fn(5) # x=5, kwargs = {}
fn(x=6) # x=6, kwargs = {}
fn(y=3,x=10) # x=10, kwargs = {"y":3}
fn(3,y=10) # x=3, kwargs = {"y":10}
=====================================================
def fn(x,y,z=3,*args,m=4,n,**kwargs): # 此函数必须为x,y,n传入参数
print(x,y,z,m,n)
print(args)
print(kwargs)
=====================================================
def connect(host=‘127.0.0.1‘,port=80,user=‘test‘,password=‘test‘,**kwargs):
print(host,port)
print(user,password)
print(kwargs)
connect(db=‘cmdb‘) # 127.0.0.1 80 test test
In [2]: connect(db=‘cmdb‘)
127.0.0.1 80
test test
{‘db‘: ‘cmdb‘}
In [3]: connect(host=‘192.168.1.1‘,db=‘cmdb‘)
192.168.1.1 80
test test
{‘db‘: ‘cmdb‘}
In [4]: connect(host=‘192.168.1.1‘,db=‘cmdb‘,password=‘mysql‘)
192.168.1.1 80
test mysql
{‘db‘: ‘cmdb‘}
通过几个简单的加法函数来演示
def add(x,y):
return x + y
add(4,5) # 正确
add((4,5)) # 不正确,需要解构,(4,5) 是一个参数
t = (4,5)
add(t[0],t[1])
add(*t) 或 add(*(4,5)) add(*[4,5]) add(*(4,6))
add(*range((1,3))
def add(x,y):
return x+y
add(*(4,5)) # 9
add((*[4,5])) # 9
add(*{4,6}) # 10
d = {"x":1,"y":2}
add(**d) # 3
add(**{"x":1,"y":2}) # 3
add(**{"a":1,"b":2}) # 报错,因为解构之后是 a=1,b=2,而函数定义的时候是 x,y
add(*{"a":1,"b":2}) # 通过一个 * 解构之后,是只对第一层的 key 解构,解构是 字符串相加 ‘ab‘
def add(*args):
total = 0
for i in args:
total += i
return total
add(1,2,3) # 6
add(*(1,2,3)) # 6
add(*range(10)) # 45
定义
def fn(x,y,*args,**kwargs):
print(‘x={}; y={}‘.format(x,y))
print(‘args is {}‘.format(args))
print(‘kwargs is {}‘.format(kwargs))
调用传参
fn(1,2,3,4,5)
--------------------------------------------------------
C:\python36\python.exe D:/pyporject/test/test6.py
x=1; y=2
args is (3, 4, 5)
kwargs is {}
fn(1,2,3,4,x=5)
--------------------------------------------------------
C:\python36\python.exe D:/pyporject/test/test6.py
Traceback (most recent call last):
File "D:/pyporject/test/test6.py", line 8, in <module>
fn(1,2,3,4,x=5)
TypeError: fn() got multiple values for argument ‘x‘
fn(y=2,x=1,z=3)
--------------------------------------------------------
C:\python36\python.exe D:/pyporject/test/test6.py
x=1; y=2
args is ()
kwargs is {‘z‘: 3}
定义
此时的x,y是keyword-only参数
def fn(*args,x,y,**kwargs):
print(‘x={}; y={}‘.format(x,y))
print(‘args is {}‘.format(args))
print(‘kwargs is {}‘.format(kwargs))
调用传参
fn(1,2,3,4,5)
--------------------------------------------------------
C:\python36\python.exe D:/pyporject/test/test6.py
Traceback (most recent call last):
File "D:/pyporject/test/test6.py", line 7, in <module>
fn(1,2,3,4,5)
TypeError: fn() missing 2 required keyword-only arguments: ‘x‘ and ‘y‘
fn(1,2,3,4,5,x=6,y=7)
--------------------------------------------------------
C:\python36\python.exe D:/pyporject/test/test6.py
x=6; y=7
args is (1, 2, 3, 4, 5)
kwargs is {}
fn(1,2,3,4,5,x=6,y=7,z=9)
--------------------------------------------------------
C:\python36\python.exe D:/pyporject/test/test6.py
x=6; y=7
args is (1, 2, 3, 4, 5)
kwargs is {‘z‘: 9}
fn(x=6,y=7,z=9)
--------------------------------------------------------
C:\python36\python.exe D:/pyporject/test/test6.py
x=6; y=7
args is ()
kwargs is {‘z‘: 9}
定义
此时的x,y是keyword-only参数
def fn(*,x,y):
print(‘x={}; y={}‘.format(x,y))
调用传参
fn(x=6,y=7)
--------------------------------------------------------
C:\python36\python.exe D:/pyporject/test/test6.py
x=6; y=7
定义
此时的x,y是keyword-only参数
def fn(x,y,*args, m=9, n, **kwargs): # 由于 m和n是keyword_only参数,所以可以写成 m=9, n 的形式,顺序没有关系,因为传参的时候是按照名称对应传参的。
print(‘x={}; y={}‘.format(x,y))
print(‘args is {}‘.format(args))
print(‘m={}; n={}‘.format(m,n))
print(‘kwargs is {}‘.format(kwargs))
调用传参
fn(1,2,3,4,5)
--------------------------------------------------------
C:\python36\python.exe D:/pyporject/test/test6.py
Traceback (most recent call last):
File "D:/pyporject/test/test6.py", line 8, in <module>
fn(1,2,3,4,5)
TypeError: fn() missing 1 required keyword-only argument: ‘n‘
fn(1,2,3,4,5,n=6)
--------------------------------------------------------
C:\python36\python.exe D:/pyporject/test/test6.py
x=1; y=2
args is (3, 4, 5)
m=9; n=6
kwargs is {}
fn(1,2,3,4,5,m=9,n=119,z=555)
--------------------------------------------------------
C:\python36\python.exe D:/pyporject/test/test6.py
x=1; y=2
args is (3, 4, 5)
m=9; n=119
kwargs is {‘z‘: 555}
fn(1,2,m=9,n=119,z=555)
--------------------------------------------------------
C:\python36\python.exe D:/pyporject/test/test6.py
x=1; y=2
args is ()
m=9; n=119
kwargs is {‘z‘: 555}
*
和 **
在函数定义和函数调用时候的区别 ※※※在片函数的源码中就有类似的用法
函数的示例
def fn(*args,**kwargs):
print(args)
print(kwargs)
函数传参后 *args 和 **kwargs 分别收集位置参数和关键字参数
fn(1, 2, 3, a=4, b=5)
----------------------------------------------------------
C:\python36\python.exe D:/pyporject/test/test6.py
(1, 2, 3)
{‘a‘: 4, ‘b‘: 5}
函数传参的时候,实参中使用 * 和 ** 的时候,* 将对应的对可解构的对象(list,set,range,str,tuple等)解构为位置参数,实参中使用 * 只可以对字典的key进行解构,** 将对应的字典解构为关键字参数
实参解构后还是会被函数的 *args 和 **kwargs分别将位置参数和关键数参数收集
fn(*(1, 2, 3), **{‘x‘: ‘love‘, ‘y‘: ‘you‘})
# === 等价于 ===
# fn(1, 2, 3, x=‘love‘, y=‘you‘)
----------------------------------------------------------
C:\python36\python.exe D:/pyporject/test/test6.py
(1, 2, 3)
{‘x‘: ‘love‘, ‘y‘: ‘you‘}
fn(*[1, 2, 3], **{‘x‘: ‘love‘, ‘y‘: ‘you‘})
# === 等价于 ===
# fn(1, 2, 3, x=‘love‘, y=‘you‘)
----------------------------------------------------------
C:\python36\python.exe D:/pyporject/test/test6.py
(1, 2, 3)
{‘x‘: ‘love‘, ‘y‘: ‘you‘}
fn(*‘123‘, **{‘x‘: ‘love‘, ‘y‘: ‘you‘})
# === 等价于 ===
# fn("1", "2", "3", x=‘love‘, y=‘you‘)
----------------------------------------------------------
C:\python36\python.exe D:/pyporject/test/test6.py
(‘1‘, ‘2‘, ‘3‘)
{‘x‘: ‘love‘, ‘y‘: ‘you‘}
等价的效果
fn(1, 2, 3, x=‘love‘, y=‘you‘)
----------------------------------------------------------
C:\python36\python.exe D:/pyporject/test/test6.py
(1, 2, 3)
{‘x‘: ‘love‘, ‘y‘: ‘you‘}
fn("1", "2", "3", x=‘love‘, y=‘you‘)
----------------------------------------------------------
C:\python36\python.exe D:/pyporject/test/test6.py
(‘1‘, ‘2‘, ‘3‘)
{‘x‘: ‘love‘, ‘y‘: ‘you‘}
在函数传参的时候,我们可以使用 * 将多个可解构的对象解构为位置参数,使用 ** 将多个字典解构为关键自参数
fn(*‘123‘, *(4, 5, 6), **{‘x‘: ‘love‘, ‘y‘: ‘you‘})
----------------------------------------------------------
C:\python36\python.exe D:/pyporject/test/test6.py
(‘1‘, ‘2‘, ‘3‘, 4, 5, 6)
{‘x‘: ‘love‘, ‘y‘: ‘you‘}
fn(*‘123‘, *(4, 5, 6), **{‘x‘: ‘love‘, ‘y‘: ‘you‘}, **{‘m‘: 666, ‘n‘: 999})
----------------------------------------------------------
C:\python36\python.exe D:/pyporject/test/test6.py
(‘1‘, ‘2‘, ‘3‘, 4, 5, 6)
{‘x‘: ‘love‘, ‘y‘: ‘you‘, ‘m‘: 666, ‘n‘: 999}
*
, 不支持 **
*
,对字典来说只能对key解构*
和 **
*
可以理解为是对可解构对象(list,set,range,str,tuple等)进行解构,解构之后就是一个一个的位置参数,对字典只能对key进行解构。**
是对字典的解构,解构之后就是一个一个的key value 对儿。本文链接: https://www.cnblogs.com/shichangming/p/10383404.html
原文:https://www.cnblogs.com/shichangming/p/10383404.html