在编程解决问题时,会有很多问题重复,这样的话我们使用的代码也是重复的,如果我们再把代码全部重写一遍的话,这样是非常不明智的,因此我们可以将这些重复功能的函数封装到一个代码块中,当我们要解决相应的问题再去调用这个代码块,即调用相应的函数。
简而言之,一个函数就是将一些语句集合在一起的部件,它们能够不止一次地在程序中运行。
我们定一函数的时候,会用到def关键字,函数的基本结构如下所示:
def <name> (arg1,arg2,...,argn):
<statements>
在python中使用def来定义函数,后面name的部分就是函数的名字,括号里的arg1,arg2…argn为传入的参数。当函数中的内容执行完成后,如果需要就是用return关键字返回相应的值,如果不需要返回值,可以不用return。
下面是有关函数的几个例子:
'''
例1:求阶乘并打印
'''
def factorial(num):
result = 1
for n in range(1,num+1):
result = result*n
return result
n = int(input())
# 直接调用已经定义好的阶乘函数
print(factorial(n))
说明:说明: Python的math模块中其实已经有一个factorial函数了,事实上要计算阶乘可以直接使用这个现成的函数而不用自己定义。
函数的参数
在python中,函数的参数可以有默认值,也可以使用可变参数,所以Python并不需要像其他语言一样支持函数的重载,因为我们在定义一个函数的时候可以让它有多种不同的使用方式。
'''
例2:函数参数默认值小例子
'''
from random import randint
#摇色子
def roll_dice(n=2):
total = 0
for _ in range(n):
total = total + randint(1,6)
return total
#返回求和
def add(a=0, b=0, c=0):
return a+b+c
#如果没有指定,则默认摇色子摇两次
print(roll_dice())
#指定要几次色子
print(roll_dice())
print(add())
print(add(1))
print(add(1, 2))
print(add(1, 2, 3))
# 传递参数时可以不按照设定的顺序进行传递
print(add(a=50, c=100, b=200))
但是,有很多时候存在需要传入几个参数个数不确定的情况,因此这个时候就需要使用可变参数,如例3
'''
例3:使用可变参数求和
'''
#参数名字前加*表示为args是一个可变参数
def add(*args):
total = 0
for val in args:
total = total + val
return total
#在调用add函数时可以传入0个或多个参数
print(add())
print(add(1))
print(add(1, 2))
print(add(1, 2, 3))
print(add(1, 3, 5, 7, 9))
使用模块管理函数
在实际的开发过程中,会遇到函数重名的情况,上边说过在python中函数不能重载,所以遇到函数重名的情况,我们会用模块化的方法来解决。
def foo():
print('hello, world!')
def foo():
print('goodbye, world!')
foo()
对于上述代码,编译器无法判断要先输出哪个,因此我们采用如下的方法解决:
module1.py
def foo():
print('hello, world!')
module2.py
def foo():
print('goodbye, world!')
test.py
from module1 import foo
# 输出hello, world!
foo()
from module2 import foo
# 输出goodbye, world!
foo()
也可以采用以下方法:
test.py
import module1 as m1
import module2 as m2
m1.foo()
m2.foo()
在python中也有像C语言中main函数,如下所示
def foo():
pass
def bar():
pass
# __name__是Python中一个隐含的变量它代表了模块的名字
# 只有被Python解释器直接执行的模块的名字才是__main__
if __name__ == '__main__':
print('call foo()')
foo()
print('call bar()')
bar()
一些小例子
'''
例4:定义函数求两个数的最大公因数和最小公倍数
'''
#求最大公因数
def gcd(x,y):
if y > x:
temp = x
x = y
y = temp
for i in range(x, 0, -1):
if x%i==0 and y%i==0:
return i
#求最小公倍数
def lcm(x,y):
m = x*y // gcd(x,y)
return m
print(gcd(30,45))
print(lcm(30,45))
在这里有一个公式:两个数的成绩=两个数的最大公因数*最小公倍数
'''
例5:定义函数判断一个数是否为素数
'''
def is_prime(num):
for i in range(2,num):
if num % i == 0:
return False
return True
if is_prime(5):
print('Yes')
else:
print('No')
当我们将代码中重复出现的和相对独立的功能抽取成函数后,我们可以组合使用这些函数来解决更为复杂的问题,这也是我们为什么要定义和使用函数的一个非常重要的原因。
变量作用域
def foo():
b = 'hello'
# Python中可以在函数内部再定义函数
def bar():
c = True
print(a)
print(b)
print(c)
bar()
# print(c) # NameError: name 'c' is not defined
if __name__ == '__main__':
a = 100
# print(b) # NameError: name 'b' is not defined
foo()
对于以上的程序,主函数中的a变量为全局变量(global variable),属于全局作用域,因为它没有定义在任何一个函数中。在foo()函数中的b变量这是一个定义在函数中的局部变量(local variable),属于局部作用域,在foo函数的外部并不能访问到它;但对于foo函数内部的bar函数来说,变量b属于嵌套作用域,在bar函数中我们是可以访问到它的。bar函数中的变量c属于局部作用域,在bar函数之外是无法访问的。事实上,Python查找一个变量时会按照“局部作用域”、“嵌套作用域”、“全局作用域”和“内置作用域”的顺序进行搜索。
def foo():
a = 200
print(a) # 200
if __name__ == '__main__':
a = 100
foo()
print(a) # 100
对于上面这段代码,由于foo函数中定义的a属于局部变量,只在该函数的内部能够访问,而main中的函数属于全局变量,所以在给全局变量a赋值后调用foo函数无法改变全局变量a的值。两者只是名字相同,但实质上根本就是两个不同内存空间。
def foo():
global a
a = 200
print(a) # 200
if __name__ == '__main__':
a = 100
foo()
print(a) # 200
我们可以使用global关键字来指示foo函数中的变量a来自于全局作用域,如果全局作用域中没有a,那么下面一行的代码就会定义变量a并将其置于全局作用域。
注意:在开发过程中应该避免全局变量的使用(迪米特法则)
以下为python函数的最基本框架:
def main():
# Todo: Add your code here
pass
if __name__ == '__main__':
main()
参考资料:
[1]https://github.com/jackfrued/Python-100-Days
[2]《Python学习手册(第4版)》