函数就是把一段代码封装起来,定义成一个函数,当要使用这段代码的时候,调用该函数即可。函数的作用在于减少重复代码,提高代码可读性,易于扩展。
一、先来看一个最简单的函数。
def first_func(): # 定义函数 #写逻辑 print('hello world!') first_func() #调用
--------------------------- hello world! #运行结果
函数定义规则:
def 函数名():
#函数逻辑
pass
函数调用方式:
函数名()
二、参数
def say_hi(name): #定义时的参数叫形参 print('Hi,', name) say_hi('Alex') # 调用时传入的参数叫实参 ---------------------- Hi, Alex
当参数有多个时,根据参数传入的方式分为位置参数、关键字参数、和非固定参数
1、位置参数,函数在调用时,实参和形参的位置必须一一对应,下面的例子如果调用时say_hi(20,'Alex'),则输出:20 is Alex years old.
def say(name, age): print('%s is %s years old.' % (name, age)) say('Alex', 20) ---------------------- Alex is 20 years old.
在定义函数时,可以给形参设置默认值,函数调用时如果不传该参数,则使用默认值,否则使用实传入的值。
有默认值的形参放到后边。
def say(name, age=20): print('%s is %s years old.' % (name, age)) def say2(name, age=20): print('%s is %s years old.' % (name, age)) say('Alex') -->Alex is 20 years old. say2('Alex', 30) -->Alex is 30 years old.
2、关键字参数,在函数调用时指定哪个形参的值是什么
def say(name, age=20): print('%s is %s years old.' % (name, age)) say(age=30, name='Alex') -->Alex is 30 years old.
当关键字参数和位置参数混合使用时,调用时位置参数在前,关键字参数在后。
3、非固定参数--*args和**kwargs
定义函数时使用*args和**kwargs,则在调用时可以传入任意数量的参数。
def say(*args, **kwargs): print('args: ', args) print('kwargs: ', kwargs) for item in args: print('Hi,', item) for j in kwargs: print('%s is eating.' % kwargs[j]) say('Alex', 'Rice', 'Black', p1='cat', p2='dag') ----------------------------------------------- args: ('Alex', 'Rice', 'Black') kwargs: {'p1': 'cat', 'p2': 'dag'} Hi, Alex Hi, Rice Hi, Black cat is eating. dag is eating.
可以看到,位置参数以元组形式传给了args,关键字参数以字典形式传给了kwargs(不能写成say_hi('Alex', 'Rice', p1='cat', p2='dag', 'Black'))
如果在调用的时候人为的传入列表、字典、或元组呢?
say_hi(*['Alex', 'Rice', 'Black'], **{'p1': 'cat', 'p2': 'dag'})
输出结果与上面是相同的。
def func(*args, name=1, **kwargs,): print(args) print(name) print(kwargs) return 1 a = func(11, 22, 33, x=123, y=456, ) b = func(11, 22, 33, name=123, x=123, y=456, ) c = func(11, 22, 33, x=123, y=456, name=123, ) ######################## (11, 22, 33) 1 {'x': 123, 'y': 456} (11, 22, 33) 123 {'x': 123, 'y': 456} (11, 22, 33) 123 {'x': 123, 'y': 456}
参数顺序:位置参数,args,默认值参数, kwargs
def f1(x, y, *args, z='2', **kwargs, ): print(z) print(args) print(kwargs) # 默认值参数位置 f1(1, 2, 'a', 'b', 5, 4, z='zz', q=3, w=123, e='456') f1(1, 2, 'a', 'b', 5, 4, q=3, z='zz', w=123, e='456')
三、返回值
函数的返回值用return,前面没写,默认返回None
def calc(a, b): result = a+b return 'result', result print('哈哈哈') ret = calc(1, 2) print(ret) ------------------- ('result', 3)
可以看出,打印函数的执行结果得到函数的返回值,返回值可以有多个,并且当遇到return时,函数结束。在程序中可以根据函数的返回值做一些相应的操作。
四、局部变量
尝试一下在函数内部修改变量
name = 'alex' # print(id(name)) def change_name(): # global name # 强改全局变量 name = '土豪' print('-->', name) # print(id(name)) change_name() print(name) ------------------------- --> 土豪 alex
what?为什么没有改成功呢,看一下ID吧,可以看到函数内部和外部的name其实是两个不同的变量,如果硬要改,就使用global关键字,声明name是全局变量,但是,不要随便这么用。
五、作用域
在python中,一个函数就是一个作用域。
name = "lzl" def f1(): name = "Eric" def f2(): name = "Snor" print(name) f2() f1()
name = "lzl" def f1(): print(name) def f2(): name = "eric" f1() f2()
name = "lzl" def f1(): print(name) def f2(): name = "eric" return f1 ret = f2() ret() >>:'lzl'
在函数未执行之前,作用域已经形成了,作用域链也生成了