燕草如碧丝,
秦桑低绿枝。
——李白《春思》
本期文章8400字
根据之前文章的后台统计数据推算
本期预计所需阅读时间50分钟
关于return和返回值的补充解释
这是上一期的内容,有些难懂,补充说明一下。
函数有两种:有返回值的,没有返回值的。
有返回值的函数,可以直接理解为它会把写函数时定义的return的内容替换到调用此函数的位置。(后面会解释这句话)
没有返回值的函数主要是为了完成某种任务(其实这是废话,函数的功能就是为了完成某种任务)。这种函数完成任务后,函数执行期间的所有数据一律不再需要使用,这时候就不需要给这个函数定义return语句,也就是不需要返回任何值。来看例子:
deffunction(a, b):
answer= a + b
print(answer)
function(2, 9)
运行结果:
上面这个函数属于没有返回值那一类的,因为它没有return语句。11是由函数内部的print(answer)语句输出的。来看另一个例子:
deffunction(a, b):
answer= a + b
returnanswer
print ("line 1:")
function(2, 9)
print ("line 2:")
print(function(2, 9))
运行结果:
line 1:
line 2:
11
可以看到,上面这个函数是有返回值的。在函数内部并没有进行任何输出,所以
function(2, 9)
没有任何输出结果。输出结果中的11是由
print(function(2, 9))
这行代码输出的。在这里,
print(function(2, 9))
这行代码与下面这行代码的作用基本完全相同:
print(11)
这也就是上文说到的,有返回值的函数会把return的内容替换到调用此函数的位置。
同理可以举例,如果函数的定义与上面这个例子中的函数定义相同,那么:
function(2, 9) * 5
与
11 * 5
的计算结果也完全相同,都是55。
即使函数内部执行的是加法,最后输出的结果也不是2 + 9 * 5 == 47,而是(2 + 9)* 5 == 55。这也证明了返回值是直接替换到调用位置的。
OK,下面开始聊今天的内容。
注释
注释通常用于使代码更易于理解。 注释的内容不会影响代码的运行过程。
在Python中,通过插入一个井号(#)来创建注释。这个符号所在的行,在这个符号之后的所有文本都将作为注释。之前的文章说过,注释的内容不参与运行,只在代码编写的过程中显示出来,在运行时被忽略。来看例子:
x = 365
y = 7
# this is a comment
print(x % y)# find the remainder
# print (x // y)
# another comment
运行结果:
需要说明的是,C语言等编程语言有多行注释,但是Python没有那种东西。如果想注释多行,需要每行打一个#号。
但是,没有多行注释,我们可以曲线救国。
文档型字符串
Docstrings(文档型字符串)有时候被当做多行注释使用,因为在这种用法下,Docstrings与注释差不多,因为它们二者都可以写在源代码里去解释代码。但是,Docstrings更具体,并且创建注释和创建Docstrings的语法也不同。Docstrings是通过在函数的第一行下面放置一个包含函数说明的多行字符串来创建的。看例子:
defshout(word):
"""
This function
print a word
with an
exclamation mark (!)
following it.
"""
print(word + "!")
shout("spam")
运行结果:
>>>
spam!
>>>
在前面我们说字符串的时候(详见第二篇文章“始数”的内容),说到过这种三个引号的字符串,当时我们叫它是“一个由三对引号做开头和结尾的字符串”。可见,这东西实际上就是一个字符串。所以,在上面这个例子中,实际上被我们当成“多行注释”的东西是一个实实在在的字符串,但是由于这个字符串我们一直没有使用,所以就变成了一个在运行的时候没有用处的“注释”了。但是需要注意的是,与传统注释不同,因为这是以一个真正的字符串实现的“多行注释”,所以docstrings在整个程序运行时期间都是存在于程序中的,而非像普通注释那样在运行时完全被忽略。另外,这种三个引号的字符串也一样可以像普通字符串那样使用,用法详见第二篇文章。
“函数有时像变量一样”
这一小节的名字有点奇怪,但是很形象。我想说的是,虽然函数的创建方式(def语句)与普通变量(直接赋值产生)不同,但函数与任何其他类型的值在某种意义上是一样的。
我们可以将函数赋值给变量,然后由变量名去调用。看例子:
defmultiply(x, y):
return x * y
a = 4
b = 7
operation = multiply
print(operation(a, b))
运行结果:
可以看到,我们使用print函数输出的是operation(a, b),但是由于operation = multiply,所以operation与multiply成为了除名字外完全相同的函数,所以上面的例子的运行结果是成立的。
换种说法,上面的例子里,我们把函数赋予给了一个变量。之后,直接像调用原来的函数那样操作这个变量也相当于调用该函数。
测试题7.1.
代码的输出结果是?
def shout(word):
return word + "!"
speak = shout
output = speak("shout")
print(output)
点击下方空白区域查看答案
▼
shout!
嗯,应该比较好理解。
另外,一个函数也可以当做其他函数的参数。可以通过上面的“返回值原位置替换”来理解这件事。看例子:
defadd(x, y):
return x + y
defdo_twice(func, x, y):
returnfunc(func(x, y),func(x, y))
a = 5
b = 10
print(do_twice(add, a, b))
运行结果:
正如我们所见,do_twice这个函数将add函数作为其参数来使用(用刚讲过的“函数有时像变量一样”来理解),并且do_twice函数在其函数体内部调用add函数。
测试题7.2.
填空,使函数square作为另一个函数pass的一个参数。
____ square(x):
return x * x
def test(func, x)___
print(func(x))
test( ____ , 42)
点击下方空白区域查看答案
▼
def : square
完整代码如下:
defsquare(x):
return x * x
def test(func, x):
print(func(x))
test(square, 42)
模块(Modules)
模块是别人为了完成常见的任务而编写的代码片段,这些任务一般是Python自带功能无法直接完成的,例如生成随机数,执行复杂的数学运算等。
使用模块的基本方法是在代码顶部添加一行代码:
import模块名
然后使用
模块名.模块里的某个函数或变量名
来访问模块中现成的对应名称的函数或变量。
例如,下面这份代码使用random模块生成随机数:
import random
for i in range(5):
value =random.randint(1, 6)
print(value)
运行结果:
通过源代码可以看出,该代码使用random模块中的randint函数来输出1到6范围内的5个随机数。由于是随机数,所以每次运行的结果会不同,上面给出的只是某一种运行结果。
测试题7.3.
下面这份代码用到的模块的模块名是什么,调用的模块内部函数的函数名又是什么?
import math
num = 10
print (math.sqrt(num))
点击下方空白区域查看答案
▼
模块名是math,函数名是sqrt
看嘛,import后面是模块名。实际用到的时候,模块名后面的点,后面是调用的具体函数名。
当然,程序里面的无用代码越少越好。如果我们只需要某个模块中的部分功能,就不必完全导入完整的整个模块,我们可以使用另一种方式只把我们用得到的部分导入到我们的程序中。
这种导入方式的形式是
from模块名import所需部分名
然后可以直接调用我们用得到的那部分的名字就可以了,就像它在代码中正常定义之后一样。
注意区分:如果直接用“import模块名”的方式整体导入模块的话,调用所需内容的时候是要在所需内容名字前面加上模块名和点的;但是如果像现在说的这种部分导入方式,就相当于在我们自己的程序里直接定义好了所需部分,这种时候用到所需内容时不需再写来源模块名,直接写所需内容的名字就好。
例如,我们现在只需要用到π值,所以我们要从math模块中仅导入pi常量:
frommathimportpi
print(pi)
运行结果:
当然,我们需要的部分可能不止一个,这种情况在导入的时候可以用逗号分隔我们需要的部分的名字。来看例子:
from math import pi, sqrt
另外,星号(*)表示从模块导入所有这个模块内含有的对象。 例如:
from math import *
这样就把math模块里的所有对象(包括函数、常量、变量等)全部导入现在的程序里了。
通常我们不鼓励这样做,因为这种导入方式也属于“部分导入”,所以在之后的调用过程中是不需要写来源模块名的。这样批量导入很容易出现考虑不严谨的情况,出现导入的对象与原来自己代码中定义的对象重名的情况,如果这种事情真的发生了,在调用时,代码中自己定义的变量与导入进来的模块中的同名变量就很容易混淆,所以我们一般不用这种导入方式。
如果我们尝试导入一个不存在的模块,会导致ImportError。例如:
import some_module
运行结果:
>>>
ImportError: No module named 'some_module'
>>>
刚才说到过,直接导入模块的一部分,可能会与自己代码中的东西重名,所以Python设计时也考虑到了这一点。我们可以使用as关键字来以不同的名称导入模块或部分对象。这主要用于模块或对象具有比较长的名称(防止每次调用时都写这个过长的名称)或有混淆名称的情况。
例如:
from math import sqrtassquare_root
print(square_root(100))
运行结果:
>>>
10.0
>>>
可以看出来,上面这个例子里我们实际上用到的是math模块中sqrt这个函数(用途是开根号),但是我们在导入的时候给它重新命名成了square_root,所以在后面print语句里调用时,我们就用自己改的新名字square_root来调用了导入的这个函数。
有人问了,那改了名之后,原来的名字还可不可以拿来调用这个对象呢?来看测试题:
测试题7.4.
代码的输出结果是?
import math as m
print(math.sqrt(25))
领取专属 10元无门槛券
私享最新 技术干货