Python 入门(四)- 函数与变量作用域

函数的定义

1
2
def funcname(parameter_list):
pass
  1. 如果函数体内没有return,则返回 None
  2. 先定义,后调用(解释性语言)
  3. 递归次数有限制,设置最大递归次数方法如下:
1
2
import sys
sys.setrecursionlimit(100000)

多结果

python 支持返回多个结果,且结果为 tuple 类型。

1
2
3
4
5
6
7
8
def cal(a, b):
r1 = a*3
r2 = b*2+10
return r1, r2

result = cal(3,6) // (9, 22)
result[0] // 9
result[1] // 22

不推荐用下标来获得多个结果中的每一个,而使用变量名称来接收多个结果。

1
r1, r2 = cal(3,6) // 9, 22

序列解包与链式赋值

可以用多变量接收多个数值

1
a,b,c = 1,2,3

也可以一个变量接收多个数值

1
2
d = 1,2,3 
type(d) // <type 'tuple'>(序列)

序列解包(sequence unpacking)是一个序列赋值给多个变量

1
2
a,b,c = d 
a,b,c // (1, 2, 3)

注:序列解包的个数必须相同,否则则会发生错误异常

1
2
3
4
5
a,b = [1,2,3]

// File "main.py", line 11, in <module>
a,b = [1,2,3]
ValueError: too many values to unpack

链式赋值

1
a=b=c=1

等价于

1
a,b,c = 1,1,1

参数

参数包括必须参数、关键字参数、默认参数与可变参数。

必须参数

必须参数,参数必须传递。

1
2
3
4
def func(x,y):
pass

func(1,2)

关键字参数

关键字参数,参数必须传递。调用时指明实参赋值给哪个形参,无需按照顺序传递。

1
2
3
4
def func(x,y):
pass

func(x=1,y=2)

默认参数

默认参数,参数可不传,采用默认值。
默认参数必须出现在非默认参数之后。

1
2
3
4
5
6
def func(x,y=2,z=3):
pass

func(x=3)
func(3,2)
func(3,y=2,3) #报错

可变参数

*用来表示可变参数,可变参数会自动转化为元组类型。

1
2
3
4
5
6
def func(*param):
print(param) #(1, 2, 3, 4, 5, 6)
print(type(param)) #<type 'tuple'>
pass

func(1,2,3,4,5,6)

如果传入一个元组,则会变为二维元组。

1
2
3
4
5
6
def func(*param):
print(param) #二维元组 ((1, 2, 3, 4, 5, 6),)
print(type(param)) #<type 'tuple'>
pass

func((1,2,3,4,5,6))

如果想只传入一个元组,而不想变成二维元组怎么办?

1
2
3
4
5
6
def func(*param):
print(param) #(1, 2, 3, 4, 5, 6)
print(type(param)) #<type 'tuple'>
pass

func(*(1,2,3,4,5,6))

*a 的作用在于把a中数据平铺。

可变参数可与其它参数同时使用,但其它参数一定要在可变参数之前。

如果参数顺序为必须参数 > 默认参数 > 可变参数,则可变参数会覆盖默认参数。

1
2
3
4
5
6
7
def func(param1, param2=2, *param):
print(param1) #a
print(param2) #1
print(param) #(2,3)
pass

func('a', 1,2,3) #无法跳过默认参数

如果参数顺序为必须参数 > 可变参数 > 默认参数,则默认参数之前的所有参数都会被认为是可变参数。

1
2
3
4
5
6
def func(param1, *param, param2=2):
print(param1) #'a'
print(param2) #(1,2,3,'param')
print(param) #2

func('a', 1,2,3,'param')

可用关键字参数代替默认参数,顺序为必须参数 > 可变参数 > 关键字参数。

1
2
3
4
5
6
def func(param1, *param, param2=2):
print(param1) #'a'
print(param2) #(1,2,3)
print(param) #'param'

func('a', 1,2,3, param2='param')

解析可变参数列表:for 循环

1
2
3
4
5
6
7
def func(*param):
sum = 0
for i in param:
sum += i*i
print(sum) # 91

func(1,2,3,4,5,6)

不建议使用多种类型的形参列表,种类越少越好。

关键字可变参数

**用来表示关键字可变参数,关键字可变参数会自动转化为字典类型。

1
2
3
4
5
def func(**param):
print(param) #{'aa': 1, 'cc': 3, 'bb': 2}
print(type(param)) #<type 'dict'>

func(aa=1,bb=2,cc=3)

如何快速遍历字典呢?常见的错误写法如下:

1
2
3
4
5
6
7
8
9
10
def func(**param):
for key,value in param:
print(key,':',value)

func(aa=1,bb=2,cc=3)

#
('a', ':', 'a')
('c', ':', 'c')
('b', ':', 'b')

其中,key 为键的第一个字母,value 为键的第二个字母。正确的写法为:调用items()方法:

1
2
3
4
5
6
7
8
9
10
def func(**param):
for key,value in param.items():
print(key,':',value)

func(aa=1,bb=2,cc=3)

#
('aa', ':', 1)
('cc', ':', 3)
('bb', ':', 2)

如果传入的参数为字典格式,和可变参数类似,需要在参数传入时增加**

1
2
a = {'aa':1,'bb':2,'cc':3}
func(**a)

注:当定义时设置了参数,但传入参数为空,则不会调用该函数。

变量作用域

函数内的变量作用域为局部变量(只在函数内部),函数外部的变量为全局变量,函数内部可以使用外部变量。

python没有块级作用域(例如:for循环),只有函数作用域。

作用域链

当变量在当前函数作用域里找不到值时,则会在上一级中寻找,直至全局寻找。此为作用域的链式特性。

1
2
3
4
5
6
7
8
9
c=1
def func1():
c=2
def func2():
c=3
print(c)
func2()

func1() #3
1
2
3
4
5
6
7
8
9
c=1
def func1():
c=2
def func2():
#c=3
print(c)
func2()

func1() #2
1
2
3
4
5
6
7
8
9
c=1
def func1():
#c=2
def func2():
#c=3
print(c)
func2()

func1() #1

global 关键字

global关键字可以使在外部可以访问函数内部的局部变量变为可能,即变成全局变量。

1
2
3
4
5
6
def func():
global c
c=2

func()
print(c) #2