一 核心特征及基本语法
1 动态、强类型语言
参考:弱类型、强类型、动态类型、静态类型语言的区别是什么? www.zhihu.com/question/19…
静态语言(强类型语言):使用变量前声明数据类型,一旦类型被确定就不能转化。强制数据类型定义。
动态语言(弱类型语言):使用变量前不需声明类型,变量类型由上下文定义。数据类型可被忽略。
2 四大基本语法
命名规则
-
蛇形命名法:英文、数字以及下划线,不能以数字开头,可用中文作为变量名(不建议)
-
驼峰命名法: Java典型的命名法
-
名称区分大小写
安晓=1 print(安晓) #输出1,此时安晓是一个变量 print("安晓") #安晓是一个字符串
下划线含义
-
单前导下划线 _var:仅供内部使用
-
末尾下划线 var_:避免与Python关键字命名冲突
-
前导下划线 __var:解释器重写属性名称,以避免子类中的命名冲突。
名称修饰(name mangling) - 解释器更改变量的名称(例如:class名为Test, 变量名为__a,那么__a会被Python解释器重写属性名为_Test__a),以便在类被扩展的时候不容易产生冲突。名称修饰会影响在一个类的上下文中,以两个下划线字符("dunders")开头的所有名称。
-
双前导和双末尾下划线 var:不会被Python解释器修改。
-
单下划线 _:表示某变量是临时或无关紧要
缩进原则
采用代码缩进和": "分隔代码块,同一个级别代码块的缩进量一样
m = ""
if m :
print('m不是空字符串')
else:
print('m是空字符串')
特殊关键字
-
不能使用和关键字相同的标识符、函数名、类名、属性名、方法名。
-
可以通过keyword模块来查看具体关键字:
import keyword #导入模块 print(keyword.kwlist) #输出kwlist列表
二 基本数据类型与运算符
变量
变量含义:用来存储一些之后可能会变化的值 变量赋值:通过“=”将变量名和值连接起来,同一变量可以反复赋值不同类型
short_id=1
print(short_id)
1
type(short_id)
Out[10]: int
short_id="1"
print(short_id)
1
type(short_id)
Out[13]: str
命名规范
- 一般变量名;
- 类名首字符为大写
- 类方法名
- 其他特殊变量,例如常量会全部大写;
多个变量赋值
- 允许同时为多个变量赋值。如:a = b = c = 1
- 可以多个变量赋值使用一个语句完成,如:number1,numbe2,numbe3=1,2,3
常量
常量表示“不能变”的变量,pi=3.1415
python数据类型
数值型
a1.整型:int;
>>>number=10
>>>type(number)
<type 'int'>
a2.浮点型:float;
>>>number=1.1
>>>type(number)
<type 'float'>
扩展说明:
1.int与float间可数据类型转换;函数int、float
2.所有的值默认都是以十进制形式进行表示;0b(二->十),0o(八->十),0x(十六->十)(对应函数是:bin、oct、hex)
3.在计算机中都是以固定的多少位进行处理数据,如果一个数其转换成二进制不足指定的位的话,则其对应的高位会采取补位补0操作;
a3.复数类型:
number = 1 + 2j #实部+虚部 (z=a+bi);虚部单位是i;
print(number) # (1+2j)
print(type(number)) # <class 'complex'>
print(number.real) # 获取实部1.0
print(number.imag) # 获取虚部2.0
bool类型
bool可进行 and (&)、 or(|) 和 not 运算; 逻辑判定型存在两个值:True、False; 常用false值有:""、0、[]、None、()、{}
>>>type(True)
<type 'bool'>
空值类型
空值用 None 表示,一般用来填充表格中缺失值,用 type() 函数来获取某值类型
>>>type(None)
<type 'NoneType'>
类型转换
int()、float()、str() 和 bool() 分别用于将变量转换成整型、浮点型、字符串和布尔型变量
number = "123"
print(int(number)) # 123
print(float(number)) # 123.0
print(str(number)) # 123
print(bool(number)) # True
思考:如果存在一个变量str1="hello",然后强制转换成int,即int(str1),其结果是?
isinstance用法
isinstance作用:判断object是否与第二个参数的类型相同,若参数二为一个元组,则若对象类型与元组中类型名之一相同即返回True。
number = "123"
print(isinstance(number, int)) # False,判断number是否是xx类型
print(isinstance(number, float)) # False
print(isinstance(number, str)) # True
ASCII码获取
作用:实现ASCII码与字符相互转换。
ASCII码转换,分别函数是:ord(字符)、chr(整型数字)
ord()函数接受一个字符类型参数,并返回一个十进制整数;
chr()函数接受一个整型参数,并返回一个与其ASCII码相对应的字符。
>>> ord('A')
65
>>> chr(65)
'A'
运算符
算术运算符
以下变量a为10,变量b为5:
| 运算符 | 描述 | 实例 |
|---|---|---|
| + | 加:两个对象相加 | a+b输出结果15 |
| - | 减:得到复数或者是一个数减去另一个数 | a-b输出结果5 |
| * | 乘:两个数相乘或者是返回一个被重复若干次的字符串 | a* b输出结果是50 |
| / | 除:x除以y | a/b输出结果2 |
| % | 取模:返回除法的余数 | b%a 输出结果0 |
| ** | 幂:返回x的y次幂 | a** b 为10的5次方,输出结果100000 |
| // | 取整除(地板除):返回商的整数部分 | 9//2输出结果4,9.0//2.0输出结果4.0 |
比较运算符
以下变量a为10,变量b为20:
| 运算符 | 描述 | 实例 |
|---|---|---|
| == | 等于:比较对象是否相等 | (a==b) 返回False |
| != | 不等于:比较两个对象是否不相等 | (a!=b) 返回True |
| 大于:返回x是否大于y | (a>b) 返回False | |
| < | 小于:返回x是否小于y | (a<b) 返回True |
| >= | 大于等于:返回x是否大于等于y | (a>=b) 返回False |
| <= | 小于等于:返回x是否小于等于y | (a<=b) 返回True |
赋值运算符
以下变量a为10,变量b为20:
| 运算符 | 描述 | 实例 |
|---|---|---|
| -= | 减法赋值运算符 | c-=a等价于c=c-a |
| * = | 乘法赋值运算符 | c*=a等价于c=c* a |
| /= | 除法赋值运算符 | c/=a等价于c=c/a |
| %= | 取模赋值运算符 | c%=a等价于c=c%a |
| ** = | 幂赋值运算符 | c**=a等价于c=c** a |
| //= | 取整除赋值运算符 | c//=a等价于c=c//a |
逻辑运算符
Python语言支持逻辑运算符,以下变量a为10,变量b为20:
| 运算符 | 逻辑表达式 | 描述 | 实例 |
|---|---|---|---|
| And | x and y | 布尔"与" - 如果 x 为 False,x and y 返回 False,否则它返回 y的计算值 | (a and b) 返回 20 |
| Or | x or y | 布尔“或” - 如果 x 是非 0,它返回 x 的值,否则它返回 y 的计算值 | (a or b) 返回 10 |
| Not | not x | 布尔“非” - 如果 x 为 True,返回 False 。如果 x 为 False,它返回 True | not(a and b)返回False |
位运算符
| 运算符 | 描述 | 实例 |
|---|---|---|
| & | 按位与运算符 | (a&b)输出结果是12 二进制解释:0000 1100 |
| | | 按位或运算符 | (a|b)输出结果四61 二进制解释:0011 1101 |
| ^ | 按位异或运算符 | (a^b)输出结果是49 二进制解释:0011 0001 |
| ~ | 按位取反运算符 | (~a)输出结果是-61 二进制解释:1100 0011 在一个有符号二进制数的补码形式 |
| << | 左移动运算符:<<“右边的数指定移动的位数,高位丢弃,低位补0 | a << 2 输出结果 240 ,二进制解释:1111 0000 |
| >> | 右移动运算符 | a >> 2 输出结果 15 ,二进制解释:0000 1111 |
扩展内容:原码、反码、补码
结论:保存正负数,不断改进方案后,选择了最好的"补码"方案
运算符优先级
口诀:指位比等赋身成逻
| 运算符 | 描述 |
|---|---|
| ** | 指数(最高优先级) |
| ~+- | 按位反转,一元加号、减号(最后两个方法名为+@和-@) |
| * / % // | 乘、除、取模、取整除 |
| + - | 加法、减法 |
| >> << | 右移、左移动运算符 |
| ^ | | 位运算符 |
| <= < >= > | 比较运算符 |
| <> != == | 等于运算符 |
| = += -= * = /= ** = | 赋值运算符 |
| is is not | 身份运算符 |
| in not in | 成员运算符 |
| not and or | 逻辑运算符 |
三 五类容器型数据类型(字符串、列表、元组、字典、集合)
数据容器分为5类:字符串(str)、列表(list)、元组(tuple)、字典(dict)、集合(set)是一种可以存储多份数据的数据类型,数据容器内的数据被称为元素,元素可以是任意数据类型(字符串、整数、布尔等)
1 字符串
定义
引号内的任何数据,必须使用单引号、双引号括起来
str1 = 'www.woodprogramming.com'
str2 = "wood编程"
print(str1)
print(str2)
如果内容本身包含引号: (1)巧用不同引号。假如字符串内容中包含单引号,则可用双引号将字符串括起来
str3 = 'I'm a coder'
str3 = "I'm a coder"
(2)转义字符。使用反斜线(\)将特殊字符转义,其也可实现换行操作。
str5 = '"we are scared,Let's hide in the shade",says the bird'
字符串常用符号
取值顺序
2种取值顺序:
从左到右索引默认从0开始,最大范围[str_length-1]
从右到左索引默认-1开始的,最大范围是[字符串开头]
+:字符串拼接
(1)两数值,表加法;(2)字符串和数值型,表拼接,则将数值型强制转换成字符串使用函数str
num_str1= 5 + 6
print(num_str1)
str1="H"
str2="ello"
print(str2 + str1)
s1="hello"
p = 99
print(s1 + str(p))
*:字符串复制
str1='hello'
print(str1*3)
[]: 字符串切片
-
结果为空值;如:str1[10:]---------->返回空值;
-
超过字符串最大索引,会抛出异常(索引越界)
-
语法:[初始索引:结束索引:间隔的值]
-
注意:
- 1.字符串索从0开始;获取字符串中某字符可通过索引;
- 2.截取的切片是左闭右开区间;
- 3.不声明初始索引表从0截取;不声明结束索引表截取字符串末尾
- 4.如果间隔值是负数,则表示先将字符串进行反转后间隔取值
str1="hello"
print(str1[1])
print(str1[2:])
print(str1[:2])
print(str1[:3:3])
print(str1[1:4:2])
print(str1[-4:-2])
print(str1[::-1])
思考题:str1="hello",实现切片操作,如果切片的初始索引超过字符串的最大索引值的话则结果是?
字符串的常用操作方法
数据清洗
a=" hello world "
print(a)
print(a.strip()) #去除首尾空格
print(a.lstrip()) #去除首空格
print(a.rstrip()) #去除尾空格
print(a.replace(' ','')) #删除空格,
replace(old,new,count),count参数表示的是可选参数,不声明则表示将所有的旧字符串全部替换;声明表示替换的次数
字符串的类型判断
#字符串类型判断
s="Hello 2021 World " ##False
print(s.isalnum()) #判断所有字符都是数字或者字母
print(s.isalpha()) #判断所有字符都是字母
print(s.isdigit()) #判断所有字符都是数字
print(s.islower()) #判断所有字符都是小写
print(s.isupper()) #判断所有字符都是大写
print(s.istitle()) #判断所有字符都是空白字符
字符串类型的转换
s="hEllo wOrld "
print(s.capitalize()) #首字母大写,其余全部小写
print(s.upper()) #全转换成大写
print(s.lower()) #全转换成小写
print(s.title()) #标题首字大写
判断字符串的开头的和结尾
#判断字符串的开头的和结尾
s="hello world "
print(s.startswith("hel")) #判断是否以目标字符开头
print(s.startswith("^ld")) #判断是否不以目标字符开头
print(s.endswith("ld ")) #判断是否以目标字符结尾
#判断文件的类型
name="file.txt"
if name.endswith(".doc"):
print(f"{name}是doc类型的文件")
elif name.endswith(".txt"):
print(f"{name}是txt类型的文件")
else:
print(f"{name}是其他类型的文件")
字符串位置的调整
a="hello world"
print(a.center(20,"*"))
print(a.ljust(20,"*"))
print(a.rjust(20,"*"))
字符串的搜索和统计
##find():如果找到子串, 则返回子串开始的索引位置。 否则返回-1
a="hello world abcab"
print(a.find("llo"))
print(a.find("le"))
##count():返回字串出现的次数
print(a.count("ab"))
print(a.count("le"))
##index():如果找到子串,则返回子串开始的索引位置。否则报错(抛出异常)
print(a.index("llo"))
##index()的使用
print(a.index("le"))
字符串的分离和拼接
(1)字符串的分离
split() 通过指定分隔符对字符串进行切片,如果参数 num 有指定值,则分隔 num+1 个子字符串
语法: s.split(str="", num=string.count(str))
str分隔符,默认为所有的空字符,包括空格、换行(\n)、制表符(\t)等,num分割次数。默认为 -1, 即分隔所有
a="hello world abcab"
print(a.split(" "))
print(a.split(" ",1))
print(a.split(" ",2))
(2)字符串的拼接
join() 方法用于将序列中的元素以指定的字符连接生成一个新的字符串
“连接符”.join(列表或元组或字符串或字典), 返回的是一个使用连接符进行拼接的字符串
如果对象是列表,元组,就是以一个下标元素为单位进行拼接
如果对象是字典,就是以一个键为单位进行拼接
如果对象是字符串,就是一个单词元素为单位进行拼接
##列表
a=['hello', 'world', 'abcab']
print("**".join(a))
##字典
b={'a1':123,'a2':456,'a3':789}
print("*".join(b))
##字符串
c="hello"
print("*".join(c))
随机生成数字和字母
随机生成数字-Random模块
import random
print(random.random())##随机输出[0,1]的浮点数
print(random.randint(0,9)) ##随机输出[0,9]之间的整数
print(random.uniform(2,5)) ##随机输出[2,5]之间的浮点数
print(random.choice("12345678")) ##随机输出字符串中的单个字符
print(random.choice([1,4,5,6])) ##输出列表中的随机项
print(random.choice((1,2,6))) ##输出元组中的随即项
print(random.sample('1233',3)) #多用于截取列表的指定长度的随机数,但是不会改变列表本身的排序
print(random.sample([1,2,5,7],3))
随机生成字符-String模块
import string
print(string.digits) #生成所有数字0-9
print(string.ascii_letters) #生成所有字母从a-z和A-Z
print(string.ascii_lowercase) #生成小写字母:a-z
print(string.ascii_uppercase) #生成大写字母:A-Z
随机生成数字和字母的组合
import random,string
print(random.sample(string.ascii_letters,4))
print("".join(random.sample(string.ascii_letters,4)))
print("".join(random.sample(string.digits,2))+"".join(random.sample(string.ascii_letters,2)))
生成十个验证码包含两个数字两个字母
#生成十个验证码包含两个数字两个字母
import random,string
for i in range(10):
print("".join((random.sample(string.digits,2))+(random.sample(string.ascii_letters,2))))
#print("".join(random.sample(string.ascii_letters, 2)) + "".join(random.sample(string.digits, 2)))
测试题
(1)小学生计算能力测试(10以内的运算)
设计用来实现帮助小学生进行算术运算练习。功能: 提供基本算术运算(加减乘)的题目,每道题中的操作数是随机产生的, 练习者根据显示的题目输入自己的答案,程序自动判断输入的答案是否正确 并显示出相应的信息。最后显示正确率。
import random,string
count=0
for i in range(10):
num1=random.randint(0,9)
num2=random.randint(0,9)
symbol=random.choice('+-*') ##随机生成运算符号
print(f"{num1}{symbol}{num2}=?") ##打印题目
right=eval(f"{num1} {symbol} {num2}") ##正确的结果
answer=int(input("请输入答案:"))
if answer==right: ##判断结果是否正确
print("正确")
count+=1
else:
print("错误")
print("共答对%d道题,正确率是%.2f%%" %(count,count/10*100))
(2)回文串判断
给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。说明:本题中,将空字符串定义为有效的回文串。
import string
a='A man, a plan, a canal: Panama'
for i in a:
if i not in string.ascii_letters:
a=a.replace(i,"")
else:
continue
print("true" if a[:].lower()==a[::-1].lower() else "false")
1
(3)编写一个函数来验证输入的字符串是否是有效的 IPv4
IPv4 地址由十进制数和点来表示,每个地址包含4个十进制数,其范围为 0 - 255,用(".")分割,比如,172.16.253.1;IPv4 地址内的数不会以 0 开头。比如,地址 172.16.254.01 是不合法的
ip = input("请输入IP地址:")
items = ip.split('.')
if len(items) != 4:
print("不合法的IP地址")
else:
for i in range(len(items)):
if int(items[i]) > 255 or items[i].startswith('0'):
print("不合法的IP地址")
exit()
else:
continue
print("合法的IP地址")
(4)机器人移动
a=input("输入动作[R]右 [L]左 [D]下 [U]上:")
r=l=d=u=0
for i in a:
if i=="R":
r+=1
elif i=="L":
l+=1
elif i=="D":
d+=1
elif i=="U":
u+=1
else:
print("请输入正确的字符!")
exit()
print(" true " if r==l and u==d else "false")
字符串格式符操作
通过字符串进行调用format方法,format中传入的参数即通过{索引}进行获取,其索引0对应的是format传入的第一个参数;如:
#字符串格式符操作
str1="hello"
str2="world"
print("{0}{1}".format(str1,str2))
%d、%i:表示的是十进制数占位
%f:表示的是浮点数的占位
number=1
print("%03d"%number)
number1=1.222222
print("%.2f"%number1)
print("%%d%d"%number)
2 列表list[v]
Python中常用的序列结构有列表、元组、字典、集合以及range等对象也支持很多类似的操作。列表、元组、字符串支持双向索引。
定义列表
语法:list1=[元素1,元素2,元素3.....]
示例:如果需要在列表中声明1-100个值的话则可以使用range函数完成;
通过list对象进行强制转换range对象即可
>>>list1=list(range(1,101))
访问列表中的值
>>>list1 = ['tom', 'jack', 2020, 2019]
>>>list2 = [1, 2, 3, 4, 5, 6, 7 ]
>>>print("list1[0]: ", list1[0])
>>>print("list2[1:5]: ", list2[1:5])
更新列表-append()
>>>list3 = [] ## 空列表
>>>list3.append('tom') ## 使用 append() 添加元素
>>>list3.append('jack')
print(list3)
删除列表元素-del()
>>>list4 = ['chinese', 'english', 2010, 2020]
>>>print(list4)
>>>del list4[2]
>>>print("After deleting value at index 2 : ")
>>>print(list4)
列表符号操作
list1=[1,2,3]
print(list1*3) # *: 表示列表元素重复
list1=[1,2]
list2=[2,3]
print(list1+list2) # +: 表示两个list的拼接;
列表截取
L = ['Google', 'Baidu', 'Taobao']
print(L[2])
print(L[-2])
print(L[1:])
列表函数及方法
函数:
list1=[4,6,1,2,3]
print(len(list1)) #列表元素个数
print(max(list1)) #返回列表元素最大值
print(min(list1)) #返回列表元素最小值
seq = (4, 5, 6)
print(list(seq)) #将元组转换为列表
方法:
| 序号 | 方法 |
|---|---|
| 在列表末尾添加新的对象 | list.append(obj) |
| 统计某个元素在列表中出现的次数 | list.count(obj |
| 在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表) | list.extend(seq) |
| 从列表中找出某个值第一个匹配项的索引位置 | list.index(obj) |
| 将对象插入列表 | list.insert(index, obj) |
| 移除列表中的一个元素(默认最后一个元素),并且返回该元素的值 | list.pop([index=-1]) |
| 移除列表中某个值的第一个匹配项 | list.remove(obj) |
| 反向列表中元素 | list.reverse() |
| 对原列表进行排序 | list.sort(cmp=None, key=None, reverse=False) |
list1 = [1, 2, 3, 2]
list3 = [1, 2, (2, 4, 3), 3, 2]
list2 = ["4", "5", "6"]
obj1 = [2]
obj2 = ["6"]
seq = (0, 1)
list1.append(obj1) # 在列表末尾添加新的对象
print("list1.append(obj1) result is", list1)
# 统计某个元素在列表中出现的次数
print("list1.count(obj1) result is", list1.count(2))
list1.extend(seq) # 在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)
print("list1.extend(seq) result is", list1)
list1.index(2) # 从列表中找出某个值第一个匹配项的索引位置
print("list1.index(obj) result is", list1.index(2))
list1.insert(1, obj1) # 将对象插入列表
print("list1.insert(index, obj) result is", list1)
list1.pop(1) # 移除列表中的一个元素(默认最后一个元素),并且返回该元素的值
print("list1.pop(1) result is", list1)
list2.remove("5") # 移除列表中某个值的第一个匹配项
print("list2.remove(obj) result is", list2)
list1.reverse() # 反向列表中元素
print("list1.reverse() result is", list1)
list1.sort(key=None, reverse=False) # 对原列表进行排序
print("list1.sort() result is", list1)
def takeSecond(elem):# 获取列表的第二个元素
return elem[1]
random = [(2, 2), (3, 4), (4, 1), (1, 3)]# 列表
random.sort(key=takeSecond)# 指定第二个元素排序
print('排序列表:', random)# 输出类别
思考
Q:[::-1]和reverse方法实现列表反转的两者区别?
R:[::-1]反转后返回一个新的列表,不会修改原有列表对象值(会开辟内存空间进行存在);reverse方法没有返回值,直接在原有对象上(原有列表内存空间)进行元素的反转操作;
list1=[1,2,4,3]
list1[::-1]
print("list1[::-1] result is",list1[::-1])
print("list1 is",list1)
list1.reverse()
print("list1.reverse() result is",list1)
print("list1 is",list1)
3 元组tuple(v)
定义元组
语法:tuple1=(元素1,元素2,元素3......)
tuple1=(1,2,3)
print(type(tuple1))
元组特点与操作
- 获取元组中的元素的方式与列表相同;
- 支持多个元组重复输出以及元组之间的拼接操作(+ * )
元组的作用
- a.对数据起到保护作用(数据不需要被重新赋值修改的操作都可以定义为元组)
- b.在函数中返回多个值,实际返回的就是一个元组
- c.针对多个变量操作,可以实现数据的封包和解包的操作;
- 解包:一组数据(元组)进行一一对应的赋值给每个变量
- 封包:如果一个变量进行赋予多个值的话,则表示的是该变量实际就是一个元组类型,该过程称之为封包操作;
元组的注意事项
- a.元组中的元素都是不可变的,不能够被重新赋值;
- b.如果在元组中需要只声明一个元素的话,则表示形式是(元素1,);如果省略逗号则表示的是与之元素所对应的类型;
- c.列表与元组之间可以实现相互转换;
思考
Q1:如何实现创建空元组以及元组中只有一个元素情况?
R1:空元组:tuple1=() 元组一个元素:tuple2=(30,)单个元素必须在元素后面添加逗号
tuple1=()
print(tuple1)
tuple2=(30,)
print(tuple2)
Q2:元组与列表的区别?
R2:元组中的数据一旦定义就不允许更改。
元组没有append()、extend()、insert()、remove()或pop()等方法,无法向元组中添加和删除元素。
从效果上看, tuple( )冻结列表,而list( )融化元组。
4 字典dict{k:v}
定义字典
语法:dict1={key:value,key:value}
键唯一,如果重复最后的一个键值对会替换前面的,值不需要唯一。
dict1={'a':'1','b':'2','b':'3','c':'4'}
print(type(dict1))
print(dict1)
访问字典里的值
dict2 = {'Name': 'Zemu', 'Age': 18, 'Class': 'First'}
print("dict2['Name']: ", dict2['Name'])
print("dict2['Age']: ", dict2['Age'])
修改字典
向字典添加新内容的方法是增加新的键/值对,修改或删除已有键/值对如下实例:
dict3 = {'Name': 'Zemu', 'Age': 18, 'Class': 'First'}
dict3['Age'] = 28 # 更新
dict3['School'] = "Zelin" # 添加
print("dict3['Age']: ", dict3['Age'])
print("dict3['School']: ", dict3['School'])
print("dict3: ", dict3)
删除字典
元素能删单一的元素也能清空字典,清空只需一项操作。显示删除一个字典用del命令,如下实例:
dict4 = {'Name': 'Zemu', 'Age': 18, 'Class': 'First'}
del dict4['Name'] # 删除键是'Name'的条目
print(dict4)
dict4.clear() # 清空字典所有条目
print(dict4)
字典内置函数和方法
函数:
dict1 = {'a': '1', 'b': '2', 'b': '3', 'c': '4'}
dict2 = {'a': '1', 'b': '2', 'b': '3', 'c': '5'}
dict3 = {'d': '1', 'e': '2', 'f': '3'}
seq = (8, 9, 0)
if dict1 == dict2:
print("dict1与dict2相等") # 比较两个字典元素
print("len(dict1):", len(dict1)) # 计算字典元素个数,即键的总数
print("str(dict1):", str(dict1)) # 输出字典可打印的字符串表示
print("type(dict1):", type(dict1)) # 返回输入的变量类型,如果变量是字典就返回字典类型
print("dict1.clear():", dict1.clear()) # 删除字典内所有元素
print("dict1:", dict1)
print("dict2.copy():", dict2.copy()) # 返回一个字典的浅复制
print("dict1.fromkeys(seq,10):", dict1.fromkeys(seq, 10)) # 创建一个新字典k:v,以序列 seq 中元素做字典的键k,10为字典所有键对应的初始值
print("dict3.get('d'):", dict3.get('d')) # 返回指定键的值,如果值不在字典中返回default值
print("dict3.items():", dict3.items()) # 以列表返回可遍历的(键, 值) 元组数组
print("dict3.keys():", dict3.keys()) # 以列表返回一个字典所有的键
print("dict3.values():", dict3.values()) # 以列表返回一个字典所有的值
print("dict1.update(dict2)", dict1.update(dict2)) # 把字典dict2的键/值对更新到dict里
print("dict1", dict1)
print("dict1.pop('a')", dict1.pop('a')) # 删除字典给定键 key 所对应的值,返回值为被删除的值。key值必须给出。否则,返回default值
print("dict1", dict1)
print("dict1.popitem(dict2)", dict1.popitem()) # 返回并删除字典中的最后一对键和值
思考
Q1:如果用字典里没有的键访问数据,则结果是?
R1:会提示当前字典中不存在该键,即KeyError错误
5 集合set{v}
集合是无序可变序列,使用一对大括号界定,元素不可重复,同一个集合中每个元素都是唯一的。集合中只能包含数字、字符串、元组等不可变类型(或者说可哈希)的数据。
集合创建与删除
直接将集合赋值给变量
a = {3, 5}
a.add(7) #向集合中添加元素
print(a)
a_set = set(range(8,14))#使用set将其他类型数据转换为集合
print(a_set)
b_set = set([0, 1, 2, 3, 0, 1, 2, 3, 7, 8]) #自动去除重复
print(b_set)
c_set = set() #空集合
print(c_set)
集合操作
# 并集操作:使用union、| ;表示取两个集合的不同数据
set1 = {1, 2, 3, 4, 5}
set2 = {2, 3, 4, 5, 6}
print(set1.union(set2)) # 等价操作表示方式:set1|set2
# 交集操作:使用intersection 、& ;表示取两个集合的相同数据
set1 = {1, 2, 3, 4, 5}
set2 = {2, 3, 4, 5, 6}
print(set1.intersection(set2)) # 等价操作表示方式:set1&set2
# 差集操作:使用difference 、-;表示两个集合相减;
set1 = {1, 2, 3, 4, 5}
set2 = {2, 3, 4, 5, 6}
print(set1.difference(set2)) # 等价操作表示方式:set1-set2
# 全集减交集(异操作):symmetric_difference、^ ;表示是全集-交集
set1 = {1, 2, 3, 4, 5}
set2 = {2, 3, 4, 5, 6}
print(set1.symmetric_difference(set2) ) # 等价操作表示方式:set1^set2
思考
Q1:因为集合和字典都是使用{}进行表示的,所以问空集合和空字典的表示形式?
R1:dict1={} 此种形式表示的是空字典,如果需要表示空集合的话,则必须使用set()
6 比较功能
Python 3.X 需引入 operator 模块
operator.gt(a, b) 和 operator.__gt__(a, b) 的区别
operator.gt(a, b)
operator.gt 是Python标准库 operator 模块中的一个函数,用于比较两个对象 a 和 b,如果 a > b 为真,则返回 True,否则返回 False。这个函数提供了一种函数式编程的方式来执行比较操作,使得比较操作可以像其他任何函数一样被传递和使用。
使用 operator.gt 的好处之一是它的通用性和灵活性。它不需要 a 和 b 必须是某种特定类型的对象,只要这些对象支持大于(>)比较操作符即可。此外,由于它是一个函数,因此可以很方便地作为参数传递给其他函数,如 filter(), map(), 或在需要函数作为参数的任何上下文中使用。
operator.__gt__(a, b)
operator.__gt__ 实际上并不是直接用于比较操作的函数或方法。在Python中,__gt__ 是一个特殊方法(也称为魔术方法或双下划线方法),它定义在类的内部,用于实现对象之间的大于(>)比较操作。当你尝试使用 > 操作符比较两个对象时,Python会自动调用这些对象的 __gt__ 方法(如果它们定义了的话)。
因此,operator.__gt__(a, b) 这种用法在大多数情况下是不正确的,因为它试图直接调用一个特殊方法,而不是通过操作符重载机制来间接调用。如果你尝试这样做,Python会抛出一个 TypeError,因为它期望 __gt__ 方法是某个类的一部分,而不是一个可以直接调用的函数。
总结
operator.gt(a, b)是一个函数,用于比较两个对象a和b是否满足a > b,并返回布尔值。它适用于任何支持大于比较的对象。operator.__gt__不是一个可以直接调用的函数或方法。__gt__是一个特殊方法,定义在类中,用于实现大于比较操作。你不能直接调用它,而是应该通过>操作符来间接调用。
import operator
a="saw"
b="saw"
c="fxh"
print("1:",operator.lt(a, b))
print("2:",operator.le(a, b))
print("3:",operator.eq(a, b))
print("4:",operator.ne(a, b))
print("5:",operator.ge(a, b))
print("6:",operator.gt(a, b))
print("7:",operator.__lt__(a, b))
print("8:",operator.__le__(a, b))
print("9:",operator.__eq__(a, b))
print("10:",operator.__ne__(a, b))
print("11:",operator.__ge__(a, b))
print("12:",operator.__gt__(a, b))
7 区别与联系
概括
| 数据类型 | 列表(list) | 元祖(tuple) | 集合(set) | 字典(dictionary) |
|---|---|---|---|---|
| 表示 | [] | () | () | {} |
| 举例 | a_list = [1, True, ‘aa’] | a_tuple = (1, True, ‘aa’);t2 = (1,) | a_set = {1, True, ‘aa’};s = set( [1, True, ‘aa’]) | a_dict = {‘name’: ‘xuan’, ‘age’:21} |
| 是否有序 | 有序 | 有序 | 无序 | 无序 |
| 是否读写 | 读写 | 只读 | 读写 | 读写 |
| 空定义 | a_list= [] | a_tuple= () | a_set= set();not_sure = {}空字典 | a_dict= {} |
| 元素可修改 | a_list[0] = 23 | 否 | 否 | a_dict[‘age’] =30 |
| 下标访问 | a_list[0]= 23 | a_tuple[0] | 否 | a_dict[‘age’]= 30 |
| 添加元素 | +、append、extend、insert | 不可添加 | add、update | a_dict[‘new_key’]= ‘value’ |
| 删除元素 | del、remove、pop()、pop(1)、clear | 不可删除 | discard、remove、pop、clear | pop、popitem、clear |
| 元素查找 | index、count、in | in | in | a_dict[‘key’] |
| 布尔真值 | 非空 | 非空 | 非空 | 非空 |
| 定义 | 列表(list)是有序的集合,可以存放不同数据类型的数据,并且list中的每个元素的都对应着一个索引来标记其位置,且索引从0开始。 | tuple与list类似,不同之处在于tuple中的元素不能进行修改。而且tuple使用小括号,list使用方括号。 | dic字典是另一种可变的容器模型,且可存储任意类型对象。字典的每个键值(key:value)对用冒号(:)分割,每个对之间用逗号(,)分割,整个字典包括在花括号{}中 | set()函数是创建一个无序不重复元素集,可添加,删除数据,还可以计算交集、差集、并集等。python 的集合类型和 其他语言类似, 是一个无序不重复元素集, 基本功能包括关系测试和消除重复元素.集合对象还支持union(联合), intersection(交), difference(差)和sysmmetricdifference(对称差集)等数学运算。 |
| 分析 | 列表list,用中括号“[ ]”表示1.任意对象的有序集合列表是一组任意类型的值,按照一定顺序组合而成的2.通过偏移读取组成列表的值叫做元素(Elements)。每一个元素被标识一个索引,第一个索引是0,序列的功能都能实现3.可变长度,异构以及任意嵌套列表中的元素可以是任意类型,甚至是列表类型,也就是说列表可以嵌套4.可变的序列支持索引、切片、合并、删除等等操作,它们都是在原处进行修改列表5.对象引用数组列表可以当成普通的数组,每当用到引用时,Python总是会将这个引用指向一个对象,所以程序只需处理对象的操作。当把一个对象赋给一个数据结构元素或变量名时,Python总是会存储对象的引用,而不是对象的一个拷贝 | 1.任意对象的有序集合与列表相同2.通过偏移存取与列表相同3.属于不可变序列类型类似于字符串,但元组是不可变的,不支持在列表中任何原处修改操作,不支持任何方法调用4.固定长度、异构、任意嵌套固定长度即元组不可变,在不被拷贝的情况下长度固定,其他同列表5.对象引用的数组与列表相似,元祖是对象引用的数组>tuple和list相比1.比列表操作速度快2.对数据“写保护“3.可用于字符串格式化中4.可作为字典的key | 1.通过键而不是偏移量来读取字典就是一个关联数组,是一个通过关键字索引的对象的集合,使用键-值(key-value)进行存储,查找速度快2.任意对象的无序集合字典中的项没有特定顺序,以“键”为象征3.可变长、异构、任意嵌套同列表,嵌套可以包含列表和其他的字典等4.属于可变映射类型因为是无序,故不能进行序列操作,但可以在远处修改,通过键映射到值。字典是唯一内置的映射类型(键映射到值的对象)5.对象引用表字典存储的是对象引用,不是拷贝,和列表一样。字典的key是不能变的,list不能作为key,字符串、元祖、整数等都可以dic和list比较,dict有以下几个特点:1.查找和插入的速度极快,不会随着key的增加而增加2.需要占用大量的内存,内存浪费多而list相反:1.查找和插入的时间随着元素的增加而增加2.占用空间小,浪费内存很少所以,dict是用空间来换取时间的一种方法 | 1.是一组key的集合,但不存储value,并且key不能重复创建一个set,需要提供一个list作为输入集合,s = set([1,2,3]),注意,传入的参数 [1, 2, 3] 是一个list,而显示的 set([1, 2, 3]) 只是告诉你这个set内部有1,2,3这3个元素,显示的[ ]不表示这是一个list2.重复元素在set中自动被过滤set可以看成数学意义上的无序和无重复元素的集合,因此,两个set可以做数学意义上的交集、并集等操作还有一种集合是forzenset( ),是冻结的集合,它是不可变的,存在哈希值,好处是它可以作为字典的key,也可以作为其它集合的元素。缺点是一旦创建便不能更改,没有add,remove方法3. set和dict对比1.set和dict的唯一区别仅在于没有存储对应的value2.set的原理和dict一样,同样不可以放入可变对象,因为无法判断两个可变对象是否相等,也就无法保证set内部“不会有重复元素” |
相互PK
| 比较 | 详情 |
|---|---|
| 字典dict和列表list的比较 | dict的查找和插入的速度极快,不会随着key的增加而变慢。但是需要占用大量的内存,内存浪费多。相反,list查找和插入的时间随着元素的增加而增加。但是占用空间小,浪费内存很少。 |
| 字典dict和集合set比较 | 唯一区别仅在于没有存储对应的value,但是,set的原理和dict一样,所以,同样不可以放入可变对象,因为无法判断两个可变对象是否相等,也就无法保证set内部“不会有重复元素”。 |
| 元祖tuple与列表list比较 | tuple与list类似,不同之处在于tuple中的元素不能进行修改。而且tuple使用小括号,list使用方括号。 |
Python常用内置函数
编号 函数 注释
1 cmp(A, B) 比较可为list、tuple等的A、B,A>B为1,A=B为0,小于为-1
2 len(obj) 计算元素个数。
3 max(obj) 返回元素最大值。
4 min(obj) 返回元素最小值。
5 reversed(obj) 对元素进行翻转
6 enumerate(obj) 遍历list的元素,返回序号及其对应的元素 for x,y in list:
7 zip() 打包成tuple(元组),然后返回由这些tuples组成的list(列表)
五 可变对象与不可变对象
基本概念
可变对象:对象存放在地址中的值会被改变,如:list dict set
不可变对象:对象存放在地址中的值不会原地改变,如:tuple string int float bool
总结: 可变对象与不可变对象的区别在于对象本身是否可变
# 可变对象
>>> number = [1, 2, 3]
>>> number[1] = 4
>>> number
[1, 4, 3]
# 不可变对象
>>> number1 = (1, 2, 3)
>>> number1[1] = 4
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
地址问题
可变对象的内存地址变化
>>> number = [1, 2, 3]
>>> id(number)
2139167175368
>>> number[1] = 4
>>> id(number)
2139167175368
结果:可变对象变化后,地址是没有改变的
如果两个变量同时指向一个地址
1.可变对象
>>> number1 = [1, 2, 3]
>>> id(number1)
2139167246856
>>> number2 = number1
>>> id(number2)
2139167246856
>>> number1[1] = 4
>>> number1
[1, 4, 3]
>>> number2
[1, 4, 3]
>>> id(number1)
2139167246856
>>> id(number2)
2139167246856
结果:改变number1则number2也跟着变,因为他们始终指向同一个地址
2.不可变对象
>>> number1 = (1, 2, 3)
>>> id(number1)
2139167074776
>>> number2 = number1
>>> number1 = (4, 5, 6)
>>> number1
(4, 5, 6)
>>> number2
(1, 2, 3)
>>> id(number1)
21391670759281
>>> id(number2)
2139167074776
结果:number1的值和地址发生了变化,而number2值和地址都没变化
作为函数参数
1.可变对象
>>> def func_test(obj):
... obj.append(1)
... print(obj)
...
>>> obj = [1, 2, 3]
>>> func_test(obj)
[1, 2, 3, 1]
>>> obj
[1, 2, 3, 1]
我们可以看到,可变对象作为参数传入时,在函数中对其本身进行修改,是会影响到全局中的这个变量值的,因为函数直接对该地址的值进行了修改。
2.不可变对象
>>> def func_test(number):
... number += 1
... print(number)
...
>>> number = 2
>>> func_test(number)
3
>>> number
2
对于不可变对象来说,虽然函数中的number值变了,但是全局中的number值没变,因为函数中的number值已经对应了另外一个地址,而全局中的number值指向的原来地址的值是没有变的。
3.总结
python中向函数传递参数只能是引用传递,表示把它的地址都传进去了
有的编程语言允许值传递,即只是把值传进去,在里面另外找一个地址来放,这样就不会影响全局中的变量。
可变参数在类中使用
我们直接来看下面这个例子
class Myclass:
def __init__(self, a):
self.a = a
def print_a(self):
print(self.a)
运行如下
>>> aa = [1,2]
>>> my = Myclass(aa)
>>> my.print_a()
[1, 2]
>>> aa.append(3)
>>> my.print_a()
[1, 2, 3]
我们可以看到,类中的变量和全局变量地址依然是共用的,无论在哪里修改都会影响对方。
其实这个特性也不能说是一个弊端,利用这一点可以进行一些很方便的操作,比如两个线程同时操作一个队列,我们不用设置一个global队列,只要将队列这个可变对象传入类之中,修改就会自动同步。
函数默认参数
函数默认参数一定要设定为不可变参数,否则会引发一些错误,我们来看下面一个例子
>>> def func_test(l=[]):
... l.append('add')
... print(l)
...
>>> func_test([1, 2, 3])
[1, 2, 3, 'add']
>>> func_test(['a', 'b'])
['a', 'b', 'add']
上面代码是正常运行的,我们来看下面这些
>>> func_test()
['add']
>>> func_test()
['add', 'add']
>>> func_test()
['add', 'add', 'add']
按理说应该每次都是['add'],但是现在出现了意想不到的错误。
这是因为l = []是在函数定义时就确定下来的了,所以之后每次调用这个函数,使用的l都是同一个,如果不指定这个参数的新值,就会出现上面这个问题。
上面这个l可以默认设置为None,这就是一个不可变对象。
两种类在实现上的差异
对于list tuple这些类来说,它们的元素都相当于类的属性,修改元素相当于修改类的属性。
正常定义一个类它的属性是可以正常访问和修改的,所以那些类的实例都是可变对象。
我们只要定义一个类,不允许它修改属性,就可以创建一个不可变对象。
这就要使用python的魔法方法,主要有两种方法
- 设置
__setattr__ 直接抛出异常,即只要想设置属性值,就会抛出异常 - 设置
__slot__ 限制属性的访问,如果属性都不能访问了,那就肯定不能修改
六 分支流程控制
if语句---单分支结构
基本语法
if 表达式:
语句块
【例】单分支结构示例(if_single.py):
输入两个数a和b,比较两者大小,如果a小于b则实现两数互换,否则不做任何操作。
#!/usr/bin/python
# -*- coding: UTF-8 -*-
a = int(input("请输入第1个整数:"))
b = int(input("请输入第2个整数:"))
print(str.format("输入值:{0}, {1}", a, b))
if (a < b): #a和b交换
t = a
a = b
b = t
print(str.format("降序值:{0}, {1}", a, b))
str.format():格式化字符串的函数。
语法:是通过{} 和 :来代替以前的 %
if...else语句---双分支结构
【例】双分支结构示例(if_double.py):
输入两个数a和b,比较两者大小,如果a小于b则求和操作,否则求差操作。
#!/usr/bin/python
# -*- coding: UTF-8 -*-
a = int(input("请输入第1个整数:"))
b = int(input("请输入第2个整数:"))
print(str.format("输入值:{0}, {1}", a, b))
if (a < b):
print("a,b两数的和是:%d"%(a+b))
else:
print("a,b两数的差是:%d"%(a-b))
if...elif...else---多分支结构
基本语法
if 表达式 1:
语句块 1
elif 表达式 2:
语句块 2
elif 表达式 3:
语句块 3
…
else:
语句块 n
【例】多分支结构示例(if_more.py):
将百分制分数mark转换为五级制(优、良、中、及格、不及格)的评定等级grade
方法一:
mark = int(input("请输入分数:"))
if (mark >= 90): grade = "优"
elif (mark >= 80): grade = "良"
elif (mark >= 70): grade = "中"
elif (mark >= 60): grade = "及格"
else: grade = "不及格"
方法二:
if (mark >= 90): grade = "优"
elif (mark >= 80 and mark < 90): grade = "良"
elif (mark >= 70 and mark < 80): grade = "中"
elif (mark >= 60 and mark < 70): grade = "及格"
else: grade = "不及格"
方法三:
if (mark >= 60): grade = "及格"
elif (mark >= 70): grade = "中"
elif (mark >= 80): grade = "良"
elif (mark >= 90): grade = "优"
else: grade = "不及格"
if语句嵌套
基本语法
if 条件1:
条件1满足执行的代码
......
if 条件1基础上的条件2:
条件2满足时,执行的代码
......
#条件2不满足的处理
else:
条件2不满足时,执行的代码
#条件1不满足的处理
else:
条件1不满足时,执行的代码
......
【例】if嵌套示例(if_insert.py):
number1 = int(input("请输入第1个整数:"))
number2 = int(input("请输入第2个整数:"))
if number1<number2:
if number1==9:
print("number1等于9")
elif number2<30:
print("number2小于30")
elif number1<20:
print("number1小于20")
#下面的输出语句只要进入第一个if,则无论上述判定是否执行,都会执行下面这个输出语句
print("number1小于number2")
else:
print("number1大于number2")
三目运算符
用法详解
使用 if else 实现三目运算符(条件运算符)的格式如下:
exp1 if contion else exp2
condition 是判断条件,exp1 和 exp2 是两个表达式。如果 condition 成立(结果为真),就执行 exp1,并把 exp1 的结果作为整个表达式的结果;如果 condition 不成立(结果为假),就执行 exp2,并把 exp2 的结果作为整个表达式的结果。
语句max = a if a>b else b的含义:
- 如果 a>b 成立,就把 a 作为整个表达式的值,并赋给变量 max;
- 如果 a> b 不成立,就把 b 作为整个表达式的值,并赋给变量 max。
嵌套
在嵌套时需要注意 if 和 else 的配对,如:
a if a>b else c if c>d else d
应该理解为:
a if a>b else ( c if c>d else d )
【例】使用 Python 三目运算符判断两个数字的关系:
a = int( input("Input a: ") )
b = int( input("Input b: ") )
print("a大于b") if a>b else ( print("a小于b") if a<b else print("a等于b") )
该程序是一个嵌套的三目运算符。程序先对 a>b 求值,如果该表达式为 True,程序就返回执行第一个表达式 print("a大于b"),否则将继续执行 else 后面的内容,也就是:
( print("a小于b") if a<b else print("a等于b") )
进入该表达式后,先判断 a<b 是否成立,如果 a<b 的结果为 True,将执行 print("a小于b"),否则执行 print("a等于b")。
七 循环
while循环
while bool表达式:
循环体
else:
语句块
【例】 1-100的求和
i=1
sum=0
while i<=100:
sum+=i
i+=1
print("1-100的和为:%d"%sum)
for循环
for 变量名 in 可迭代对象:
循环体
else:
语句块
【例】1-100的求和
sum=0
for i in range(1,101):
sum+=i
print(sum)
【思考】完成1-100之间的奇数和以及偶数和的计算
sum_odd = 0;
sum_even = 0
for i in range(1, 101):
if i % 2 != 0: #奇数
sum_odd += i #奇数和
else: #偶数
sum_even += i #偶数和
print("1~100中所有奇数的和:", sum_odd)
print("1~100中所有偶数的和:", sum_even)
循环嵌套
在一个循环体内又包含另一个完整的循环结构,称为循环的嵌套【例】利用嵌套循环打印九九乘法表(nest_for.py)
for i in range(1, 10): #外循环
s = ""
for j in range(1, 10): #内循环
s += str.format("{0:1}*{1:1}={2:<2} ", i, j, i * j)
print(s)
【思考】所示的2个九九乘法表:
break语句
- 用于退出for、while循环,即提前结束循环
- 当多个for、while嵌套时,break语句只能跳出最近的一层循环
【例】使用break语句终止循环(break.py)
while True:
s = input('请输入字符串(按Q或者q结束):')
if s.upper() == 'Q':
break
print('字符串的长度为:', len(s)
思考
Q:编程(prime1.py和prime2.py)判断所输入的任意一个正整数是否为素数
方法一(利用for循环和break语句):
import math
m = int(input("请输入一个整数(>1):"))
k = int(math.sqrt(m))
for i in range(2, k + 2):
if m % i == 0:
break #可以整除,肯定不是素数,结束循环
if i == k+1 : print(m, "是素数!")
else: print(m, "是合数!")
方法二(利用while循环和bool变量):
import math
m = int(input("请输入一个整数(>1):"))
k = int(math.sqrt(m))
flag = True #假设输入的整数为素数
i = 2
while (i <= k and flag == True):
if (m % i == 0): flag = False #可以整除,肯定不是素数,结束循环
else: i += 1
if (flag == True): print(m, "是素数!")
else: print(m, "是合数!")
continue语句
- 结束本次循环,即跳过循环体内自continue下面尚未执行的语句,返回到循环的起始处,并根据循环条件判断是否执行下一次循环
【例】 使用continue语句跳过循环。要求输入若干学生成绩(按Q或q结束),如果成绩<0,则重新输入。统计学生人数和平均成绩
num = 0
scores = 0 #初始化学生人数和成绩和
while True:
s = input('请输入学生成绩(按Q或q结束):')
if s.upper() == 'Q':
break
if float(s) < 0: #成绩必须>=0
continue
num += 1 #统计学生人数
scores += float(s) #计算成绩之和
print("学生人数:%d,平均分:%d"%(num,scores/num))
continue语句与break语句的区别
continue语句仅结束本次循环,并返回到循环的起始处,循环条件满足的话就开始执行下一次循环;而break语句则是结束循环,跳转到循环的后继语句执行
死循环
- 如果while循环结构中循环控制条件一直为真,则循环将无限继续,程序将一直运行下去
【例】死循环示例(infinite.py)
while True: #循环条件一直为真
num = float(input("请输入一个正数:"))
print("该数是:%f"%num)
print("Good bye!")
else子句
- 【例】使用for语句的else子句(for_else.py)
hobbies = ""
for i in range(1, 3 + 1):
s = input('请输入爱好之一(最多三个,按Q或q结束):')
if s.upper() == 'Q':
break
hobbies += s + ' '
else:
print('您输入了三个爱好。')
print('您的爱好为:', hobbies)