定义函数
定义函数用def语句,格式:def 函数名(自变量) :函数名称的定义规则和变量定义规则相同。在缩进板块中编写函数体,最后用return返回一个值。
求n的阶乘
def f(x) :
"""
计算阶乘
:param x: 一个非负整数
:return: x的阶乘
"""
y = 1
for n in range(1, x + 1) :
y *= n
# return表示返回一个值,同时结束此函数
return y
注意:函数内部一旦执行到return,该函数就会停止执行,并将结果返回。如果没有return语句,函数执行完毕就会停止,返回的是一个空值none。
求最大公约数
def gcd(x, y):
"""
计算两个数的最大公约数
:param x: 一个非负整数
:param y: 一个非负整数
:return: x,y的最大公约数
"""
(x, y) = (y ,x) if x > y else (x, y)
for factor in range(x, 0, -1):
if x % factor == 0 and y % factor == 0:
return factor
判断素数
def is_prime(x):
"""
判断素数
Parameters:
x - 一个非负整数
y - 一个非负整数
Returns:
如果num是素数返回True,反之返回False
"""
for num in range (2,int(sqrt(x)) + 1):
if x % num == 0:
return False
# return True
# 排除1的写法:
return True if x != 1 else False
-
函数自变量的四种定义方式:
1.不设定自变量
def main():
pass
2.自变量为确定个数的参数,如上面的is_prime函数,自变量为1个,即x;gcd函数,自变量为2个,即x,y
3.自变量为不确定的参数
如下举例说明:
在参数数量不确定的情况下,求多个数的和
利用*args 定义可变参数:*args 参数数量不确定,可为0个,也可为多个。在调用函数add时,输入的自变量为多少个,函数就求多少个数的和。
def add(*args):
"""
参数数量不确定的情况下,求多个数的和
:param argus:
*args 定义可变参数:*args 参数数量不确定,可为0个,也可为多个
:return: 多个参数的和
"""
total = 0
for value in args:
total += value
return total
if __name__ == '__main__':
# 直接传入可变参数
# 求的是1+3+2+2+2+2的和
print(add(1,3,2,2,2,2))
# 传入列表,求列表中各个元素的和
mylist = [1, 3, 5, 2, 10]
# 如果传入的直接就是一个列表,必须在列表前面加上*,才能取到列表中各个元素,否则会被视为只传入了一个值,即列表
print(add(*mylist))
4.自变量设定了默认值
定义摇n个色子,求每次色子点数之和的函数,假设我们给自变量一个默认值,可设置为“n=2”格式,如下:
def roll_dice(n=2):
total = 0
for _ in range (n) :
total += randint(1, 6)
return total
if __name__ == '__main__':
# 调用函数,但未定义自变量,自变量取默认值2
roll_dice()
# 调用函数,定义自变量的值为3
roll_dice(3)
注意:在定义函数自变量时,官方建议不要用空格,如定义自变量为n,并给n赋一个默认值2,官方建议的书写格式为:n=2,而不是n = 2。但在其他情况下,官方建议的书写格式为:n = 2。
空函数
如果想定义一个什么事也不做的空函数,可以用pass语句。pass语句的意义:什么都不做,实际上是用来做占位符。比如现在还没有想好怎么写函数的代码,就可以先放一个pass,程序可以顺利运行。
举例说明:
def nop():
pass
pass还可以放在其他语句中,如:
if x<1:
pass
函数的调用
一个文件就是一个模块,一个模块中可能有1个或任意多个函数
-
当前模块中调用函数
调用函数时,若函数就在当前文本,则可以直接进行调用。格式为:函数名(变量)。由于很多时候这一个函数会被其他文本调用,为了让其他文本在调用此函数时不执行其他的代码,可以使用下面的if条件语句,让其他文本在导入此模块时不执行下面的代码,原理:只有本文件执行时,name = main,当其他文件执行时,name = 这个文件的命名,则name != main,if条件不成立,代码不执行。
-
其他模块调用函数
若当前文本需要调用其他文本的函数,则需要引入调用的函数模块。
1.同一跟目录下的两个文本函数之间调用:from 要调用的函数所在文本的名称 import 函数名称
2.不同根目录下的两个文本函数直接的调用:from 要调用的函数所在文本的路径(如day01.practice.prime,表示day01包下面的practice包下面的prime文本)import 函数名称
3.一个文本可能存在多个函数,若需要调用此文本的所有函数,可写作如下格式:import combination * 导入combination中所有模块
#导入 combination文件中所有模块
import combination *
4.直接引入函数所在文本,每次调用时再输入:文件名.函数名称。若原本的文件名太过复杂,还可临时给他命一个新的名字(别名):import combination as com 此处把combination命为com,在调用时,写作com.f
import combination
#调用cobination的f(x)函数
print(com.f(5))
-
实例说明
1.直接调用输出内容
打印100以内的素数:
if __name__ == '__main__':
for num in range(1,100):
# 当is_prime(num)函数返回的值为True时,if条件语句才会执行
if is_prime(num):
print(num)
调用求阶乘函数:f(x),求组合数C(m, n)
m = int(input('m = '))
n = int(input('n = '))
# 调用函数f(x)
print(f(m) // f(n) // f(m - n))
2.调用函数构造新的函数
求最小公倍数,lcm函数调用cgd函数
def lcm(x,y):
"""
计算两个数的最小公倍数
Parameters:
x - 一个非负整数
y - 一个非负整数
Returns:
x,y的最小公倍数
"""
return x * y // gcd(x, y)
3.函数的递归调用
函数的递归调用指的是函数直接或间接调用函数自身,构造这样的递归函数必须满足以下几点:
1.收敛条件 - 让递归在有限的次数完成或者进行回溯
2.如果递归无法在有限次数内收敛就有可能导致RecursionError,而且栈的空间很小,必须控制此函数的递归深度在栈的递归深度内。
3.递归公式
在进入函数调用之前要保存当前的执行现场,函数的执行现场是保存在一种称为栈(stack)的内存空间上,栈是一种先进后出(FILO)的存储结构。所以函数在做递归调用时,会一层一层向下递归,最后在一层一层回溯。
求最大公约数
def gcd(x, y):
if x > y:
return gcd(y, x)
elif y % x == 0:
return x
else:
return gcd(y % x, x)
求1到100的和
def add(n):
if n == 1 :
return 1
return n + add(n - 1)
计算走楼梯有多少种方式
10级楼梯,1次可选择1,2,3层台阶,走完这10层台阶,问有多少种走法
def way(n):
if n < 0:
return 0
elif n == 0:
return 1
return way(n - 1) + way(n - 2) + way(n - 3)
汉诺塔
def hanoi(n, a, b, c):
if n > 0:
hanoi(n - 1, a, c, b)
print(a,'---->', b)
hanoi(n - 1, c, b, a)
函数命名冲突
当有多个函数命名冲突时,后面的函数自动覆盖前面相同名称的函数。
-
自己设定的函数和python内置的函数冲突:
如自己编写了一个求最大公约数的函数gcd,和math中的内置的gcd函数冲突
from combination import gcd,
from math import gcd
调用gcd函数时,如果直接书写gcd(),文本会自动调用写在后面的那个函数,如上就会调用math中的gcd,为了避免这种情况,可以按照以下方式调用:
# 方法一
import combination
import math
print(math.gcd())
print(combination.gcd())
# 方法二
from combination import gcd
# 调用的是conbinaion中的gcd函数
print(gcd())
from math import gcd
# 调用的是math中的gcd函数
print(gcd())
函数变量的作用域
变量的作用域有三种:
1.全局(global)作用域的变量:定义在函数外部的变量,此变量可在全局范围内被调用
2.嵌套(enclosed)作用域的变量:当一个函数调用另一个函数时,定义在外层函数中的变量,此变量可被内外层函数调用
3.局部(local)作用域:当一个函数嵌套在另一个函数内部时,定义在内层函数中的变量,此变量只能被内层函数调用
4.内置(build-in)作用域
Python 搜索一个变量的方式是从局部作用域到嵌套作用域再到全局作用域,如果都没有搜索到,则会搜索内置函数,简称为LEGB(Local - Enclosed - Global - Build-in),如果想改变搜索范围,可以使用global和nonlocal关键字改变变量的作用域。
举例说明:
# 在函数外面定义的a是一个全局变量
# 实际开发时一定要减少对全局变量的使用
# global variable
a = 100
def foo():
# 把foo函数内的变量a改为全局变量,这时如果在函数外调用a,当搜索到此处的a = 200时,原本变量a不能在函数外被调用,但此处变量a改为了全局变量,则能被函数外的代码调用
global a
a = 200
# local variable
# 函数内部的局部变量 离开foo函数变量是无法访问的
b = 'hello'
def bar():
# 把局部作用域bar中的变量b改为嵌套作用域foo中的局部变量b,这时如果在foo中调用b,则搜索到的是b = 'good',而不是之前的b = 'hello'
nonlocal b
b = 'good'
print(a)
print(b)
bar()
print(b)
# foo()函数运行结果:200 good good
foo()
# 运行结果:200
print(a)