随机生成姓名
- 需要把“姓”与“名”分为两组常用字,所以可以定义两个列表;
- 需要从两个列表中随机抽取一个字,于是可以使用 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 * 2
y = 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.close
fname_boy_file.close
fname_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_boy
else:
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_girl
gender = 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)
【注意】如果是读入本例中的名字列表,则需要以顿号 “ 、” 为分隔符。