一、函数定义
def 函数名(参数列表):
函数体
判断一个数是不是素数?
# 方法一:for 循环判断素数
num = int(input('请输入一个正整数:'))
for i in range(2,int(num**0.5)+1):
if not num%i:
print(f'{num} 不是素数')
break
else:
print(f'{num} 是素数')
# 方法二:自定义函数判断素数
def isPrime(n):
'''
判断素数 # 这里是函数的说明文档,doc的位置
:param list: n 是自然数 # 参数列表的说明
:return: bool # 返回值的说明
'''
for i in range(2,int(n**0.5)+1):
if not n%i:
return False
else:
return True
# print('这一行永远运行不到!')
# 2 到100 之内素数的和
primes=[i for i in range(2,100) if isPrime(i)]
print(sum(primes))
print(isPrime.__doc__)
二、return
return [表达式] 语句用于退出函数,选择性地向调用方返回一个表达式。
不带参数值的 return 语句或缺省 return 返回 None。
返回多个值会自动打包成一个元组,接收可用多个变量(解包)也可用一个变量(元组)
def fun():pass
print('No return:', fun())
def fun():return
print('Return:', fun())
def fun():return 1, 2, 3, 4
print(fun())
三、调用
所谓调用就是附带可能为空的一系列 参数 来执行一个可调用对象。
用户定义的函数,内置函数,内置对象的方法,类对象,类实例的方法以及任何具有 call() 方法的对象都是可调用对象。
print(dir(isPrime))
# isPrime.__call__() 函数是可调用的 它有 __call__() 方法
print(isPrime.__call__(97))
# 'abc'() # TypeError: 'str' object is not callable
参数列表在函数被调用时需要赋值,定义时会初始化默认参数值,函数体只有当函数被调用时才会执行。
default = 12
def function(parameter=default): # 定义时会初始化默认参数值
print(f'This is a function {parameter}') # 定义时不会打印,调用后才执行
default = 13
function()
四、参数
形参 是指出现在函数定义中的名称,而 实参 则是在调用函数时实际传入的值。 形参定义了一个函数能接受何种类型的实参。 例如,对于以下函数定义:
def mymax(x,y):
return x if x > y else y
print(mymax(10, 20))
1、位置参数
又称为必需参数,须以正确的顺序传入函数。调用时的数量必须和声明时的一样。
print(mymax(10, 20))
# 调用函数时,如果参数个数或类型不对,Python 解释器会自动检查出来,并抛出 TypeError
# print(mymax(2))
# TypeError: mymax() missing 1 required positional argument: 'y'
# print(mymax(2, 3, 1))
# TypeError: mymax() takes 2 positional arguments but 3 were given
# print(mymax(3, 'a'))
# TypeError: '>' not supported between instances of 'int' and 'str'
2、默认(缺省、可选)参数
当一个或多个 形参 具有 形参 = 表达式 这样的形式时,该函数就被称为具有“默认形参值”。 对于一个具有默认值的形参,其对应的 argument 可以在调用中被省略,在此情况下会用形参的默认值来替代。如果一个形参具有默认值,后续所有在 “*” 之前的形参也必须具有默认值 。
def mypow(x, n=2):
t = 1
for i in range(n):
t *= x
return t
i,j = 2,3
print('{} 的 {} 次方:{}'.format(i, j, mypow(i,j)))
print('{} 的平方:{}'.format(j, mypow(j)))
仅当定义函数时,默认参数进行初始化。
i = 5
def f(arg=i):
print(arg)
i = 6
f()
print(f.defaults) # defaults 查看函数的默认值参数的当前值,其返回值是一个元组
**默认形参值会在执行函数定义时按从左至右的顺序被求值。**这意味着当函数被定义时将对表达式求值一次,相同的“预计算”值将在每次调用时被使用。 这一点在默认形参为可变对象,如果函数修改了该对象(例如向列表添加了一项),则实际上默认值也会被修改。绕过此问题的一个方法是使用 None 作为默认值,并在函数体中显式地对其进行测试,例如:
def f(a, l=[]):
l.append(a)
return l
print(f('x'))
print(f('y'))
def f(a, l=None):
if l is None:
l = []
l.append(a)
return l
print(f('x'))
print(f('y'))
3、关键字参数
关键字参数是指函数调用时使用形参名来确定传入的参数值。
指定函数实参时,不需要与形参的位置一致,因为 Python 解释器能够用参数名匹配参数值。
注意:关键字参数是在调用时指定,形参可以是位置参数,也可以是默认参数
def func(a, b, c=4):
print('a = {},b = {}, c = {} '.format(a, b, c))
return a+b+c
print(func(1, c=3, b=2))
# b, c 是关键字参数必须放在 a 的后面
4、动态参数 又称不定长参数
有时可能需要一个函数能处理比当初声明时更多的参数,声明时不会命名。
加了星号 * 的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数。
def mysum(*args):
print(args)
return sum(args)
print(mysum(1,2,3,4,5))
print(mysum(*[1,2,3,4,5]))
print(mysum(*(1,2,3,4,5)))
print(mysum(*{1:2,2:3})) # 注意 字典关键字类型
# 可变参数就是允许在调用参数的时候传入多个(≥0个)参数(类似于列表、字典)
# 这些参数在传入时被自动组组装为一个元祖
def func(arg1, *vartuple, arg2=2):
'打印任何传入的参数'
print(arg1, vartuple, arg2)
func(70,60,50)
# 如果在函数调用时没有指定参数,它就是一个空元组。我们也可以不向函数传递未命名的变量。
# 声明函数时,参数中星号 * 可以单独出现,* 后的参数必须用关键字传入。例如:
def f(a,b,*,c):
return a+b+c
print(f(1,2,c=3))
# 加了两个星号 ** 的参数会以字典的形式导入。
def func(arg1,**vardict):
"打印任何传入的参数"
print (arg1)
print (vardict)
func(1, a=2, b=3)
func(1, **{'a':2,'b':3})
*args 是可变参数,args 接收的是一个 tuple (list dict 等),被组装成 tuple。
**kw 是关键字参数,kw 接收的是一个 dict。
以及调用函数时如何传入可变参数和关键字参数的语法:
可变参数既可以直接传入:func(1, 2, 3),又可以先组装 list 或 tuple,再通过 args 传入:func((1, 2, 3));
关键字参数既可以直接传入:func(a=1, b=2),又可以先组装 dict ,再通过 kw 传入:func({‘a’: 1, ‘b’: 2})。
5、强制位置参数
Python3.8 新增了一个函数形参语法 /
用来指明函数形参必须使用指定位置参数,不能使用关键字参数的形式。
在以下的例子中,形参 a 和 b 必须使用指定位置参数,c 或 d 可以是位置形参或关键字形参,而 e 或 f 要求为关键字形参:
def f(a, b, /, c, d, *, e, f):
print(a, b, c, d, e, f)
f(10, 20, 30, d=40, e=50, f=60)
命名的关键字参数是为了限制调用者可以传入的参数名,同时可以提供默认值。
定义命名的关键字参数在没有可变参数的情况下不要忘了写分隔符 *,否则定义的将是位置参数。
小结
参数定义顺序:位置参数、*args、关键字参数,默认参数、**kwargs
def func(arg1, *vartuple, arg3, arg4=4, **vardict):
print(arg1, vartuple, arg3, arg4, vardict)
func(1, 2, 2, 2, 2, arg3=3, a=5, b=5, c=5)
# func(1, *(2,2), arg3=3, **{'a':5,'b':5})
def func(*a, **b):
print(a)
print(b)
func(*(1, 2), **{'a':3, 'b':4})
def f(a, b, c=3, *d, e=5, g, **k):
print(a, b, c, d, e, g, k)
f(1,2,10,4,4,4,g=6,h=7,l=7)
# 1 2 10 (4, 4, 4) 5 6 {'h': 7, 'l': 7}
f(1,2,g=6,h=7,l=7)
# 1 2 3 () 5 6 {'h': 7, 'l': 7}
f(1,2,g=6)
# 1 2 3 () 5 6 {}
# a,b,c位置参数
# d为可变位置参数
# e为默认参数
# h,l为关键字参数
# g为命名关键字参数
# 可变参数 *args 允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个 tuple。*args 接收多余的位置参数
# 而关键字参数 **kvargs 允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个 dict。
# 在定义命名的关键字参数时,需要使用 * 将命名的关键字参数和位置参数分开。
# 默认参数 * 前为位置参数默认 * 后为关键字参数默认
parameter – 形参
function (或方法)定义中的命名实体,它指定函数可以接受的一个 argument (或在某些情况下,多个实参)。有五种形参:
positional-or-keyword:位置或关键字,指定一个可以作为 位置参数 传入也可以作为 关键字参数 传入的实参。这是默认的形参类型,例如下面的 foo 和 bar:
def func(foo, bar=None): …
positional-only:仅限位置,指定一个只能通过位置传入的参数。 仅限位置形参可通过在函数定义的形参列表中它们之后包含一个 / 字符来定义,例如下面的 posonly1 和 posonly2:
def func(posonly1, posonly2, /, positional_or_keyword): …
keyword-only:仅限关键字,指定一个只能通过关键字传入的参数。仅限关键字形参可通过在函数定义的形参列表中包含单个可变位置形参或者在多个可变位置形参之前放一个 * 来定义,例如下面的 kw_only1 和 kw_only2:
def func(arg, *, kw_only1, kw_only2): …
var-positional:可变位置,指定可以提供由一个任意数量的位置参数构成的序列(附加在其他形参已接受的位置参数之后)。这种形参可通过在形参名称前加缀 * 来定义,例如下面的 args:
def func(*args, **kwargs): …
var-keyword:可变关键字,指定可以提供任意数量的关键字参数(附加在其他形参已接受的关键字参数之后)。这种形参可通过在形参名称前加缀 ** 来定义,例如上面的 kwargs。
形参可以同时指定可选和必选参数,也可以为某些可选参数指定默认值。
argument – 实参
在调用函数时传给 function (或 method )的值。参数分为两种:
关键字参数: 在函数调用中前面带有标识符(例如 name=)或者作为包含在前面带有 ** 的字典里的值传入。举例来说,3 和 5 在以下对 complex() 的调用中均属于关键字参数:
complex(real=3, imag=5)
complex(**{‘real’: 3, ‘imag’: 5})
位置参数: 不属于关键字参数的参数。位置参数可出现于参数列表的开头以及/或者作为前面带有 * 的 iterable 里的元素被传入。举例来说,3 和 5 在以下调用中均属于位置参数:
complex(3, 5)
complex(*(3, 5))
参数会被赋值给函数体中对应的局部变量。有关赋值规则参见 调用 一节。根据语法,任何表达式都可用来表示一个参数;最终算出的值会被赋给对应的局部变量。
五、空函数
def nop():
pass
# pass 语句什么都不做,实际上 pass 可以用来作为占位符,
# 比如现在还没想好怎么写函数的代码,就可以先放一个 pass,
# 让代码能运行起来。
# pass 还可以用在其他语句里,比如:
age=19
if age >= 18:
pass
练习
1、请定义一个函数 quadratic(a, b, c),接收3个参数,返回一元二次方程 ax2+bx+c =0 的两个解。
一元二次方程的求根公式为:,计算平方根可以调用math.sqrt()函数
import math
def quadratic(a, b, c):
pass
# 测试:
print('quadratic(2, 3, 1) =', quadratic(2, 3, 1))
print('quadratic(1, 3, -4) =', quadratic(1, 3, -4))
if quadratic(2, 3, 1) != (-0.5, -1.0):
print('测试失败')
elif quadratic(1, 3, -4) != (1.0, -4.0):
print('测试失败')
else:
print('测试成功')
2、以下函数允许计算两个数的乘积,请稍加改造,变成可接收一个或多个数并计算乘积:
def product(x, y):
return x * y
# 测试
print('product(5) =', product(5))
print('product(5, 6) =', product(5, 6))
print('product(5, 6, 7) =', product(5, 6, 7))
print('product(5, 6, 7, 9) =', product(5, 6, 7, 9))
if product(5) != 5:
print('测试失败!')
elif product(5, 6) != 30:
print('测试失败!')
elif product(5, 6, 7) != 210:
print('测试失败!')
elif product(5, 6, 7, 9) != 1890:
print('测试失败!')
else:
try:
product()
print('测试失败!')
except TypeError:
print('测试成功!')
3、不要上机测试,仅凭代码,你能说出打印的结果吗?
def func(a=[]):
a.append("A")
return a
print(func())
print(func())
print(func())