在程序里面,我们定义一个函数通常是为了将这部分代码重复使用。你可以为一个函数指定名字,定义可执行的语句。让它加班加点的为我们做重复劳动,压榨机器人的价值。
之前我们使用过的 type
与 print
就是函数。
type(10)
这里 type
就是函数名,括号中的 10 是一个参数。参数是我们传给函数的值或变量。type
函数这里的作用是返回参数的类型,此时类型就是 type
的返回值。
python 提供了一些内建函数使我们无需定义就能直接使用。
例如下面的 max
与 min
函数的作用是返回所给参数中的最大值和最小值。
print('最大值:', max(1, 8, 3, 5))
print('最小值:', min(1, 8, 3, 5))
输出
最大值: 8
最小值: 1
len
函数则能告诉我们一个字符串中有多少个字符。
print(len('小明是个傻X'))
输出
6
len
函数还可计算一些类型的成员数,这将在之后提到。
python 中提供了一些函数给我们转换类型,它们同样属于内建函数。例如 int
、str
和 float
。
例如 n
虽然书面意思是数字,但被包含在单引号中属于 str
类型。我们只需用 int
函数就能转换其为 int
类型。
n = '123'
print(type(n))
n = int(n)
print(type(n))
输出
<class 'str'>
<class 'int'>
同样我们可以用 float
对带小数的 str
类型进行同样操作。
n = '34.12'
print(type(n))
n = float(n)
print(type(n))
输出
<class 'str'>
<class 'float'>
当然我们也可以用 str
进行类型转换。
n = 34.12
print(type(n))
n = str(n)
print(type(n))
输出
<class 'float'>
<class 'str'>
Python 提供了 math
模块供我们进行一些数学上的操作。
在引入其他模块时我们使用的是 import
关键字。我们在引入之后直接 print
可以看到一些基本信息,并且能通过 print(math.**doc**)
查看其自身的描述。
import math
print(math)
print(math.__doc__)
输出
<module 'math' (built-in)>
This module provides access to the mathematical functions
defined by the C standard.
引入 math 模块后我们往往一脸茫然无可下手,不知其能干嘛不知如何去使用。
用内建的 dir
函数能帮我们看到模块内部都有什么方法。
print(dir(math))
输出
['__doc__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'comb', 'copysign', 'cos', 'cosh', 'degrees', 'dist', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'isqrt', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'perm', 'pi', 'pow', 'prod', 'radians', 'remainder', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc']
看到这些方法是不是有一股熟悉的感觉,我们还可以调用方法的 doc 方法知道他的基本描述。
print(math.log.__doc__)
print(math.pow.__doc__)
输出
log(x, [base=math.e])
Return the logarithm of x to the given base.
If the base not specified, returns the natural logarithm (base e) of x.
Return x**y (x to the power of y).
学好英语很重要,能帮我们省去绕很多弯路的力气,直达问题的最终答案。不然要靠百度去吸收二手答案,可想会耗费多大力气。
接着我们完成一个运用勾股定理对直角三角形求斜边的程序。
import math
a = float(input('请输入一个直角边长度:'))
b = float(input('请输入另一个直角边长度:'))
print('斜边的长度是:', math.sqrt(math.pow(a, 2) + math.pow(b, 2)))
随机是我们日常生活中不或缺的一部分,比如我们抽奖是一个随机事件,天气是一个随机事件,晚上回家吃什么大概率也是个随机事件。
python 里面的 random
模块就提供了生成随机数的方法。random
模块中的 random
方法的作用是返回一个 0 到 1 的浮点数(包括 0 不包括 1)。
我们下面打印了三个随机数,每次都不一样。
import random
print(random.random())
print(random.random())
print(random.random())
输出
0.7174432452813149
0.8797376860445014
0.22724064581942438
我们还能用 randint
方法,返回一个随机的整数。randint
方法接收两个参数 a
和 b
,返回 a
与 b
之间的数(包括 a
与 b
)。
import random
print(random.randint(1, 5))
print(random.randint(1, 5))
print(random.randint(1, 5))
输出
2
5
4
此时我们就能用 randint 方法决定我们晚饭吃啥了(下面的写法比较累赘,我们之后学到列表时会有更好的写法)。
import random
choice = random.randint(1, 5)
if choice == 1:
print('吃鱼')
elif choice == 2:
print('吃虾')
elif choice == 3:
print('吃面')
elif choice == 4:
print('吃肉')
elif choice == 5:
print('吃土')
输出
吃土
我今晚吃土,你们呢?
到目前为止我们都还是用的 python 的内建函数,我们同样也可以自己定义一些函数。函数的目的是为了封装一些重复性的代码,避免重复造轮子,同时方便将功能直接给其他开发者调用。
下面我们定义一个函数,接着调用它。
def say_hello():
print('叔叔阿姨早上好')
print('哥哥姐姐晚上好')
say_hello()
输出
叔叔阿姨早上好
哥哥姐姐晚上好
def
在这里表明我们定义了一个函数,后面紧接着的就是其函数名say_hello
。函数名的选择类似于变量名,应避开 python 的关键字,不能以数字开头,尽量使名字有意义等。
函数名后面的空括号()
表示这个函数不需要传递任何参数。
def say_hello():
为其函数头的定义。从:
往后的内容是函数的执行代码块。一般另起一行,以缩进(Tab)
作为区分。
需要注意的是,python 是从上到下顺序执行的,因此 say_hello 的定义必需在其调用之前。
以下是错误示范,say_hello 的调用在其定义之前。
say_hello()
def say_hello():
print('叔叔阿姨早上好')
print('哥哥姐姐晚上好')
报错
Traceback (most recent call last):
File ".\first.py", line 1, in <module>
say_hello()
NameError: name 'say_hello' is not defined
为了保证你在调用函数之前就已经定义了函数,你需要了解 python 中的执行顺序。
python 中的执行永远从文件的第一行语句开始,从上到下顺序执行。
当执行到函数的定义部分时,会略过函数内部的代码块继续往下执行。
当执行到函数的调用部分时,会跳到函数内部执行代码,直到函数中的语句执行完成,并返回到调用的位置继续执行。
函数中也可以调用其他的函数。
我们通过编写下面的程序验证一下。
print(1)
def a():
print(4)
print(2)
def b():
print(3)
a()
b()
print(5)
输出
1
2
3
4
5
在函数定义时,上下空行不是必须的,但加上空行的话会让代码看起来更清晰。同样在写一段长代码时,不同意义的部分,比如 import 语句,变量的定义,执行语句,与不同含义的逻辑代码块间,同样可以插入空行,保证代码的可读性。
在之前使用一些内建函数的时候,我们就已经接触过参数。例如对于 print 函数,他的参数是我们要打印的东西。对于 math.pow,他的参数有两个,底数与幂数。
我们同样可以在自定义函数中添加参数。
在下面的例子中,我们在定义函数的同时指定了一个形参
name
,并且在调用时各自用 '叔叔阿姨'
与 '哥哥姐姐'
作为实参
进行了传值。
在函数内部便可对传进来的值进行操作。
def say_hello(name):
print(name + '早上好')
say_hello('叔叔阿姨')
say_hello('哥哥姐姐')
输出
叔叔阿姨早上好
哥哥姐姐早上好
我们还可以定义多个参数,这样在使用时便可依次按照顺序
传递值。
例如:
def eating(name, something):
print(name + '正在吃' + something)
eating('小明', '土')
输出
小明正在吃土
唉,吃土的生活,男默女泪。
在之前使用 random.randint
函数时,使用了一个变量接收其返回的值。我们同样可以在我们的函数中返回值。
下面的例子中,我们定义一下函数对输入的两个参数进行求和运算,并且返回所得结果。
def addtwo(a, b):
added = a + b
return added
x = addtwo(3, 5)
print(x)
输出
8
如果一个函数并没有使用 return
返回一个值,那它的返回值将是 None
。
def addtwo(a, b):
added = a + b
x = addtwo(3, 5)
print(x)
输出
None
函数在执行到 return
时意味着结束,在 return
之后的代码将不会再被执行。从下面的例子可以看出,print('小明爱吃瓜')
并没有被执行。
def addtwo(a, b):
added = a + b
return added
print('小明爱吃瓜') # 这里并没有被执行到
x = addtwo(3, 5)
print(x)
输出
8
It may not be clear why it is worth the trouble to divide a program into functions. There are several reasons:
Creating a new function gives you an opportunity to name a group of statements, which makes your program easier to read, understand, and debug.
Functions can make a program smaller by eliminating repetitive code. Later, if you make a change, you only have to make it in one place.
Dividing a long program into functions allows you to debug the parts one at a time and then assemble them into a working whole.
Well-designed functions are often useful for many programs. Once you write and debug one, you can reuse it.
Throughout the rest of the book, often we will use a function definition to explain a concept. Part of the skill of creating and using functions is to have a function properly capture an idea such as “find the smallest value in a list of values”. Later we will show you code that finds the smallest in a list of values and we will present it to you as a function named min which takes a list of values as its argument and returns the smallest value in the list.