python课程记录-2

  1. 下面程序的运行结果是( )

    1
    2
    3
    4
    5
    6
    for i in range(3):
    for j in range(3):
    if i == j == 1
    break
    else:
    print(i, '----', j)

    A. 0 —— 0 B. 0 —— 0
    ​ 0 —— 1 0 —— 1
    ​ 0 —— 2 0 —— 2
    ​ 1 —— 0 1 —— 0
    ​ 2 —— 0
    ​ 2 —— 1
    ​ 2 —— 2

答案:A(我怀疑这题的选项对齐在网页上显示会出问题,不过懒得改了)

break的中断只会断一层,也就是说这个代码在i=j=1的时候,属于j的循环会中断,j=2j=3将跳过,直接开始i=2, j=0然后继续循环,也就是A选项。

  1. 下面程序的运行结果是( )

    1
    2
    3
    4
    5
    6
    7
    8
    9
    for i in range(3):
    for j in range(3):
    if i == j == 1:
    break
    else:
    print(i, '----', j)
    else:
    continue
    break

    A. 0 —— 0 B. 0 —— 0
    ​ 0 —— 1 0 —— 1
    ​ 0 —— 2 0 —— 2
    ​ 1 —— 0 1 —— 0
    ​ 2 —— 0
    ​ 2 —— 1
    ​ 2 —— 2

答案:B

这里首先要学习的是python与其他语言中不太一样的else用法,在其他语言中,else只搭配if来做条件判断,而python中有for... else...while...else...try...else...的用法,具体来说,在for循环中如果有并触发了break,则for循环后的else语句不会被执行,如果没触发或者没有,则会执行else分支的语句;在while循环中,也是如此,break不执行或不存在的时候,就会执行else语句,而如果执行了break就不会执行elsetry中的用法则是当try块中的语句正常执行完毕就会执行else分支。

其次,continue在循环中是用来跳过这次循环并开始下一次循环,比如在j=1的时候continue,则j=1中剩下的语句不执行,但是会开始执行j=2,而不是像break那样跳出j的循环去执行i的循环。

分析这个代码,这个else分支是j的循环对应的,也就是说i=0,j=x时,没触发break,每次都会执行else中的continue,也就是说此时最后一行的打断i的循环的break不会执行;在i=j=1的时候j的循环break了,那么else分支不会执行,就会执行到最后一行的break,从而打断i的循环,程序直接结束,也就是B选项。

课后作业:

  1. 利用random库,随机出100道两个数的加、减口算题。要求 : (1)a+b或者a-b,a、b和得数范围均为[0,100];(2)如果是加法运算,要求有进位;如果是减法运算,要求有退位;(3)在屏幕上打印出结果,每一行显示4道题,注意对齐。示例如下。(示例就不放了总之就是100个加减法运算题,加法有进位减法有借位,输出是格式化的)

这个本来是不难的,随机生成两个100以内的数字然后随机决定加减法就行,但是还必须有进位和退位。

一开始的思路是,先随机生成第一个数字a,然后再随机生成01来决定加减法,接下来如果是加法,就生成一个在a100-a之间的数字b,如果是减法,就生成一个在1a之间的数字b,这两个分支中,如果b不符合进位或者退位,就重新生成,也就是一个while循环。

按这个思路写好运行以后就发现了问题,那个while循环有时候会一直循环下去就是找不到符合进位或退位的数字b,这是因为一开始的数字a如果不合适,那什么数字也没法实现进位或者退位,比如加法中,个位数如果是0,这个数字还不是90,则无论如何也不会遇到进位;而减法中,这个数字如果个位是9,题目又要求不会出现负数的减法,那无论如何都不可能有借位运算。也就是说,先决定加减法,再生成一个恰当的数字a,它要符合一些条件,接着生成一个恰当的数字b,也要符合一些条件。

具体来说,数字a要符合:

    1. 如果是加法,则个位数不是0,或这个数不是90,且范围在1到90之间;
     2. 如果是减法,则个位数不是9,且范围在10到100之间。

数字b要符合:

    1. 如果是加法,则小于`100-a`,且个位数之和大于10,或十位数之和大于10;
    2. 如果是减法,则小于`a`,且个位数比`a`的个位数大,或十位数比`a`的十位数大。

最后就是格式化输出,然后就结束了,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import random
for i in range(0, 100):
bool = random.randint(0, 1)
if bool == 0:
a = random.randint(1, 90)
while a != 90 and a % 10 == 0:
a = random.randint(1, 90)
b = random.randint(1, 100 - a)
while ((a % 10 + b % 10) < 10) and ((a // 10 + b // 10) < 10):
b = random.randint(1, 100 - a)
print('{:<2} + {:<2}='.format(a, b), end="\t\t")
else:
a = random.randint(10, 100)
while a % 10 == 9:
a = random.randint(10, 100)
b = random.randint(1, a)
while ((b % 10) <= (a % 10)) and ((b % 100) <= (a % 100)):
b = random.randint(1, a)
print('{:<2} - {:<2}='.format(a, b), end="\t\t")
if i % 4 == 3:
print('\n')

补充一下关于print格式化输出的内容:

python中的print函数有一个end参数,当直接print而没有end时,默认换行;当end=""时,就不自动换行了;当end=XXX时,在print后,会接着有XXX,比如上面代码的\t\t,也不自动换行。

C语言中,可以通过prints("%d, %d", a, b)来实现输出a, b,并通过%x.yd(比如%5.3d)来控制输出长度和精度,而python中有类似的用法,即str.format(),其基本语法是通过{}:来代替%'{:<2} - {:<2}='.format(a, b)这样的语句含义是:把ab按默认顺序填入前面的花括号,并把长度控制为2个字符且左对齐。

format()的用法很多。

可以接受不限个数和顺序的参数:

1
2
3
4
5
6
7
8
>>>"{} {}".format("hello", "world")    # 不设置指定位置,按默认顺序
'hello world'

>>> "{0} {1}".format("hello", "world") # 设置指定位置
'hello world'

>>> "{1} {0} {1}".format("hello", "world") # 设置指定位置
'world hello world'

可以指明参数:

1
2
3
4
5
6
7
8
9
print("网站名:{name}, 地址 {url}".format(name="菜鸟教程", url="www.runoob.com"))

# 通过字典设置参数
site = {"name": "菜鸟教程", "url": "www.runoob.com"}
print("网站名:{name}, 地址 {url}".format(**site))

# 通过列表索引设置参数
my_list = ['菜鸟教程', 'www.runoob.com']
print("网站名:{0[0]}, 地址 {0[1]}".format(my_list)) # "0" 是必须的

可以向format传入对象:

1
2
3
4
5
class AssignValue(object):
def __init__(self, value):
self.value = value
my_value = AssignValue(6)
print('value 为: {0.value}'.format(my_value)) # "0" 是可选的

数字格式化输出的完整形式如下:

数字 格式 输出 解释
3.1415926 {:.2f} 3.14 保留小数点后两位
3.1415926 {:+.2f} +3.14 带符号保留小数点后两位
-1 {:+.2f} -1.00 带符号保留小数点后两位
2.71828 {:.0f} 3 不带小数
5 {:0>2d} 05 数字补零 (填充左边, 宽度为2)
5 {:x<4d} 5xxx 数字补x (填充右边, 宽度为4)
10 {:x<4d} 10xx 数字补x (填充右边, 宽度为4)
1000000 {:,} 1,000,000 以逗号分隔的数字格式
0.25 {:.2%} 25.00% 百分比格式
1000000000 {:.2e} 1.00e+09 指数记法
13 {:>10d} 13 右对齐 (默认, 宽度为10)
13 {:<10d} 13 左对齐 (宽度为10)
13 {:^10d} 13 中间对齐 (宽度为10)

^,<, > 分别是居中、左对齐、右对齐,后面带宽度, : 号后面带填充的字符,只能是一个字符,不指定则默认是用空格填充。+ 表示在正数前显示 +,负数前显示 -; (空格)表示在正数前加空格。

此外,还可以转进制输出,bdox 分别是二进制、十进制、八进制、十六进制。

1
2
3
4
5
6
'{:b}'.format(11) --> 1011
'{:d}'.format(11) --> 11
'{:o}'.format(11) --> 13
'{:x}'.format(11) --> b
'{:#x}'.format(11) --> 0xb
'{:#X}'.format(11) --> 0XB
  1. 编写程序,求解所有由两个四位数组成的亲和数。(如果两个正整数a和b满足:a的所有真因数(除本身以外的因数)之和等于b,同时b的所有真因数之和等于a,则称a,b是一对亲和数 。)

思路是先写一个算真因数之和的函数,接着写两层循环,第一层a是1000到9999,第二层b是1000到a,然后调用函数判断ab的真因数之和是否符合条件。一个整数n的真因数之和是很好计算的,只需要遍历1到n//2+1看是否整除n,然后把整除的累加一下,就可以了。

但是实际运行的时候,发现这样搞真的很慢,要等好久才会出结果,这是因为两层for循环,每次都要算两个真因数的和,而这也是一层循环,再加上python本身就效率很低,速度就格外慢了,因此最好的办法是能去掉一层循环,或者有什么库可以飞快地计算真因数之和。

然后在查资料的过程中,看到了另一种亲和数的定义:先求出数字n所有真因数之和a,然后再求出数字a所有真因数之和b。如果a!= bn==b,则abn都是亲和数。

也就是说,可以只写一层循环a,计算a的真因数之和b,再计算b的真因数之和sum_b,如果a=sum_b,则符合条件输出一下,反之就直接继续下一次循环,算真因数之和的部分没有变化。这样循环少了一层,运算速度快了好多。

此外,看到一个不是用取余,而是用除法和整除结果来判断是否是因数的代码:

1
2
3
4
5
6
def d(n):  #计算数字n所有真因数之和
res = 0
for i in range(1, n//2+1):
if n/i == float(n//i):
res += i
return(res)

猜测python中的除法、整除、取余可能有运算时间的差别,不过应该不大。

最后代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 计算一个数的真因数和
def sum_of_factor(n):
sum = 0
for i in range(1, n // 2 + 1):
if n % i == 0:
sum += i
return sum
for a in range(1000, 9999):
b = sum_of_factor(a)
if b <= a:
sum_b = sum_of_factor(b)
if sum_b == a:
print(a, b)
  • Copyrights © 2020-2024 Kun Li

请我喝杯咖啡吧~

支付宝
微信