函数
定义和注意事项
- 将可能需要反复执行的代码封装为函数,并在需要该功能的地方进行调用,不仅可以实现代码复用,更重要的是可以保证代码的一致性,只需要修改该函数代码则所有调用均受到影响。
- 设计函数时,应注意提高模块的内聚性,同时降低模块之间的隐式耦合。
- 在实际项目开发中,往往会把一些通用的函数封装到一个模块中,并把这个通用模块文件放到顶层文件夹中,这样更方便管理。
- 在编写函数时,应尽量减少副作用,尽量不要修改参数本身,不要修改除返回值以外的其他内容。
- 应充分利用Python函数式编程的特点,让自己定义的函数尽量符合纯函数式编程的要求,例如保证线程安全、可以并行运行等等。
- 函数定义时括弧内为形参,一个函数可以没有形参,但是括弧必须要有,表示该函数不接受参数。
- 函数调用时向其传递实参,将实参传递给形参。
- 在定义函数时,对参数个数并没有限制,如果有多个形参,需要使用逗号进行分隔。
- 对于绝大多数情况下,在函数内部直接修改形参的值不会影响实参,而是包建一个新变量。
函数定义语法:
def 函数名([参数列表]):
函数体
注意:
- 函数形参不需要声明类型,也不需要指定函数返回值类型
- 即使该函数不需要接收任何参数,也必须保留一对空的圆括号
- 括号后面的冒号必不可少
- 函数体相对于def关键字必须保持一定的空格缩进
- Python允许嵌套定义函数
总之,函数可以改变参数的值,进行传递,并不会是局部变量
- 在Python中,函数参数有很多种:可以为普通位置参数、默认值参数、关键参数、可变长度参数等等。
- Python在定义函数时不需要指定形参的类型,完全由调用者传递的实参类型以及Python解释器的理解和推断来决定。
- 不需要指定函数的返回值类型,函数的返回值类型由return语句返回值的类型决定。如果函数没有return语句,或者没有执行到return语句,或者执行了不带任何值的return语句,则函数都默认返回空值None。
- 调用函数的实参和形参的位置必须一样,数量也必须相同。
- 在设置默认值参数的时候,两个默认值参数中间不能加非默认值参数
____defaults__
__可以查看函数的默认值参数的当前值,并且返回一个元组,其顺序按照当时值进行传递
def test(a,b=2,c=5):
print(a,b,c)
print(test.__defaults__)
多次调用函数并且不为默认值参数传递值时,默认值参数只在定义时进行一次解释和初始化,对于列表、字典这样可变类型的默认值参数,这一点可能会导致很严重的逻辑错误。
def test(new,old=[]):
old.append(new)
return old
print(test(1,[1,2,3,4]))
print(test(1))
print(test(2))
[1, 2, 3, 4, 1]
[1]
[1, 2]
函数的默认值参数是在函数定义时确定值的,只会被初始化一次。
i=3
def test(n=i):
print(n)
test()
i=2
test()
i=56
test(2)
3
3
2
按照参数名字传参
- 按参数名字传递值,明确指定哪个值传递给哪个参数。
- 通过关键参数,实参顺序可以和形参顺序不一致,但不影响传递结果,避免了用户需要牢记位置参数顺序的麻烦,使得函数的调用和参数传递更加灵活方便。
- 关键参数主要指调用函数时的参数传递方式,与函数定义无关。
可变长度参数
- *parameter用来接受多个实参并将其放在一个元组中
- **parameter接受多个关键参数并存放到字典中
def test1(*p):
print(p)
def test2(**p):
print(p)
if __name__=="__main__":
test1(1,2,3,4)
test2(x=1,y=2,z=3)
(1, 2, 3, 4)
{'x': 1, 'y': 2, 'z': 3}
参数传递的序列解包
调用函数时对实参序列使用一个星号*进行解包后的实参将会被当做普通位置参数对待,并且会在关键参数和使用两个星号**进行序列解包的参数之前进行处理。
def demo(a,b,c):
print(a+b+c)
seq=[1,2,3]
sxe=(1,2,3)
demo(*seq)
demo(*sxe)
6
6
解包字典
def demo(a,b,c):
print(a+b+c)
seq=['a','b','c']
sxe=(1,2,3)
demo(**dict(zip(seq,sxe)))
6
序列解包相当于位置参数,优先处理
demo(a,b,c)
demo(a=1,*(1,2))#错误
demo(b=1,*(1,2))#错误
demo(c=1,*(1,2))#正确
序列解包在关键参数解包之后
demo(**{'a':1,'b':2}, *(3,))#错误
demo(*(3,),**{'a':1,'b':2} )#错误
demo(**{'c':1,'b':2},*(3,))#错误
demo(*(3,),**{'c':1,'b':2} )#正确
return
return语句用来从一个函数中返回一个值,同时结束函数。无论出现在函数的什么位置,一旦执行结束函数。
对于以下情况,Python将认为该函数以return None结束,返回空值:
- 函数没有return语句;
- 函数有return语句但是没有执行到;
- 函数有return但是没有返回任何值。
变量
定义
- 变量起作用的代码范围称为变量的作用域,不同作用域内变量名可以相同,互不影响。
- 在函数内部定义的普通变量只在函数内部起作用,称为局部变量。当函数执行结束后,局部变量自动删除,不再可以使用。
- 局部变量的引用比全局变量速度快,应优先考虑使用。
- 除了在函数内部定义变量,Python还允许在所有函数的外部定义变量,这样的变量称为全局变量(Global Variable)。
- 和局部变量不同,全局变量的默认作用域是整个程序,即全局变量既可以在各个函数的外部使用,也可以在各函数内部使用。
- 如果在函数内任意位置有为变量赋新值的操作,该变量即被认为是(隐式的)局部变量,除非在函数内显式地用关键字global进行声明。
- 如果局部变量与全局变量具有相同的名字,那么该局部变量会在自己的作用域内隐藏同名的全局变量。
- 一个变量已在函数外定义,如果在函数内需要为这个变量赋值,并要将这个赋值结果反映到函数外,可以在函数内使用global将其声明为全局变量。
- 如果一个变量在函数外没有定义,在函数内部也可以直接将一个变量定义为全局变量,该函数执行后,将增加一个新的全局变量。
变量作用域的实操重点
如果需要在同一个程序的不同模块之间共享全局变量的话,可以编写一个专门的模块来实现这一目的。例如,假设在模块A.py
中有如下变量定义:
a=1
在B.py
中包含以下来设置全局变量
import A
A.a=2
在C.py
中有以下语句来访问全局变量
import A
print(A.a)