函数
数据类型检查
数据类型检查可以用内置函数 isinstance()
实现:
def my_abs(x):
if not isinstance(x, (int, float)): #如果传入错误的参数类型,函数就可以抛出一个错误
raise TypeError('bad operand type')
if x >= 0:
return x
else:
return -x
函数参数
变量引用查找顺序:首先在局部符号表中查找,然后是包含函数的局部符号表,然后是全局符号表,最后是内置名字表。 默认情况下,所有函数中的变量赋值都是将值存储在局部符号表。 因此,全局变量不能在函数中直接赋值(除非用 global 语句命名),尽管他们可以被引用。
global
在函数内部定义的变量拥有一个局部作用域,在函数外定义的拥有全局作用域。
在函数内部可以引用全局变量,但无法对其赋值(除非用 global 进行声明)
x, y = 1, 2
def func():
global x #声明全局变量
x = 10 #给全局变量重新赋值
y = 20 #给局部变量赋值,它和全局变量同名
func()
print(x, y) #输出结果:10 2
注:你可以使用同一个 global 语句指定多个全局变量。例如 global x, y, z
nonlocal
还有一种作用域叫做“非局部”域,处于全局和局部这两种作用域之间。
非局部作用域在你定义函数内的函数时会看到。
a = 100 #这是一个全局变量,这里是全局作用域
def func_outer():
x = 2 #外层局部作用域
print(x)
def func_inner():
nonlocal x
x = 5
func_inner()
print(x)
func_outer() #输出结果:2 5
注:对于func_inner 的内部来说,func_outer中定义的 ’x’ 既不是在当前局部范围也不是在全局的作用域中,使用这样的 x 称之为非局部 x。
位置参数
def print_max(a, b):
pass
print_max(1,2)
默认参数
有默认参数值的参数不能位于没有默认参数值的参数之前。
def print_max(a, b=2):
pass
print_max(1)
函数默认值在函数定义点( 即defining scope)进行计算,并且只计算一次。如果默认值是一个可变对象是要小心,在后续调用过程中会累积(前面)传给它的参数。
例1:
i = 5
def f(arg=i):
print(arg)
i = 6
f() #输出:5
例2:
def f(a, L=[]): #如果想避免累积问题,应该定义L=None
L.append(a)
return L
print(f(1)) #输出:[1]
print(f(2)) #输出:[1,2]
print(f(3)) #输出:[1,2,3]
定义默认参数要牢记一点:默认参数必须指向不变对象,否则容易掉入陷阱!!!
Keyword参数(关键字参数)
使用名字(关键字)而不是位置来给函数指定实参。
def print_max(a, b):
pass
print_max(b=2, a=1)
可变参数
可变参数允许你传入 0 个或任意个参数。
- 当我们声明一个诸如
*param
的星号参数时,从此处开始直到结束的所有位置参数都将被收集并打包成一个名为 param 的元组( tuple); - 当我们声明一个诸如
**param
的双星号参数时,从此处开始直至结束的所有关键字参数都将被收集并打包成一个名为 param 的字典( dict );
举例:
def func(*args, **kw):
print(args)
print(kw)
这里,args 接收的是一个 tuple,kw 接收的是一个 dict。 使用
*args
和**kw
是 Python 的习惯写法,当然也可以用其他参数名,但最好使用习惯用法。
解包出参数列表:*
操作符可以从序列或可迭代对象解包出参数;**
操作符可以从dict解包出关键字参数;
a = [1,2,3]
b = {'p1':100, 'p2':200}
func(*a, **b)
Keyword-only 参数
如果想指定特定的关键参数为 keywor-only 而不是位置参数,可以用分隔符*
申明。 *
后面的参数被视为Keyword-only参数。
keywor-only参数必须传入参数名,keywor-only参数可以有默认值,从而简化调用。举例:
def person(name, *, city='Beijing', job):
print(name, city, job)
person('erick',job='engineer')
person('erick',city='sz',job='engineer')
参数定义的顺序
参数定义的顺序必须依次是:必选参数、默认参数、可变参数/命名关键字参数、关键字参数
def f1(a, b, c=0, *args, **kw):
print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
def f2(a, b, c=0, *, d, **kw):
print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)
运行如下:
>>> f1(1, 2)
a = 1 b = 2 c = 0 args = () kw = {}
>>> f1(1, 2, c=3)
a = 1 b = 2 c = 3 args = () kw = {}
>>> f1(1, 2, 3, 'a', 'b')
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {}
>>> f1(1, 2, 3, 'a', 'b', x=99)
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99}
>>> f2(1, 2, d=99, ext=None)
a = 1 b = 2 c = 0 d = 99 kw = {'ext': None}
return
三者等价:
- 函数末尾没有return
- 函数末尾只有一个return
- return None
返回多个值
函数可以通过返回一个元组来实现返回多个值。
def hi():
return (1,2) #语法上返回一个 tuple 可以省略括号,所以还可以直接写: return 1,2
a, b = hi() #多个变量可以同时接收一个 tuple,序列解包后按位置赋给对应的值
ret=func(1,2)
print(a, b) #输出: 2 3
print(ret) #输出: (2,3)
函数注解(Function Annotations)
函数注解是是可选的注释信息,用于描述函数形参和返回值。
Parameter annotation格式: 形参名:注解表达式 = 形参默认值
Return annotations格式: -> 注解表达式
举例:
def func(name: str, age: int = 100) -> str:
print(func.__annotations__)
return 'ok'
func('erick')
#输出结果:{'name': <class 'str'>, 'age': <class 'int'>, 'return': <class 'str'>}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论