def foo():
pass
foo()
输出为空。
其中 pass 是占位符。
def my_max(x, y):
return x if x > y else y
print(my_max(10, 20))
其中 x if x > y else y 是三目运算,类似于Java里的 x > y ? x : y 。
结果如下:
20
def my_sum_and_avg(my_list):
s = 0
a = 0
count = len(my_list)
for e in my_list:
s += e
a = s / count
return s, a
list1 = [10, 20, 30, 100]
result = my_sum_and_avg(list1)
print(result)
s1, a1 = my_sum_and_avg(list1)
print(s1, a1)
结果如下:
(160, 40.0)
160 40.0
前面在调用函数时,是通过位置来指定参数,此外也可以通过关键字(形参名字)来指定参数:
def foo(width, height, age):
print("width = ", width, "height = ", height, "age = ", age)
foo(100, 200, 20)
foo(height=100, age=30, width=200)
foo(100, age=20, height=150)
结果如下:
width = 100 height = 200 age = 20
width = 200 height = 100 age = 30
width = 100 height = 150 age = 20
注意:位置和关键字混合使用时,关键字参数必须在位置参数之后。
下面的用法会报错:
foo(100, width=200, age=20)
因为第一个参数是位置参数,一定会绑定到 width 参数,如果后面再次指定 width 参数,会报错: TypeError: foo() got multiple values for argument 'width'
在定义函数时,可以给参数指定默认值。
注意:带默认值的参数必须在没有默认值的参数之后。
def foo(age, width=10, height=20):
print("age = ", age, "width = ", width, "height = ", height)
foo(20, 100, 200)
foo(20)
foo(20, 100)
结果如下:
age = 20 width = 100 height = 200
age = 20 width = 10 height = 20
age = 20 width = 100 height = 20
*args :位置参数;**kwargs 关键字参数;args 和 kwargs 可以任意命名,惯例是使用 args 和 kwargs 。
def foo(*args, **kwargs):
print("args: ", args)
print("kwargs: ", kwargs)
print()
foo(1, 2, 3)
foo(a=1, b=2, c=3)
foo(1, 2, 3, a=4, b=5, c=6)
结果如下:
args: (1, 2, 3)
kwargs: {}
args: ()
kwargs: {'a': 1, 'b': 2, 'c': 3}
args: (1, 2, 3)
kwargs: {'a': 4, 'b': 5, 'c': 6}
若函数需要多个参数,而调用函数时,只传一个参数(如列表,元组,字典),则会自动拆开。
***def foo(width, height):
print("width = ", width, "height = ", height)
list1 = [100, 200]
foo(*list1)
tuple1 = (10, 20)
foo(*tuple1)
dict1 = {"height": 1, "width": 2}
foo(**dict1)
dict2 = dict(height=1, width=2)
foo(**dict2)
结果如下:
width = 100 height = 200
width = 10 height = 20
width = 2 height = 1
width = 2 height = 1
name = "Tom"
def foo():
age = 20
print(name, age)
foo()
print(name)
结果如下:
Tom 20
Tom
没有问题,在函数内部可以访问全局变量。
但是如果(在访问全局变量之后)试图修改其值,会报错:
name = "Tom"
def foo():
print(name)
name = "Jerry"
foo()
报错如下:
UnboundLocalError: local variable 'name' referenced before assignment
这是因为在函数内部的 name = "Jerry" 会产生一个新的局部变量。
同理,如果在函数内部只给 name 赋值:
name = "Tom"
def foo():
name = "Jerry"
print("before:", name)
foo()
print("after:", name)
结果如下:
before: Tom
after: Tom
在函数内修改 name, 并不影响全局变量,这是因为函数里的 name 是一个新的局部变量,并不是那个全局的 name 。
若要修改/修改全局变量,有两种方法:
global <变量名> 声明:name = "Tom"
def foo():
global name
name = "Jerry"
print("before:", name)
foo()
print("after:", name)
结果如下:
before: Tom
after: Jerry
global() 函数访问:name = "Tom"
def bar():
print(globals()['name']) # 显式使用全局变量name
name = "Jerry" # 该name是局部变量
print("before:", name)
bar()
print("before:", name)
结果如下:
before: Tom
Tom
before: Tom
前面的函数都是在全局范围内定义的,叫做全局函数,而在函数内定义的函数叫做局部函数。
默认情况下,局部函数对外不可见,只在其封闭(enclosing)函数内有效:
def foo():
def bar():
print("hello")
bar()
foo()
结果如下:
hello
在 foo() 函数之外是不能直接访问 bar() 函数的。
如果局部函数需要访问其上级(全局函数)定义的变量,也有前面提到的作用域问题,需要先用 nonlocal 声明一下:
def foo():
name = "Tom"
def bar():
nonlocal name
print(name)
name = "Jerry"
bar()
print(name)
foo()
结果如下:
Tom
Jerry
注意:如果没有 nonlocal name ,程序会报错 UnboundLocalError: local variable 'name' referenced before assignment 。
函数本身也可以当做变量来使用。注意函数当变量时,后面不要加括号,否则就变成函数调用了。
def foo():
print("hello")
bar = foo
bar()
结果如下:
hello
同理,函数也可以当作参数或者返回值。
def my_fun():
print("hello")
def foo(bar):
bar()
foo(my_fun)
结果如下:
hello
def foo():
def my_fun():
print("hello")
return my_fun
foo()()
结果如下:
hello
foo()() 也可以写成如下形式:
bar = foo()
bar()
可以用lamda表达式来简化局部函数。
def foo(bar):
bar()
foo(lambda: print("hello"))
结果如下:
hello
def foo():
return lambda: print("hello")
foo()()
结果如下:
hello
函数作为参数和返回值:
def foo(fn):
def bar(*args, **kwargs):
print(fn.__name__, "before")
fn(*args, **kwargs)
print(fn.__name__, "after")
return bar
def myfunc1():
print("hahaha")
def myfunc2(a, b, c):
print("good")
print(a, b, c)
foo(myfunc1)()
foo(myfunc2)("aa", c="bb", b="cc")
结果如下:
myfunc1 before
hahaha
myfunc1 after
myfunc2 before
good
aa cc bb
myfunc2 after
上面的写法,可用 @<函数名 的方式来简化:
def foo(fn):
def bar(*args, **kwargs):
print(fn.__name__, "before")
fn(*args, **kwargs)
print(fn.__name__, "after")
return bar
@foo
def myfunc1():
print("hahaha")
@foo
def myfunc2(a, b, c):
print("good")
print(a, b, c)
myfunc1()
myfunc2("aa", c="bb", b="cc")
当使用 @foo 修饰 myfunc1 的函数定义时,相当于 foo(myfunc1) 。同时将 myfunc1 替换为 foo(myfunc1) 的返回值,本例中也就是 bar 函数。
这有点类似于Spring里面的AOP。