1. 使用函数
在编写程序的过程中,可以将完成重复工作的语句提取出来,将其编写为函数。这样,在过程中可以方便地调用函数来完成这些重复的工作,而不必重复地粘贴复制代码。此外,函数也可以使得程序结构更加清晰,更容易维护。
注意: 与js中有变量提升不同,在python中,函数必须先声明,然后才能调用它
hello()
def hello():
print('hello')
如上代码,执行后,会显示如下错误:
NameError: name 'hello' is not defined
正确的书写方式:
def hello():
print('hello')
hello()
1.1 声明函数
使用def声明一个函数,如果有返回值则使用return语句返回结果,其一般形式如下:
def <函数名> (参数列表):
<函数语句>
return <返回值>
参数列表 和 返回值 不是必须的,return后也可以不跟返回值,甚至连return也没有。
参数的使用:
def sum(a, b):
print(a + b)
sum(2,3) # 5
返回值的使用:
def sum(a, b):
return a + b
print(sum(4,3)) # 7
对于return后没有返回值 和 没有return语句的函数都会返回None值,如下示例:
def sum(a, b):
print(a + b) # 7
print(sum(4,3)) # None
上述例子中,因为函数体没有return返回值,所以sum(a, b)拿到的返回值是None
def sum(a, b):
print(a + b) # 7
return
print(sum(4,3)) # None
如上代码,虽然函数体中有return语句,但是return后没有返回的内容,所以sum(4,3)拿到的也是None
1.2 函数调用
函数名之后用圆括号将调用参数括起来,多个参数之间用逗号隔开。
def sum(list):
result = 0
for item in list:
result += item
return result
print(sum([1,2,3])) # 6
print(sum((1,2,3,4))) # 10
2. 函数参数
2.1 默认值参数
指定参数默认值的方式如下:
def <函数名> (参数=默认值):
<语句>
示例代码:
def hello(word='Python'):
print('hello, ' + word)
hello() # hello, Python
hello('Node.js') # hello, Node.js
注意: 参数列表中既包含无默认值参数,又包含有默认值的参数,那么在声明函数的参数时,必须先声明无默认值参数,后声明有默认值参数。
如下代码执行时会报错:
def fn(a, b=3, c):
print('a: {0}'.format(a))
print('b: {0}'.format(b))
print('c: {0}'.format(c))
fn(a=1,b=5,c=7)
执行结果如下:
2.2 位置参数
在python中参数值的传递是按照声明函数时参数的位置顺序进行传递的,即位置参数。
调用时传递参数会依照声明时的先后顺序一一对应。
示例代码:
def fn(a, b, c=3):
print('a: {0}'.format(a))
print('b: {0}'.format(b))
print('c: {0}'.format(c))
fn(1,5,7)
执行结果:
a: 1
b: 5
c: 7
2.3 提供关键字参数
python中另外一种传递参数的方法,按照参数名传递值得方法,即提供关键参数。
其使用方式类似于函数默认值的定义方式,即“关键字=参数值”,这样调用函数时就不必严格按照函数声明时参数列表的顺序来提供参数了。
示例代码:
def fn(a, b, c=3):
print('a: {0}'.format(a))
print('b: {0}'.format(b))
print('c: {0}'.format(c))
fn(b=1,a=5)
执行结果:
a: 5
b: 1
c: 3
优先级: 如果函数调用时,即提供了关键字参数,又提供了位置参数,则位置参数会被优先调用。如果参数结合时出现重复,则会发生运行错误。
2.4. *valuename可变数量参数传递
在自定义函数时,如果参数名前加一个星号*
,则表示该参数就是一个可变长参数。
在调用该函数时,如果依次将所有的其他变量都赋值之后,剩下的参数将会收集在一个元组中,元组的名称就是前面带星号的参数名。
示例代码:
def fn(*args):
print(type(args))
print(args)
fn(1)
fn(1,2,3)
执行结果如下:
<class 'tuple'>
(1,)
<class 'tuple'>
(1, 2, 3)
在自定义函数中,一般将带星号的参数放在最后。当带星号的参数放在前面时,调用时后面的参数必须以关键字参数方式提供,否则其后的位置参数无法获取值而引发错误。
示例代码:
def fn(a, *args):
print('a: {0}'.format(a))
print(type(args))
print(args)
fn(1)
fn(1,2,3)
执行结果:
a: 1
<class 'tuple'>
()
a: 1
<class 'tuple'>
(2, 3)
示例代码:
def fn(*args, a, b=5):
print('a: {0}'.format(a))
print('b: {0}'.format(b))
print(type(args))
print(args)
fn(1,2,3, a=10)
执行结果:
a: 10
b: 5
<class 'tuple'>
(1, 2, 3)
2.5. **valuename收集关键字参数
使用元组来收集参数的参数时,调用时提供的参数不能为关键字参数,如果要收集不定数量的关键字参数可以在自定义函数时的参数前加两颗星即valuename,这样多余的关键字参数就可以以字典的方式被收集到变量valuename中。
示例代码:
def fn(a, b=3, **kwargs):
print('a: ', a)
print('b: ', b)
print(kwargs, type(kwargs))
fn(17,5,name='wally',age=123,sex='man')
执行结果:
a: 17
b: 5
{'name': 'wally', 'age': 123, 'sex': 'man'} <class 'dict'>
注意: 收集关键字参数时要放在函数声明的参数列表中的所有参数之后
使用这种收集字典的方式,为函数中使用大量的默认值提供了方便,不用把大量的默认值全放在函数声明的参数中,而是把它放到程序中:
示例代码:
def fn(name, **kwargs):
natures = {
'x': 1,
'y': 1,
'z': 1,
'color': 'white',
'weight': 1
}
natures.update(kwargs)
print(name, '立方体属性:')
print('体积:', natures['x']*natures['y']*natures['z'])
print('颜色:', natures['color'])
print('重量:', natures['weight'], '\n')
fn('狗窝')
fn('鸟巢', x=10, y=20, z=5, color='yellow', weight='1t')
【代码说明】 示例中,第二个参数用来收集关键字参数。函数体中给了一个默认参数的字典natures,然后用字典的update()函数将调用时提供的关键字参数更新至默认参数的字典。之后直接从字典中获取即可。
执行结果:
狗窝 立方体属性:
体积: 1
颜色: white
重量: 1
鸟巢 立方体属性:
体积: 1000
颜色: yellow
重量: 1t
2.6 拆解序列
调用函数时还可以把元组和字典进行拆解调用
- 拆解元组 提供位置参数 调用时参数前加*
- 拆解字典 提供关键字参数 调用时参数前加**
示例代码:
def fn(a,b):
return a+b
print('拆解元组:')
print(fn(*(3,4)), '\n')
print('拆解字典:')
print(fn(**{'a': 3, 'b': 7}))
执行结果:
拆解元组:
7
拆解字典:
10
2.7 不同类型参数的使用
python中的元素有可变和不可变之分,如整数、浮点数、字符串、元组等都属于不可变的;而列表与字典是属于可变的(可以增减、修改元素)。
在python中,“=”的作用是将对象引用与内存中某对象进行绑定。
那么既然整数是不可变的,怎么改变一个指向整数的变量的值呢?
答案是直接在内存中创建一个新的整数值,然后将变量引用与其绑定。
在函数调用时,若提供的是不可变参数,那么在函数内部对其修改时,在函数外部其值是不变的;若提供可变参数,则函数内部对其修改时,函数外部它的值也会改变的。
示例代码:
def fn(aint, alist):
aint = 0
alist[0] = 0
alist.append(4)
print('函数中aint:', aint)
print('函数中alist:', alist)
aint = 3
alist = [1,2,3]
print('函数调用前aint:', aint)
print('函数调用前alist:', alist)
fn(aint, alist)
print('函数调用后aint:', aint) # 调用后值和调用前值相同
print('函数调用后alist:', alist) # 调用后值和调用前值不同
执行结果:
函数调用前aint: 3
函数调用前alist: [1, 2, 3]
函数中aint: 0
函数中alist: [0, 2, 3, 4]
函数调用后aint: 3
函数调用后alist: [0, 2, 3, 4]
注意:列表、字典可变对象在作为默认函数参数时的“陷阱”, 示例代码:
def fn(lst=[]):
lst.append('hello')
print(lst)
fn()
fn()
fn()
执行结果:
['hello']
['hello', 'hello']
['hello', 'hello', 'hello']
如果要实现空列表的默认参数,可以修改代码如下:
def fn(lst=None):
lst = []
lst.append('hello')
print(lst)
fn()
fn()
fn()
执行结果:
['hello']
['hello']
['hello']