随机生成姓名
- 需要把“姓”与“名”分为两组常用字,所以可以定义两个列表;
- 需要从两个列表中随机抽取一个字,于是可以使用 random.sample;
- 需要让每一次 sample 取出的字数都不固定,在一个字和两个字之间随机确定,因此可以将其参数指定为 randint(1,2);
- 需要让名字列表中出现重复文字,从而实现“叠字”姓名,因此可以使用列表乘法;
- 需要从文件中将全体常用字读入列表,因此可以使用 fopen 或 xlwings 等方法。
from random import sample, randint姓 = ['赵', '钱', '孙', '李']名 = ['慧', '芝', '雅', '琳', '秋', '月', '虹', '云']名 = 名 * 2名单 = []while len(名单) < 20:人物 = ''.join(sample(姓, 1) + sample(名, randint(1, 2)))if 人物 not in 名单:名单.append(人物)print(名单)
['钱月', '孙云', '赵虹秋', '李云芝', '孙琳', '赵琳', '钱琳云', '钱慧', '钱芝月', '孙虹', '赵雅云', '李雅琳', '赵琳云', '赵雅', '孙慧', '钱云雅', '钱琳', '孙芝虹', '孙虹雅', '赵月芝']
控制 while 循环:
将计数器更新操作( i+=1 )放到判断语句中,只有在成功添加新姓名后才更新计数器,从而确保生成的姓名总数(而while本身的执行次数则变得不确定)。
可迭代对象(iterable)
zip对象
zip()函数在执行合并操作后,返回的并不是一个列表,而是一个zip对象。
zip对象属于一种 “可迭代对象” (实际上是“可迭代对象”中的“迭代器(iterator)”,轮流出列,逐个访问)
迭代(iterate)
按某种顺序逐个访问
所有容器类型的对象,都是可迭代对象,都支持for循环这种迭代过程
可迭代对象不仅包括列表等各种容器,还包括range、zip等其他各种类型
姓 = ['张', '林', '令狐', '王', '周', '洪', '东方', '黄']名 = ['三丰', '平之', '冲', '重阳']门派 = ['武当', '华山', '华山', '全真']名单 = zip(门派, 姓, 名)for n in 名单:print(n)
('武当', '张', '三丰')('华山', '林', '平之')('华山', '令狐', '冲')('全真', '王', '重阳')
姓 = ['张', '林', '令狐', '王', '周', '洪', '东方', '黄']名 = ['三丰', '平之', '冲', '重阳']门派 = ['武当', '华山', '华山', '全真']名单 = zip(门派, 姓, 名)for n in 名单:print(''.join(n))
武当张三丰华山林平之华山令狐冲全真王重阳
zip对象用法与列表类似,是否完全一致?
print(名单[2])
---------------------------------------------------------------------------TypeError Traceback (most recent call last)<ipython-input-20-c0f1ee5a101d> in <module>----> 1 print(名单[2])TypeError: 'zip' object is not subscriptable
print(len(名单))
---------------------------------------------------------------------------TypeError Traceback (most recent call last)<ipython-input-21-b7fba21236b8> in <module>----> 1 print(len(名单))TypeError: object of type 'zip' has no len()
zip 对象不能像列表那样使用 a[i] 的方式访问指定位置的元素
x = range(10)x
range(0, 10)
type(x)
range
range()返回的结果不是一个列表(list 对象),而是一个 range 对象
但 range 类型也是“可迭代类型”,因此也可用for循环访问
如果需要 list 对象,还需用 list() 函数将 range 对象转换成 list
为什么这样设计?
x = list(range(1000000000))print(x[257])# 会卡死# list会生成完整的列表放到内存里x_ = range(1000000000)print(x_[257])# 正常运行
在Python程序中创建一个列表对象,Python会首先划分出足够的内存并填入所有数据。
如果数据量太大,有可能造成内存不足导致错误; 而如果创建同样内容的 range 对象,则只消耗极少内存,无论数据量大小。
练习
练习1:zip基本操作
编写Python程序、或直接在Python交互式命令窗口中,逐次完成下列各项任务:
- 定义三个列表,分别为 x=[1,2,3],y=[‘a’,’b’,’c’],z=[‘甲’,’乙’,’丙’] 。
- 使用zip函数将三个列表合并,顺序为 (’甲’,1,’a’) ,结果赋值给变量 a 。
- 使用 for 循环逐个输出 a 中的内容,即每个元组。
- 让列表 x 和 y 等于自身乘以2,然后观察两个列表的变化。
- 再次执行第2步中的zip操作并将结果赋值给 a ,然后观察a是否变化,思考原因。
- 思考与试验:如果将第 1 步中的 x=[1,2,3] 改为 x=range(3) ,是否能够成功执行 zip 操作?
x=[1,2,3]y=['a','b','c']z=['甲','乙','丙']a = zip(z, x, y)for i in a:print(i)
('甲', 1, 'a')('乙', 2, 'b')('丙', 3, 'c')
x=[1,2,3]y=['a','b','c']x = x * 2y = y * 2
x
[1, 2, 3, 1, 2, 3]
y
['a', 'b', 'c', 'a', 'b', 'c']
a = zip(z, x, y)for i in a:print(i)
('甲', 1, 'a')('乙', 2, 'b')('丙', 3, 'c')
x=range(3)y=['a','b','c']z=['甲','乙','丙']a = zip(z, x, y)for i in a:print(i)
('甲', 0, 'a')('乙', 1, 'b')('丙', 2, 'c')
练习2
首先,我们已经从互联网上找到了一些姓名常用字,并保存到了文本文件中,即 常见姓氏,男生姓名常用字 和 女生姓名常用字。
编写一个程序,由用户通过input语句指定 “男生/女生” 和 名字个数,然后按要求自动生成姓名。
from random import sample, randint
lastname = []fname_boy = []fname_girl = []lastname_file = open('python02_13_01_xing.txt', 'r', encoding = 'utf8')fname_boy_file = open('python02_13_01_boy.txt', 'r', encoding = 'utf8')fname_girl_file = open('python02_13_01_girl.txt', 'r', encoding = 'utf8')
for i in lastname_file.readlines():for each in i:if each not in [" ", "\n"]:lastname.append(each)for j in fname_boy_file.readlines():for each in j:if each not in [" ", "\n", "、"]:fname_boy.append(each)for k in fname_girl_file.readlines():for each in k:if each not in [" ", "\n", "、"]:fname_girl.append(each)lastname_file.closefname_boy_file.closefname_girl_file.close
def auto_name(gender, num_name):auto_name_boy = []auto_name_girl = []if gender == '男':while len(auto_name_boy) < int(num_name):name_boy = ''.join(sample(lastname, 1) + sample(fname_boy, randint(1, 2)))if name_boy not in auto_name_boy:auto_name_boy.append(name_boy)return auto_name_boyelse:while len(auto_name_girl) < int(num_name):name_girl = ''.join(sample(lastname, 1) + sample(fname_girl, randint(1, 2)))if name_girl not in auto_name_girl:auto_name_girl.append(name_girl)return auto_name_girlgender = input('请输入性别:')num_name = input('请输入数量')print(auto_name(gender, num_name))
请输入性别:女请输入数量4['戈素欢', '蒋月岚', '燕婉', '芮仪']
思路:
对于 “由用户指定性别” 的要求,可以将用户的输入(’男’/‘女’)赋值给某个变量(比如 gender),
然后使用 if 语句对其判断,根据其内容将不同的文本文件名(boy.txt或girl.txt)赋值给某个变量比如 name_file 。
这样接下来使用 fopen(name_file) 即可正确打开所需的名字文件。
对于从文本文件中读入常用字到列表,可以使用下面的代码,通过字符串对象的split方法将读入的每一行(对应一个字符串)拆分为一个列表,并且要注意删除空格、空行、空串等无意义的字符:
xing = []all_txt = []with open('d:/python_02_13_01_xing.txt', encoding='utf-8') as f:all_txt = f.readlines()for s in all_txt:xing.extend( s.strip().split(' ') )print(xing)
【注意】如果是读入本例中的名字列表,则需要以顿号 “ 、” 为分隔符。
