本项目来源于和鲸社区,使用转载需要标注来源
- 作者: 和鲸社区
- 来源: 和鲸社区
2.Python基础_循环函数
🔖循环分支和函数
- 循环结构的应用场景 - 条件 / 缩进 / 代码块 / 流程图
- while循环 - 基本结构 / break语句 / continue语句
- for循环 - 基本结构 / range类型 / 循环中的分支结构 / 嵌套的循环 / 提前结束程序
- 定义函数 - def语句 / 函数名 / 参数列表 / return语句 / 调用自定义函数:
- 函数的参数 - 默认参数 / 可变参数 / 关键字参数 / 命名关键字参数
- 函数的返回值 - 没有返回值 / 返回单个值 / 返回多个值
- 作用域问题 - 局部作用域 / 嵌套作用域 / 全局作用域 / 内置作用域 / 和作用域相关的关键字
1. for循环
如果明确的知道循环执行的次数或者要对一个容器进行迭代(后面会讲到),那么我们推荐使用for-in循环,例如下面代码中计算1~100求和的结果。
1.1 for语句
for循环可以遍历任何可迭代对象,如一个列表或者一个字符串。
for循环的一般格式如下:
for <variable> in <sequence>:
<statements>
else:
<statements>
for 循环实例:
languages = ["C", "C++", "Perl", "Python"]
for x in languages:
print (x)
1.2 break
以下 for 实例中使用了 break 语句,break 语句用于跳出当前循环体:
sites = ["Baidu", "Google","jindong","Taobao"]
for site in sites:
if site == "jindong":
print("购物!")
break
print("循环数据 " + site)
else:
print("没有循环数据!")
print("完成循环!")
上面的代码中使用了break关键字来提前终止循环,需要注意的是break只能终止它所在的那个循环, 这一点在使用嵌套的循环结构(下面会讲到)需要引起注意。
除了break之外,还有另一个关键字是continue, 它可以用来放弃本次循环后续的代码直接让循环进入下一轮。
和分支结构一样,循环结构也是可以嵌套的,也就是说在循环中还可以构造循环结构。
下面的例子演示了如何通过嵌套的循环来输出一个九九乘法表。
for i in range(1, 10):
for j in range(1, i + 1):
print('%d*%d=%d' % (i, j, i * j), end='\t')
print()
range(1,10) 会生成一个数列,左闭右开,从 1 到 9 (不包含 10)
1.3 range()函数
如果你需要遍历数字序列,可以使用内置range()函数。它会生成数列,例如:
for i in range(5):
print(i)
0
1
2
3
4
利用range()函数计算1~100和:
sum = 0
for x in range(101):
sum += x
print(sum)
或者
sum = 0
for x in range(1,101):
sum += x
print(sum)
需要说明的是上面代码中的range(1, 101)可以用来构造一个从1到100的范围, 当我们把这样一个范围放到for-in循环中,就可以通过前面的循环变量x依次取出从1到100的整数。 当然,range的用法非常灵活,下面给出了一个例子:
- range(101):可以用来产生0到100范围的整数,需要注意的是取不到101。
- range(1, 101):可以用来产生1到100范围的整数,相当于左闭右开
- range(1, 101, 2):可以用来产生1到100的奇数,其中2是步长,即每次数值递增的值。
- range(100, 0, -2):可以用来产生100到1的偶数,其中-2是步长,即每次数字递减的值。
知道了这一点,我们可以用下面的代码来实现1~100之间的偶数求和。
sum = 0
for x in range(2, 101, 2):
sum += x
print(sum)
同样地,我们也可以求奇数和
sum = 0
for x in range(1, 100, 2):
print(x)
sum += x
print(sum)
当然,也可以通过在循环中使用分支结构的方式来实现相同的功能,代码如下所示。
sum = 0
for x in range(1, 101):
if x % 2 == 0:
sum += x
print(sum)
tips:相较于上面直接跳过奇数的做法,下面这种做法很明显并不是很好的选择。
可以结合range()和len()函数以遍历一个序列的索引,如下所示:
a = ['Google', 'Baidu', 'ModelWhale', 'Taobao', 'QQ']
for i in range(len(a)):
print(i, a[i])
2. while循环
如果要构造不知道具体循环次数的循环结构,我们推荐使用while循环。while循环通过一个能够产生或转换出布尔值的表达式来控制循环,表达式的值为True则继续循环;表达式的值为False则结束循环。
2.1 while语句
while 判断条件(condition):
执行语句(statements)
...
使用 while 来计算 1 到 100 的总和
n = 100
sum = 0
counter = 1
while counter <= n:
sum = sum + counter
counter += 1
print("1 到 %d 之和为: %d" % (n,sum))
2.2 无限循环
我们可以通过设置条件表达式永远不为 false 来实现无限循环,实例如下:
var = 1
while var == 1 : # 表达式永远为 true
num = int(input("输入一个数字 :"))
print ("你输入的数字是: ", num)
print ("Good bye!")
无限循环在服务器上客户端的实时请求非常有用。
2.3 while 循环使用 else 语句
如果 while 后面的条件语句为 false 时,则执行 else 的语句块。
语法格式如下:
while <expr>:
<statement(s)>
else:
<additional_statement(s)>
写一个猜数字的游戏,游戏的规则如下:
计算机出一个1到100之间的随机数,玩家输入自己猜的数字,计算机给出对应的提示信息(大一点、小一点或猜对了), 如果玩家猜中了数字,计算机提示用户一共猜了多少次,游戏结束,否则游戏继续。
import random
# 随机取1~100之间的一个整数
answer = random.randint(1, 100)
counter = 0
while True:
counter += 1
number = int(input('请输入: '))
if number < answer:
print('大一点')
elif number > answer:
print('小一点')
else:
print('恭喜你猜对了!')
break #猜对即停止while循环
print('你总共猜了%d次' % counter)
if counter > 7:
print('你真棒')
2.4 简单语句组
类似if语句的语法,如果你的while循环体中只有一条语句,你可以将该语句与while写在同一行中, 如下所示:
3. 函数
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
函数能提高应用的模块性,和代码的重复利用率。
你已经知道Python提供了许多内建函数,比如print()。 但你也可以自己创建函数,这被叫做用户自定义函数。
3.1 定义一个函数
你可以定义一个由自己想要功能的函数,以下是简单的规则:
- 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()。
- 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
- 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
- 函数内容以冒号:起始,并且缩进。
- return [表达式] 结束函数,选择性地返回一个值给调用方,不带表达式的 return 相当于返回 None。
3.2 语法
定义函数使用 def 关键字,一般格式如下:
def 函数名(参数列表):
函数体
默认情况下,参数值和参数名称是按函数声明中定义的顺序匹配起来的。
实例1 让我们使用函数来输出”Hello World!”
def hello() :
print("Hello World!")
hello()
更复杂点的应用,函数中带上参数变量:
实例2 比较两个数,并返回较大的数
def max(a, b):
if a > b:
return a
else:
return b
a = 4
b = 5
print(max(a, b))
实例3 计算面积函数
def area(width, height):
return width * height
w = 4
h = 5
print("width =", w, " height =", h, " area =", area(w, h))
3.3 函数调用
定义一个函数:给了函数一个名称,指定了函数里包含的参数,和代码块结构。
这个函数的基本结构完成以后,你可以通过另一个函数调用执行,也可以直接从 Python 命令提示符执行。
如下实例调用了 printme() 函数:
# 定义函数
def printme( str ):
# 打印任何传入的字符串
print (str)
return
# 调用函数
printme("我要调用用户自定义函数!")
printme("再次调用同一函数")
3.4 参数
以下是调用函数时可使用的正式参数类型:
- 必需参数
- 关键字参数
- 默认参数
- 不定长参数
必需参数
必需参数须以正确的顺序传入函数。调用时的数量必须和声明时的一样。
调用 printme() 函数,你必须传入一个参数,不然会出现语法错误:
#可写函数说明
def printme( str ):
"打印任何传入的字符串"
print (str)
return
# 调用 printme 函数,不加参数会报错
printme()
关键字参数
关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。
使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。
以下实例在函数 printme() 调用时使用参数名:
#可写函数说明
def printme( str ):
"打印任何传入的字符串"
print (str)
return
#调用printme函数
printme( str = "我爱编程")
以下实例中演示了函数参数的使用不需要使用指定顺序:
#可写函数说明
def printinfo( name, age ):
"打印任何传入的字符串"
print ("名字: ", name)
print ("年龄: ", age)
return
#调用printinfo函数
printinfo( age=50, name="张三" )
默认参数
调用函数时,如果没有传递参数,则会使用默认参数。以下实例中如果没有传入 age 参数,则使用默认值:
#可写函数说明
def printinfo( name, age = 35 ):
"打印任何传入的字符串"
print ("名字: ", name)
print ("年龄: ", age)
return
#调用printinfo函数
printinfo( age=50, name="张三" )
print ("------------------------")
printinfo( name="张三" )
不定长参数
你可能需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数,和上述 2 种参数不同,声明时不会命名。基本语法如下
def functionname([formal_args,] *var_args_tuple ):
"函数_文档字符串"
function_suite
return [expression]
加了星号 *的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数。
# 可写函数说明
def printinfo( arg1, *vartuple ):
"打印任何传入的参数"
print ("输出: ")
print (arg1)
print (vartuple)
# 调用printinfo 函数
printinfo( 70, 60, 50 )
3.5 return语句
return [表达式] 语句用于退出函数,选择性地向调用方返回一个表达式。不带参数值的return语句返回None。
之前的例子都没有示范如何返回数值,以下实例演示了 return 语句的用法:
# 可写函数说明
def sum( arg1, arg2 ):
# 返回2个参数的和."
total = arg1 + arg2
print ("函数内 : ", total)
return total
# 调用sum函数
total = sum( 10, 20 )
print ("函数外 : ", total)
4. 变量的作用域
最后,我们来讨论一下Python中有关变量作用域的问题。
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()
上面的代码能够顺利的执行并且打印出100、hello和True,但我们注意到了,在bar函数的内部并没有定义a和b两个变量,那么a和b是从哪里来的。
我们在上面代码的if分支中定义了一个变量a,这是一个全局变量(global variable),属于全局作用域,因为它没有定义在任何一个函数中。在上面的foo函数中我们定义了变量b,这是一个定义在函数中的局部变量(local variable),属于局部作用域,在foo函数的外部并不能访问到它;但对于foo函数内部的bar函数来说,变量b属于嵌套作用域,在bar函数中我们是可以访问到它的。bar函数中的变量c属于局部作用域,在bar函数之外是无法访问的。 事实上,Python查找一个变量时会按照“局部作用域”、“嵌套作用域”、“全局作用域”和“内置作用域”的顺序进行搜索,前三者我们在上面的代码中已经看到了,所谓的“内置作用域”就是Python内置的那些标识符,我们之前用过的input、print、int等都属于内置作用域。
再看看下面这段代码,我们希望通过函数调用修改全局变量a的值,但实际上下面的代码是做不到的。
def foo():
a = 200
print(a) # 200
if __name__ == '__main__':
a = 100
foo()
print(a) # 100
在调用 foo 函数后,我们发现 a 的值仍然是 100 ,这是因为当我们在函数 foo 中写 a = 200 的时候,是重新定义了一个名字为 a 的局部变量,它跟全局作用域的 a 并不是同一个变量, 因为局部作用域中有了自己的变量 a ,因此 foo 函数不再搜索全局作用域中的 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 并将其置于全局作用域。
同理,如果我们希望函数内部的函数能够修改嵌套作用域中的变量,可以使用 nonlocal 关键字来指示变量来自于嵌套作用域,请大家自行试验。
✍作业
1. 找出10000以内的完美数,保存到列表L1中。
说明:完美数又称为完全数或完备数,它的所有的真因子(即除了自身以外的因子)的和(即因子函数)恰好等于它本身。
例如:$6(6=1+2+3)$ 和 $28(28=1+2+4+7+14)$ 就是完美数。完美数有很多神奇的特性,有兴趣的可以自行了解。
暴力枚举
def sum_of_proper_divisors(n):
"""返回n的所有真因数之和"""
if n < 2:
return 0
divisors_sum = 1 # 1 是所有大于1的数的真因数
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0:
divisors_sum += i
if i != n // i and n // i != n:
divisors_sum += n // i
return divisors_sum
L1 = []
for num in range(2, 10001):
if sum_of_proper_divisors(num) == num:
L1.append(num)
print("10000以内的完美数:", L1)
数学公式 偶完美数的形式为: \(2 ^ {p-1} (2 ^ p - 1)\)
其中 $ 2 ^ p - 1 $ 是一个梅森素数(Mersenne Prime)。我们枚举一些小的 p 值来生成完美数,并检查是否小于等于 10000
def is_mersenne_prime(p):
"""检查 2^p - 1 是否是素数(即是否产生完美数)"""
mersenne = (1 << p) - 1 # 计算 2^p - 1
if mersenne < 2:
return False
for i in range(2, int(mersenne ** 0.5) + 1):
if mersenne % i == 0:
return False
return True
L1 = []
p_values = [2, 3, 5, 7, 11, 13] # 小于 2^13 的结果已超过 10000
for p in p_values:
if is_mersenne_prime(p):
perfect_number = (1 << (p - 1)) * ((1 << p) - 1)
if perfect_number <= 10000:
L1.append(perfect_number)
print("10000以内的完美数:", L1)
L1 = [6, 28, 496, 8128]
2. 寻找1000内的水仙花数,并保存到列表L2中;
tips:水仙花数也被称为超完全数字不变数、自恋数、自幂数、阿姆斯特朗数,它是一个3位数,该数字每个位上数字的立方之和正好等于它本身, 例如:\(1^3 + 5^3 + 3^3=153\)
def is_narcissistic(num):
digits = list(map(int, str(num)))
n = len(digits)
return sum(digit ** n for digit in digits) == num
L2 = [num for num in range(1, 1000) if is_narcissistic(num)]
print("1000以内的水仙花数:", L2)
L2 = [153, 370, 371, 407]
3. 写一个程序查询300到500内的回文素数,并保存到列表L3中;
回文素数(Palindromic Prime) 是指既是回文数,又是素数的数。
- 回文数(Palindrome):正着读和反着读一样的数字。例如:121、131。
- 素数(Prime):只能被 1 和它本身整除的大于 1 的自然数。例如:2, 3, 5, 7, 11 等。
def is_palindrome(n):
return str(n) == str(n)[::-1]
def is_prime(n):
if n < 2:
return False
for i in range(2, int(n**0.5)+1):
if n % i == 0:
return False
return True
L3 = [num for num in range(300, 501) if is_palindrome(num) and is_prime(num)]
print("300到500之间的回文素数:", L3)
L3 = [313, 353, 373, 383]