四、Python语言基础
一)基础概念
1、什么叫程序
程序即一段可以又计算机执行的代码。
2、程序的组成
程序=语法+算法+数据结构
语法是固定的,算法是解决问题的方法,算法是变化的。
eg:如何从一堆数字里面找出最大的那个数?[1,3,17,4,34,56]
arr = [1,3,17,4,34,56]
print(max(arr)) #max() 方法返回给定参数的最大值,参数可以为序列。
py02:
1. 首先假定一个数是最大值
2. 将当前最大数保存到一个值当中
3. 从第二个数开始,挨个去将后面的每个数与当前最大值进行比较。如果后面的某个数大于当前保存的最大值,则将当前保存的最大值替换为对应的这个数。
arr = [1,3,17,4,34,56]
max = arr[0]
for num in arr:
if num > max:
max = num
print(max)
3、怎么样才能学好编程
- 明白程序的构成
- 积累编码经验
- 善用工具提高效率
二)Python环境搭建
python是解释型语言。
- 安装并配置Python
- 安装并使用Pycharm环境
1)python开发环境主要包括两个部分:
Python解释器:python主要负责在电脑上运行python程序
不要下载最新的,可能不稳定。
安装路径不要有中文及特殊字符。
添加环境变量
在path中添加
1、python的安装路径,eg:D:\Soft\python\
2、 python安装路径下的Scripts的路径,eg:D:\Soft\python\Scripts\
Pycharm代码编辑器:主要是为了方便快速写python代码
三)Python语言基础
学习一门编程语言究竟要学些什么?
- 输入输出
- 数据类型
- 控制结构
- 函数定义
- 对象定义
- 文件读写
- 异常处理
运行python程序的三种方式:
- 交互式解释器中直接运行python(python的交互式解释器)
- 命令行的方式运行python代码(在对应目录下进入cmd 下发 python py文件)
- 用编辑器运行python代码(pycharm、VScode等)
1)输入输出
input()接受用户的输入,python3.x后,默认返回值都是字符串
x = int(input('Enter your want number:'))
y = input('Enter your want number:')
print()打印输出,可以用“,”分隔参数,默认带回车(换行显示)
print('hello')
print('hello','word','!')
print('hello world!',end='') #在后台不换行打印
格式化输出:
%、format、f
%%表示对结果中的%号进行转义
2)变量定义及规则
任何值都要保存变量。
python里面直接定义一个变量即可
在程序运行过程中,它的值是允许改变的量,叫变量。
变量用于在程序中存储特定的数据或信息。
变量名相当于一个指针,指向存储变量的内存地址。
python使用变量注意点:
- python中的变量不需要类型的声明,变量的类型由赋值给它的数据的类型决定
- 每个变量在使用前必须先被赋值,变量被赋值后该变量才会被创建
- 等号(=)用来给变量赋值。等号(=)运算符左边是一个变量名,等号(=)运算符右边是存储在变量中的 值。
python赋值的过程:
即根据地址获取到其值。
Python中变量的命名规则:
- 第一个字符必须是字母或者下划线“_”,其他部分由字母、数字下划线组成。py文件不要使用“_”和以数字开头命名。
- 变量名称对大小写敏感,故命名是使用大写首字母可以有效的避开关键字的错误使用
- 变量名不要使用python的保留关键字
- 在实际项目中,尽量使用能够表征变量含义的变量名。
python的标准库提供了一个keyword module,可输出当前版本的所有关键字
3)python占位符使用
占位符即先占住一个固定的位置,等着你再王里面添加内容的符号。格式占位符(%)是再python语言中格式输入函数,如print()等函数中使用。其意义即是起到格式占位,表示再该位置有输入或者输出:
%d |
整数,print('我今年已经%d岁了'%(18)) |
%f |
浮点数,print('%.2f'%(22.3)),默认显示小数点后六位,若是位数不足,后面自动补0 |
%s |
字符串,print('hello,%s和%s'%('小明','小红')) |
%% |
表示%符号本身,print("大概有%d%%"%(40)) |
Python3.x版本中新家了format方法,支持不指定数据类型的占位。
在3.6以上的版本中话增加了f占位符,支持直接使用变量进行占位。
eg:
a = 'kytty'
print('hello,{}'.format(a))
'{:.2f}'.format(3.1415926) #保留2位小数
'{0},{1}'.format('hello','word') #通过index方式制定所用参数
print(f'hello{a}')
4)注释
单行注释采用#号开头;注释可以在语句或表达式行末;
多行注释使用三个单引号(''')或三个双引号(""")
5)语句块
不像java,C/C++以花括号{}来区分语句块,python是以缩进来表示语句块,同以缩进级别为同一级别的语句块。
缩进最好使用四个空格。而且要注意缩进要一致,使用空格就全部使用空格,使用tab就都使用tab。
def demo():
print(1+1)
n = input("你想说什么:")
if type(n) == str:
print('123')
if type(n) == int:
print('246')
print(n)
6)运算符
算数运算符:+ - * / // % |
比较运算符:> < >= == != |
逻辑运算符:or and not |
赋值运算符:= += %= -= *= |
成员运算符:in not in |
7)数据类型
01.可变和不可变数据类型
为什么要区分数据类型?
不同的数据类型可以出来不同的问题和常见,所以不同数据类型有不同的方法。
Python3的标准数据类型:
- Number数字(不可变)
- String字符串(不可变)
- Tuple元组(不可变)
- List列表
- Set集合
- Dictionary字典
什么叫可变数据类型和不可变类型?
不可变数据类型:指凡是改变了数据的值之后,这个值就将编程另外一个对象的数据类型,叫不可变数据类型。
Eg:
a = 1
print(id(a))
#id 变量内存地址,每个变量的id是唯一的,如果两个变量的id不同,则是两个不同的变量
a += 1
print(id(a))
以上,改变了值,变量内存地址改变了。原来指向则销毁了,即指向值为1的内存地址的指向销毁。
可变数据类型:改变数据的值并不会产生一个新的对象,变量仍然指向原来的对象。
Eg:
a = [1,2,3]
print(a)
print(id(a))
a.append(4)
print(a)
print(id(a))
02.数值类型——不可变
数值类型:int、float、complex三种
整型:通常被称为整型或整数,是正或负整数,不带小数点。
浮点:由整数部分与小数部分组成。
复数:复数由实数部分和虚数部分构成,可以用a+bj,或者complex(a,b)表示,复数的实部a和虚部b都是浮点型。(eg:-4的平方根)
强制类型转换
Eg:
int(10)
int(13.4)
float(32)
float(4.1245823)
/:一般的除法
//:整除,凡是小数,全部抹去
%:取余数
math模块中常用的方法:
(需导入模块,import math)
- cell:取大于等于x的最小的整数值,如果x是一个整数,则返回x
- fabs:返回x的绝对值,返回浮点型
- floor:取小于等于x的最大的整数值,如果x是一个整数,则返回x
- pow:返回x的y次方,即x**y eg:math.pow(2,3)
- sqrt:求x的平方根
Random模块产生随机数
- import random
- random.random():返回[0.0,1.0)之间的浮点数,注意,这是一个左闭右开的区间,随机数可能是0但不可能是1
- random.randint(a,b):生成一个a与b之间的随机整数,即[a,b]
- random.randrange(a,b):生成的随机整数不会包含b,即[a,b)
- random.uniform(a,b):生成[a,b]之间的随机浮点数
- random.choice([]):从列表中随机抽出一个元素 eg: random.choice([1,2,3,4])
- random.shuffle([]):打乱列表中元素的顺序
eg:
a = [1,2,3,4]
random.shuffle(a)
print(a)
random.sample([],n):从序列中随机取出n个元素。
eg:
a = [1,2,3,4]
random.shuffle(a)
print(random.sample(a,3))
3、 字符串类型——不可变
- 在python中,凡是由单引号’’、双引号””和三引号’” ‘”括起来的值或变量都数属于字符串类型
- 字符串中的单引号、双引号或三引号不可混用
- 三引号一般用于代码注释或保持样式的长字符串输出。(可以保持样式输出,比如有换行的情况)
引号类型多,是避免中间还需要使用引号的情况,作用完全一样,可嵌套使用。
字符串切片
切片操作(slice)可以冲一个字符串中获取子字符串。
格式:[start:end:step] 初始偏移量start,终止偏移量end以及可选步长step
- [:]:提取冲头开始,默认位置为0到结尾默认位置为-1的整个字符串。
- [start:]:从start提取到结尾
- [:end]:从开头提取到end-1
- [start:end]:从start 提取到end-1
- [start:end:step]:从start提取到end-1,每step个字符提取一个
- Setp为正表示正序切片,为负表示逆序切片,默认为正1.
正序切片时,要求start必须从字符串开头处进行技术,逆序切片时start必须从字符串为不计数。
无论正序还是逆序,start均要求在end之前,否则无法得到内容。
Eg1:
字符串中每个字符都有正负两个下标,两个下标对于这个字符来说都是等效的,不管使用哪个下标都是取得对应的字符。
原始字符串
在python中如果遇到字符串中需要大量使用转义字符时,可以使用python提供的原始字符串功能,即在要转义的字符串前面加r,即可实现自动转义。这个功能在windows路径的转义时特别适用。
字符串的常用函数
1. len(string):返回字符串长度
2. count(str,beg=0,end=len(string)):返回str在string里面出现的次数,如果beg或者end指定则返回指定范围内str出现的次数
3. capitalize():将字符串的第一个字符转换成大写
4. find(str,beg=0,end=len(string)):检测str是否包含在字符串中,如果beg和end指定范围,则检查是否包含在指定范围内,如果是返回开始的索引值,否则返回-1。
5. repleace(old,new):把字符串中的str1替换成str2,如果替换的内容不存在则跳过。
6. split(str=’’):以str为分隔符拆分字符串,返回的是字符串拆分后的列表
7. index(str,beg=0,end=len(string)):与find()方法一样,只不过如果str不再字符串中会报一个异常。
8. ‘,’.join([‘a’,’b’,’c’]):以指定符号连接后面列表中的字符串元素,以字符串形式返回。
9. isdigit():如果字符串只包含数字则返回true否则返回false
10. isalpha():判断字符串中是否只包含字母
11. isspace():如果字符串中只包含空格,则返回true,否则返回false
12. istitle():如果字符串是标题化的(见title())则返回true,否则返回false
13. lower():转换字符串中所有大写字符为小写
14. upper():把所有字符中的小写字母转换成大写字母
15. title():把每个单词的第一个字母转化为大写,其余小写
16. startswith(str,beg=0,end=len(string)):检查字符串是否是以指定的str开头,是则返回true,否则返回false。如果beg和end的指定值,则在指定范围内检查。
17. strip(str):删除字符串两边的str代表的字符,如果不指定str则删除空白格。
18. rstrip(str)和lstrip(str):删除字符串右边或左边str代表的字符,如果不指定str则删除空白字符。
04列表类型
列表是python中的重要数据类型,可以作为一个方括号内的都好分隔值出现。列表的数据项不需要具有相同的类型。创建一个列表,只要把逗号分割的不同数据项使用方括号括起来即可。
列表就像一个大口袋什么都可以装。列表可以嵌套列表
格式:
变量名=[element1,element2,element3]
列表的索引操作
列表也是一种序列,序列内的元素都是有标号的,即从0开始,可以通过索引访问。
eg:
lst = [1,2,3,4,5]
print(lst[2])
列表的元素修改:lst[3]=100
列表可通过“+”连接:lst1=[‘a’,’b’] lst2 = lst1+lst
列表删除:del lst2[3] #无返回值
del lst
清空列表:lst.clear()
实际上,数字、字符串、列表,包括元祖、集合和字典都可以使用del来进行删除。
lst1 = [1,2,3,4,5]
lst2 = lst1
lst1和lst2同时指向这个列表的地址。改了其中一个,另一个随之改变。
若是不想同时指向同一个位置,改变其中一个,不随之改变,可使用以下方法赋值
- 方法一:Lst2 = lst1[:] 切片
- 方法二:lst2 = lst1.copy()
列表嵌套
Eg:
lst1 = [1,2,3,4,5]
lst2 = ['哈哈哈', 2, 'saft', ['1','2'], lst1]
获取:print(lst2[3][1])
列表的常用方法
1、 list.append(obj):在列表末尾添加新的对象,默认添加至列表最后
2、list.count(obj):统计某个元素在列表中出现的次数
3、list.extend(seq):在列表末尾一次性追加另一个了序列中的多个值(用心列表扩展原来的列表)
4、list.index(obj):从列表中找出某个值第一个匹配项的索引位置,索引从0开始
5、list.insert(index,obj):将对象插入列表
6、list.pop(index):移除列表中的一个元素,默认最后一个元素,并且返回该元素的值
7、list.remove(obj):移除列表中某个值的第一个匹配项,不能删除子列表中的内容
8、list.reverse():反向列表中元素,倒转
lst = [1,2,3,4]
lst.reverse()
print(lst)
结果:
[4, 3, 2, 1]
9、list.sort():对原列表进行排序(无返回值),降序排序添加参数:reverse=True,False为升序,默认升序。
10、max(list):求列表最大值
11、min(list):求列表最小值
12、sum(list):求列表和,针对数值型
13、len(list):求列表中元素的个数
14、list(str):将字符串强制转换为列表
15、list(range(start,end=None)):快速生成指定范围内的数字列表
5、元组类型——不可变
python的元组与列表相似,不同之处在于元组的元素不能修改;元组使用小括号(),列表使用方括号[];元组创建很肩膀,只需要在括号中添加元素,并使用逗号隔开即可。
eg:
tup=('123','hello')
格式:
变量名 = (element1,element2,element3)
注意:元组一旦初始化,就不允许被修改
如果元组的元素只有一个的话,必须在这个元素后面加一个逗号,才会定义为一个元组对象,若是没有逗号,则第一个元素是什么类型,它就是什么类型。
id:查看变量内存地址
type:查看变量类型
元组常用方法
- len(tuple):计算元组元素个数
- max(tuple):返回元组中元素最大值
- min(tuple):返回元组中元素最小值
- tuple(seq):将列表转换成元组
6、 集合数据类型
python中的set和其他语言类似,是一个无序不重复的元素集,主要用于消除重复元素。
如何创建集合:
1、使用花括号,如:s = {1,2,3}
2、使用set()函数,如s1 = set([1,2,3,4])
这种方式,相当于将其他类型的数据强制转换成集合类型
因为集合是无序的,所以集合没有下标。
思考:
如何将一个字符串转换成集合,比如('hello world!')
集合的常见操作:
- 添加元素:s.add(12)
- 删除一个元素:s.remove('aa')
- 删除整改集合,连变量一起删除:del(s)
- 清空集合:s.clear()
- 长度计算:len(s)
判断元素是否在集合中。
7、 字典数据类型
字典与列表一样是python中最常用的。
python字典是键值对组成的数据结构,其中键是不可以重复,但值可以重复。
字典(dictionary)是除列表之外,python中最灵活的内置数据结构类型。只有不可变数据类型可以作为字典的键,因为键是必须可哈希,可哈希的只有不可变数据类型,数值型、字符串、元组。
列表是有序的对象集合,字典是无序的对象集合。两者之间的区别在于:字典当中的元素是通过键来存取的,二不是通过索引来存取。
字典的每个键值(key => value)对用冒号(:)分割,每个对之间用逗号(,)分割,整改字典包括在花括号中({})
格式:
d = {skey1:value1,key2:value2}
字典的特性:
1. 无序。
2. 键不可重复,可以通过键取得对应的值,值可重复。
若重复了,最新的值会覆盖之前的值。
字典常用方法
- dict.clear():删除字典内所有元素
- dict.copy():返回一个字典的深复制
- dict.fromkeys([]):创建一个以seq中的元素作为键的新字典
- dict.get(key,default=None):返回指定键的值,如果值不在字典中返回default的值
- dict.update(dict2):把字典dict2的键/值对更新到dict里
- dict.keys():以列表返回一个字典的所有键
- dict.values():以列表返回字典中的所有值
- dict.items():返回字典中键值对列表
- dict.popitem():随机删除字典里面的任意一项
- dict.pop(key):删除指定的键值对
键因为是不可重复的,所以键必须是不可变数据类型。比如,键不可以是列表、集合。元组、数字、字符串可以作键。
根据键名获取值有两种方法:
1. dict[键名]
2. dict.get(键名)。
使用第二种方法比较好,因为如果这个键不存在,第一种方法会抛出异常,第二种方法返回None。
8)python控制结构
Python的控制结构有三种:
顺序结构、分支结构(又称判断结构)、循环结构
01. 分支结构
比较运算符:
if a>b:
if a<=b:
if a==b:
if a!=b:
if a: #当a为真时条件成立,等价于 if a==True
if not a: #当a为假时条件成立,等价于 if a==False
Python种会被认为是假(False)的值:None、[]、‘’、0、{}、()
02. 循环结构
Python中的循环有while循环和for循环两种形式
如何选择for循环和while循环
For循环一般用在一个已知的集合里面进行循环的时候,比如列表里面的循环,range数字范围内循环、集合循环、字典循环等。
While一般用于明确知道循环条件,比如大于某个值,或者某个值为真或为假时运行循环。
循环中加入else
循环中的else语法。不管for循环还是while循环,当循环中写了else语句时。只有当循环体整测循环结束后才会执行else里面的语句。如果循环过程中执行了break,则else不会执行。
break用于跳出当前循环,continue用于结束本次循环,并继续下一次循环。
会被python认为是假值:None、[]、''、0、{}、()、False
占位关键字pass
当循环体或者函数定义中赞数没有内容时,可以使用pass占位符进行占位。Python中pass是空语句,是为了保持程序结构的完整性。Pass不作任何事情,一切用做占位语句。
9)函数
为什么要使用函数?
避免冗长,精炼可重复例用,实现模块化的程序设计。
- 函数是python为了代码最大程度的重用和最小化代码冗余二提供的基本程序结构。
- 函数是一种设计工具,它能让程序员将复杂的系统分解为可管理的不见。
- 函数用于将相关功能打包并参数化。
- 从类型上来说,python中有4中不同类型的函数:
- 内置函数:python内置已经写好的函数,如range、print等
- 模块函数:一个python模块中导入的函数
- 自定义函数
- 嵌套函数
01函数的定义
Python定义函数必须使用def关键字,函数名为用户自定义名称(函数名称的定义规范和普通变量名一致),参数列表为传给函数使用的参数。
格式:
def 函数名(参数列表):
函数体
规则:
- 函数代码以def关键字开头,后面接函数表示符名称和圆括号()。
- 任何传入从外部传入函数的参数必须放在函数标识符后面的圆括号中。
- 函数的第一行语句可以选择性地使用文档字符串——用于存放函数说明
- 函数内容以冒号起始,并且缩进。return[表达式]结束函数,选择性地返回一个值给对方调用,并且退出当前函数执行。
- 不带表达式的return相当于返回None
注意:对于自定义的函数,必须在使用前定义。否则会报函数未定义的异常。
02函数参数
改变形参的值是否会同时改变实参的值,这取决于参数的数据类型。
如果参数是不可变数据类型,则改变形参的值并不会改变实参的值
如果参数是可变数据类型,则改变形参的值也同时会改变实参的值。
参数:形参 实参
常见类型:
- 关键字参数
- 位置参数(必须正确位置传入函数),关键字参数(可用等号设置默认值)
- 默认值参数(形参设置默认值,若是没有传递参数,则会值用默认参数。)
- 不定长参数(形参前加*的变量名,会存放所有未命名的变量参数。如果在函数调用时没有指定参数,它就是一个空元组)
lst前面的*号自动代表解包lst这个列表,让lst列表中的每个元素作为函数的参数
还可以通过定义**kwargs来传递字典类型的不定长参数
03函数变量的作用域
一个变量必须先初始化再访问。
Python中,程序的变量并不是在哪个位置都可以访问的,访问权限决定于这个变量在哪里赋值的。
变量的作用域决定了在哪一部分程序可以访问哪个特定的变量名称。
根据变量的作用域,函数中的变量可分为全局变量和局部变量。
函数内的想改变全局变量时,需要再函数内使用关键字global(如global x)
04函数的返回值
return:结束当前函数的运行。
给当前函数返回一个指定的值,默认是None
什么时候需要返回值,什么时候不需要?取决与函数的调用方需要什么值,取决于函数本身是干嘛的
05全局变量的使用规则如下:
- 当我们在一个函数中创建一个变量时,默认情况下它时局部变量,只在当前函数生效。
- 当我们在一个函数之外定义一个变量时,默认情况下它是全局变量。不必加global关键字。
- 在函数里面读取一个全局变量时,不需要加global,但如果要给全局变量重新赋值,则必须使用global。注意,如果调用该变量的方法不算重新赋值,比如list.append这种可以不用global。
- 如果函数内部有与全局变量名字相同的局部变量,则全局变量必须使用global来进行标识。
- 在一个函数外使用global关键字没有效果。
06匿名函数
匿名函数的定义方式
匿名函数的关键字是:lambda
eg:
lambda定义一个匿名函数,只支持一行。一般用于比较简单的处理
a = lambda : print('hello,world')
a()
func = lambda a,b : a+b #默认会返回一个a+b的值,不用去写return
print(func(1,2))
10)蜗牛ATM代码实战
如下:
11)Python包和模块/模块管理
什么是模块?
模块是一个包含所有你定义的函数和变量的文件,其后缀名是.py。模块可以被使用该模块中的函数等功能,这也是别的程序引入,以使用python标准库的方法。
模块举例:
import keyword 关键字模块
import random 随机数模块
import time 时间模块
import math 数学模块
01 包和模块的导入
Eg:如图,若是file1想要调用file2的对象、方法等,如何操作
方法1:
import model
方法2:
from module import funcname
from module import fa,fb,fc
from module import classname
from module import * #导入这个模块的所有函数和变量
规范:
如果你要经常访问模块的属性和方法,且不想一遍又一遍地敲入模块名,使用from module import *
如果想要有选择地导入某些属性和方法,而不想要其它的,使用from module import xx
如果模块包含属性和方法与你某个模块同名,你必须使用import module来避免名字冲突
尽量少用from module import *,因为判定一个特殊的函数或属性是从哪里来的有些困难,并且会造成调试和重构都更加困难。无法知道导入的包里有哪些变量和函数。如果与导入的包存在相同的函数,会执行当前文件的函数,有可能存在潜在的问题。
关于if __name__=='_main_':语句的作用:
__name__属性是每个py文件的内置属性,当这个文件是被直接执行时,__name__属性的值为_main_。如果被作为一个包导入到别的文件中使用时,__name__属性的值会变为文件名,所以我们可以利用这个特性来判断当前文件的使用方式,从而执行特定的代码。
当我们导入包的时候,没有想要执行导入文件的测试语句,怎么解决
可利用特性,如图,即可。因为当__name__==_main_时,才执行下面的语句,但如果时通过导包的方式执行,其值不等于_main_,不执行test1().
12)Python文件操作
01 文件读写
python操作文件的基本语法格式:
with open(r'文件路径',mode='文件操作模式') as f:
文件具体操作代码
注意:
其中变量名f是指向打开文件的句柄(可以任意替换为其他有效变量名)
文件路径可以是相对路径,也可以是绝对路径
open方法只能用于读取txt、csv等文本文件,不能读取word、excel等第三方文件,第三方文件必须用专门的库才能操作。
相对路径:
引用下一级目录:
引用上一级目录:
绝对路径:不建议
with open(r'D:\Prgram msg\python\note.text') as f:
pass
常见文本文件读写模式:
r读模式,只能进行读操作,不能写操作,而且文件必须事先保存,否则会报找不到文件的异常,默认就是r模式
w写模式,只能进行写操作,不能进行读操作。如果用w模式打开一个已经存在的文件,会立即清空以前的文件内容。如果要打开的文件不存在,则会自动创建对应的文件。
a追加写模式,也不能读操作,只能写操作,但是在文件尾部追加写入新的内容。文件可以事先不存在
02常用文件读取方式
f.read() #一次性读取所有文件的内容
f.read(100) #读取参数指定的字符长度,如果不足,不报错
f.readline() #读取一行内容,如果指定数字则只读取一行中指定的字符数
f.readlines() #按行读取全部内容到一个列表中
for line in f: #直接通过一个循环来读取文件
03 文件写入
- 以w模式打开文件
- 写数据的几种方式(如果要换行必须自己添加换行符)
- 以字符串形式写入: f.write(“要输入的字符串”)
- 以列表形式写入:f.writelines(list_of_text_strings)
注意:在写入大量内容是,调用writelines写入多行在性能上会比使用weitr一次性写入要高。
with open(r'note1.text',mode='w',encoding='utf-8') as f:
f.write('欢迎来到中国!')
多行写入:
with open(r'note1.text',mode='w',encoding='utf-8') as f:
content = ['我本将心向明月\n','奈何明月照沟渠']
f.writelines(content)
13)异常处理
异常:语法上正确,逻辑上错误 。
大多数异常都不会被程序处理,都以错误信息的形式展现,异常以不同的类型出现,这些类型都作为信息的一部分打印出来;例子中的类型有:
ZeroDivisionError、NameError、TypeError
错误信息的前面部分显示了异常发生的上下文,并以调用栈的形式显示具体信息。
01异常处理代码的原则
- except语句不是必须的,finally语句也不是必须的,但是二者必须要有一个,否则就没有try的意义了。
- except语句可以有多个,python会按except语句的顺序依次匹配指定的异常,如果异常已经处理就不会再进入后面的except语句。
- except语句可以以原则形式同时指定多个异常
- except语句后面如果不指定异常类型,则默认捕获所有异常
- 只要有finally语句,不管有没有异常,finally里面的代码都回执行
try:
可能出现异常的代码
except 异常类型1:
异常类型1的处理代码
except 异常类型2 as e:
异常类型2的处理代码
except 异常类型n:
异常类型n的处理代码
except:
其他未知异常的处理代码
finally:
异常处理结束后要执行的代码
eg:
while True:
a = input('请输入一个数字:')
b = input('请输入第二个数字:')
try:
result = int(a) / int(b)
print(result)
break
except ValueError:
print('请输入一个有效的十进制数字!')
except ZeroDivisionError:
print('分母/除数不能为0!')
finally: #不管有没有异常,只要定义了都会进入finally进行处理
print('进入了finaly!')
五)python面向对象
1)面向对象的基础概念
面向对象编程有什么好处,为什么要使用面向对象编程?
面向对象编程以对象作为程序的基本单元,将方法和数据封装其中,它具有继承、封装、多态三个特性,可以大大提高软件的重用性、灵活性和扩展性。
- 面向过程:做一件事情,需要按照什么样的过程来完成。
- 面向过程是一种是事件为中心的编程思想。就是分析出解决问题所需的步骤,然后用函数把这写步骤实现,并按顺序调用。
- 面向对象:将一个事情先想象为一个对象,然后通过提取该对象的所有共同的方法和属性,利用这些方法和属性来完成这件事情的思想。
- 面向对象就是:把数据及对数据的操作方法放在一起,作为一个相互依存的整体——对象。对同类对象抽象出其共性,形成类。类中的大多数数据,只能用本类的方法进行处理。类通过一个简单的外部接口与外界发生关系,对象与对象之间通过消息进行通信。程序流程由用户在使用中决定。对象即为人对各种具体物体抽象后的一个概念,人们每天都要接触各种各样的对象,如手机就是一个对象。
方法其实就是函数在面向对象编程里面的一种叫法。
属性其实就是变量在面向对象编程里面的一种叫法。
参考:python基础之类,对象,类方法,实例方法详讲_追光的博客-CSDN博客_python类方法实例方法
类:
类是抽象的,在使用的时候通常会找到这个类的一个具体的存在,使用这个具体的存在。
一个类可以找到多个对象。比如图纸,手办的图纸,老虎,东北虎,这都是类。类是一个抽象的概念。
类:具有相同属性和方法的总称。类的组成由属性和方法组成,属性可以称为成员变量,方法可以称为成员函数。
对象:类的实例。
面向对象里面对象的方法不能直接调用,只能通过类或者实例来进行调用
类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
实例变量:在类的声明中,属性是用变量来表示的。这种变量就称为实例变量,是在类声明的内部但是在类的其他成员方法之外声明的。
Python3中的object为所有类的基类,所有类在创建时默认继承object,所以不声明继承object也可以,如:class className(object): 与 class className():
对象:
类实例化了就是对象
对象是类的一个实例,有状态和行为。对象包括两个数据成员(类变量和实例变量)和方法。
某一个具体事物的存在,在现实世界中可以是看得见摸得着的。对象是类抽象概念的实物表达,可以是直接使用的。我画的一张图纸,我看见的那只老虎。
数据成员:类变量或者实例变量, 用于处理类及其实例对象的相关的数据。
也就是说对象是类的具体表达;
而类则是对象的抽象表达。
实例对象:
类的实例化,具象的类对象。对象的创建,创建对象的过程称之为实例化,
通过一个类,可以创建多个对象:
- __init__方法方法,用来做变量初始化 或 赋值 操作
- __init__()方法,在创建一个对象时默认被调用,不需要手动调用
- __init__(self)中的self参数,不需要开发者传递,python解释器会自动把当前的对象引用传递过去
- __init__(self)中,默认有1个参数名字为self,如果在创建对象时传递了2个实参,那__init__(self)中出了self作为第一个形参外还需要2个形参,例如__init__(self,x,y)
2)面向对象的基本特性
01类定义
使用class关键字
格式:
class Classname:#括号可不加,一般继承父类的时候要加,其他情况不加
类的代码
init方法会在初始化一个类的实例的时候自动调用,属性,一般放到__init__方法里面
Eg:
class Student:
# def __init__(self): #self代表这是一个实例方法,只能由Student类的实例调用
# self.name = 'zhangsan' # 属性,一般放到__init__方法里面
#或者
def __init__(self,name,age,sid): #init方法会在初始化一个类的实例的时候自动调用
self.name = name
self.age = age
self.sid = sid
def study(self): #方法
print('{}在学习'.format(self.name))
#面向对象里面对象的方法不能直接调用,只能通过类或者实例来进行调用。
stu = Student('zhangsan',14,'s001') #实例是特定的对象
stu.study() #利用对象调用方法
python里面定义了一个终极父类object,所有的类默认继承终极父类。Eg:即上述类全写出来即class Student(object)
几个重要的概念:
Python面向对象编程中有几种比较特殊的方法。
02实例方法
只能由类的实例,也就是对象来调用,第一个参数总是self,调用时由python自动传入当前调用该方法的实例
实例的权限高于类权限。实例方法可以调用类属性,反正类不可直接访问实例属性。
self的作用
主要是在定义方法时表明当前方法是一个实例方法。只能由这个类的实例进行调用。self在定义方法时,必须以第一个参数的形式定义到实例方法中。而在调用时,则不需要写self参数。self是隐式传递给实例方法。
class Student:
def study(self,name): #方法
print('{}在学习'.format(name))
stu = Student() #实例是特定的对象
stu.study()
当通过类去调用的时候,会报异常
03类方法
使用@classmethod来修饰,类方法默认以cls参数作为第一参数,调用时可以以类直接进行调用,也可以以实例来调用。但类方法不能访问对象属性(即通过self.xxx定义的属性),只能访问类属性(类能做的事情,实例能做,实例能做的事情并不是所有类能做)
类方法:
类方法必须由@classmethod来进行修饰,第一个参数必须为cls.并且可以用类名直接方法,也可以由实例来访问。实例的权限高于类权限。
class Student:
@classmethod
def running(cls):
print('学生在跑步')
stu = Student() #实例是特定的对象
stu.running() #实例调用
Student.running() #类调用
class Student:
a = 1 #类属性
def study(self,name): #方法
print('{}在学习'.format(name))
print(Student.a)
stu = Student() #实例是特定的对象
stu.study('lisi')
print(Student.a)
stu.a
什么时候应该定义类方法,而什么时候定义实例方法。
与具体的某个实例没有关系的方法,一般会定义称类方法,直接调用。
跟具体的某个实例有关,每个实例可能都不一样的方法,一般会定义称实例方法,由实例来访问。
04属性方法
属性:
- 类属性
- 实例属性
可以像属性一样进行调用的方法。目的时为了放置直接对属性的值进行修饰。
#area应该通过宽和高进行决定的,但如果是属性方法,调用时进行更改了值,存在安全隐患,直接将属性暴漏出来了。
如下:
class Rectangle:
def __init__(self,height,wight):
self.height = height
self.wight = wight
self.area = self.height * self.wight
rectangle = Rectangle(10,5)
print(rectangle.area)
#area应该通过宽和高进行决定的,但如果是属性方法,调用时进行更改了值,存在安全隐患,直接将属性暴漏出来了。
rectangle.area = 100
print(rectangle.area)
有什么解决方法:
笨方法如下:
class Rectangle:
def __init__(self,height,wight):
self.height = height
self.wight = wight
#self.area = self.height * self.wight
def get_are(self):
return self.height * self.wight
rectangle = Rectangle(10,5)
print(rectangle.get_are())
#以上的漏洞,类都是公用的,别人都已经写好了,但后来改成如上这种方式,别人的代码就需要修改代码,工作量大
改善如下:
既不用修改代码,但又修改了漏洞
class Rectangle:
def __init__(self,height,wight):
self.height = height
self.wight = wight
@property
def area(self):
return self.height * self.wight
rectangle = Rectangle(10,5)
print(rectangle.area)
05构造方法
构造方法:__init__()
引用父类的构造方法:super.__init__()
06实例方法和类方法的区别
2) 面向对象的特性
面向对象编程时一种编程方式,此编程方式的落地需要使用“类”和“对象”来实现,所以,面向对象编程其实就是对“类”和“对象”的使用。
面向对象的三大特性:继承、封装和多态
python具备封装和多态的特性,语言所自带的特性,本身编程中不会刻意使用。
python的封装:隐藏对象的属性和实现细节,仅对外提供公共访问方式。把特定的业务逻辑写到一个方法或定义到一些属性里面,然后把属性和方法设定权限,并不是每个类和方法都能访问这些属性或方法。
为什么封装和多态用的不多,因为python本身没有去定义类和对象的权限
与Java不同,Python的访问控制相对简单,没有public,private,protected等属性,python认为用户在访问对象的属性的时候是明确自己在做什么的,因此认为私有数据不是必须的,但是如果你必须实现数据隐藏,也是可以的,具体方法就是在变量名前加双下划线。如__privatedata=0,定义私有方法则是在方法名称前加上__下划线。但即使对于隐藏的数据,也是有一定的方法可以访问的。方法就是__className__attrName。Python对于私有变量会进行Namemangling是Python中为了方便定义私有的变量和方法,防止和继承类以及其他外部的变量或者方法冲突而采取的一种机制。在python中通过__spam定义的私有变量为最终被翻译成_classname__spam,其中classname为类名,当类名是以_开头的时候则不会发生Namemangling。Namemangling 存在的一个问题是当字符串长度超过255的时候则会发生截断。
python的多态:一个接口,多种实现
参考:Python学习(七)面向对象 ——继承和多态 - feesland - 博客园
强类型的变量类型是一经声明不能改变的,在编译时就进行检查,如Java
弱类型变量是根据使用的情况随时改变的,由解释器解释,如JavaScript
Python是弱类型
01继承
通过继承创建的新类称为子类或派生类,被继承的类称为基类、父类或超类。
继承语法
class 派生类名(基类名)
在python中继承中的一些特点:
1、如果在子类中需要父类的构造方法就需要显式的调用父类的构造方法,或者不重写父类的构造方法。详细说明可查看: python 子类继承父类构造函数说明。
2、在调用基类的方法时,需要加上基类的类名前缀,且需要带上 self 参数变量。区别在于类中调用普通函数时并不需要带上 self 参数
3、Python 总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)。
如果在继承元组中列了一个以上的类,那么它就被称作"多重继承" 。
语法:
派生类的声明,与他们的父类类似,继承的基类列表跟在类名之后,如下所示:
class SubClassName (ParentClass1[, ParentClass2, ...]):
...
你可以使用issubclass()或者isinstance()方法来检测。
issubclass() - 布尔函数判断一个类是另一个类的子类或者子孙类,语法:issubclass(sub,sup)
isinstance(obj, Class) 布尔函数如果obj是Class类的实例对象或者是一个Class子类的实例对象则返回true。
Eg:
class RichMan:
def __init__(self,money,company):
self.money = money
self.company = company
def earMoney(self,numer):
self.money += numer
def spendMoney(self,number):
self.money -= number
def showMoney(self): #结算
print('Ricg nab has:'+str(self.money))
class RichChild(RichMan): #继承于RichMan
pass
#如果子类没有定义自己的方法的时候,就会自动调用父类的方法
rc = RichChild(100000000,8)
print(rc.money) #富二代的钱
eg2:
class RichMan:
def __init__(self,money,company):
self.money = money
self.company = company
def earMoney(self,numer):
self.money += numer
def spendMoney(self,number):
self.money -= number
def showMoney(self): #结算
print('Ricg man has:'+str(self.money))
class RichChild(RichMan): #继承于RichMan
def __init__(self,money,company): #init覆盖父类的会出错,当子类定义了自己的init方法,务必先显式调用父类的init方法,否则父类会初始化失败,则必须有父类的参数,因为要初始化父类的init方法
super().__init__(money,company) #显示调用父类的init方法,确保父类初始化成功
self.ownMoney = 0 #富二代自己的账户
def earMoney(self,numer): #子类定义了父类中同名的方法,则子类方法会覆盖父类中的方法
self.ownMoney += numer
def spendMoney(self,number):
if self.ownMoney == 0:
self.Money -= number
else:
if self.ownMoney >= number:
self.ownMoney -= number
else:
print('富二代自己出钱:', self.ownMoney)
self.money -= (number - self.ownMoney)
print('富一代出钱:', (number - self.ownMoney))
self.ownMoney = 0
def showMoney(self):
if self.ownMoney>0:
print('I have '+str(self.ownMoney))
else:
print('I have no money,but my father has:',self.money)
def showFatherMoney(self):
print('my father has:', self.money)
#如果子类没有定义自己的方法的时候,就会自动调用父类的方法
rc = RichChild(10000,8)
print('富二代自己的钱:',rc.ownMoney)
print('富二代的公司:',rc.company)
rc.earMoney(1000)
rc.showMoney()
print('富二代的钱:',rc.ownMoney)
rc.spendMoney(100)
print('富二代剩余的钱:',rc.ownMoney)
rc.spendMoney(10000)
print('富二代剩余的钱:',rc.ownMoney)
rc.showMoney()
rc.showFatherMoney()
rm = RichMan(10000,8)
rm.spendMoney(100)
rm.showMoney()
print('富一代的钱:',rm.money)
02继承方法:
- 如果子类没有定义自己的初始化函数,父类的初始化函数会被默认使用,但是如果要实例化子类的对象,则只能传入父类的初始化函数对应的参数,否则会出错
- 如果子类定义了自己的初始化函数,而子类中没有显式调用父类的初始化函数,则父类的属性不会被初始化
- 如果子类定义了自己的初始化函数,在子类中显示调用父类,子类和父类的属性都会被初始化
六)Python进阶
1)装饰器
用来装饰其他函数的函数,即为其他函数添加特定功能或约束的函数(在python中装饰器都是以@符号开头)
装饰器的两个原则:
装饰器不能修改被装饰函数的源码
装饰器不能修改被装饰函数的调用方式
学习装饰器之前那必须掌握的概念:
函数即变量
高阶函数
嵌套函数
装饰器=高阶函数+嵌套函数
01函数即变量
函数既可以直接被调用,也可以作为变量进行赋值
def boo():
print('in boo')
a = boo #如果函数名后面加了括号,则代表执行该函数,如果函数名后面没有加括号,则指代表函数的一个引用
a()
函数名跟变量名一样,只是一个变量的标识符,它只想函数定义对应的内存地址
在函数定义中去调用其他函数时,并不回立即调用该函数
Eg:不会报错
def foo():
boo()
print('in foo')
def boo():
print('in boo')
foo()
在执行一个调用了其他函数的函数时,如果在内存中还没有找到被调用的函数的定义,则程序会报错
Eg:会报错
def foo():
boo()
print('in foo')
foo()
def boo():
print('in boo')
02高阶函数
符合下列条件至义的函数就是高阶函数:
接受函数名作为形参
返回值中包含函数名
高阶函数的两个条件对编写装饰器的意义:
接受函数名作为形参(不改变被装饰器函数的代码的前提下增加功能)
返回值中包含函数名(不改变被装饰函数的调用方式)
Eg:
def foo():
print('in foo')
def gf(func):
print(func)
func()
gf(foo)
Eg2:
import time
def foo():
sum = 0
for i in range(10000):
sum += i
print(sum)
def gf(func):
start_time = time.time() #记录当前时间
func()
end_time = time.time() #记录结束时间
print('函数运行时间为:',end_time-start_time)
gf(foo)
03嵌套函数
def foo():
print('in foo')
def boo():
print('in boo')
foo()
结果只执行了print('in foo')的打印
04装饰器
定义类方法时需要添加的装饰器是:@classmethod
装饰器基本编写套路:
第一步:顶一个接受函数名作为参数的高阶函数
第二步:再高阶函数中定义一个嵌套安徽念书,再该嵌套函数中
封装想要添加的功能代码
调用作为参数传入的函数名
返回嵌套函数的函数名
Eg:
import time
def foo():
sum = 0
for i in range(10000):
sum += i
print(sum)
def timer(func):
def gf():
start_time = time.time()
func()
end_time = time.time()
print('函数运行的时间:',end_time - start_time)
return gf
foo = timer(foo)
foo()
根据定义修改后:
import time
def timer(func):
def gf():
start_time = time.time()
func()
end_time = time.time()
print('函数运行的时间:',end_time - start_time)
return gf
@timer #为了方便使用装饰器,python专门定义的装饰器的语法糖
def foo():
sum = 0
for i in range(10000):
sum += i
print(sum)
foo()
2)多线程编程
1、 线程和进程的基本概念
进程是资源分配的最小单位,线程是CPU调度的最小单位。每个进程里面至少有一个线程。
线程:实际完成任务的对象。
2、 线程和进程的关系
eg:
import threading
import time
nameList = ['woniu','python','test']
def action(content):
for item in content:
print(threading.current_thread().getName()+item) #threading.current_thread().getName()获取当前线程
time.sleep(1)
for i in range(1,4):
#参数必须以元组形式传入,如果只有一个参数,必须打逗号
t = threading.Thread(target=action, args=(nameList,))
t.start() #启动线程
print('主线程结束')
结果每次样式都不一样,但内容一样。根据当前CPU情况决定。
默认的主线程是看不到的。
线程常用方法:
join方法:用于阻塞主线程,等子线程运行完后再运行主线程(主线程等待子线程知道天荒地老)
setDaemon方法:主线程结束,子线程也必须跟着结束
如何让print在所有线程都结束后,再打印?
eg1
for循环每次都会阻塞一次主线程。一个一个出来。
import threading
import time
nameList = ['woniu','python','test']
def action(content):
for item in content:
print(threading.current_thread().getName()+item) #threading.current_thread().getName()获取当前线程
time.sleep(1)
for i in range(1,4):
#参数必须以元组形式传入,如果只有一个参数,必须打逗号
t = threading.Thread(target=action, args=(nameList,))
t.start() #启动线程
t.join()
print('所有工作结束')
三个三个一起出来:
import threading
import time
nameList = ['woniu','python','test']
def action(content):
for item in content:
print(threading.current_thread().getName()+" "+item) #threading.current_thread().getName()获取当前线程
time.sleep(1)
threads = []
for i in range(1,4):
#参数必须以元组形式传入,如果只有一个参数,必须打逗号
t = threading.Thread(target=action, args=(nameList,))
t.start() #启动线程
threads.append(t)
for t in threads:
t.join()
print('所有工作结束')
setDaemon的例子:主线程结束,子线程也必须跟着结束
import threading
import time
nameList = ['woniu','python','test']
def action(content):
for item in content:
print(threading.current_thread().getName()+" "+item) #threading.current_thread().getName()获取当前线程
time.sleep(1)
threads = []
for i in range(1,4):
#参数必须以元组形式传入,如果只有一个参数,必须打逗号
t = threading.Thread(target=action, args=(nameList,))
t.setDaemon(daemonic=True)
t.start() #启动线程
threads.append(t)
# for t in threads:
# t.join()
print('所有工作结束')
3)Python的反射
反射:
通过字符串的形式在运行时动态修改程序的变量、方法及属性的操作。注意,对于反射操作中的所有的修改都会在内存中进行,所以它并不会实际修改代码。主要目的是提高代码在运行时的灵活性。
eg:
class Dog:
def __init__(self,name):
self.name = name
def eat(self):
print('{}正在吃东西...'.format(self.name))
def sleep(self):
print('{}正在睡觉...'.format(self.name))
dog = Dog('二哈')
#如果以下方式根据用户的需求进行执行,以下的方法,若是方法比较多的情况,变化后则很难维护和扩展
func = input('请输入您需要执行的方法名:')
if func == 'eat':
dog.eat()
elif func == 'sleep':
dog.sleep()
else:
print('该方法不存在')
此时,可通过反射可以动态去寻找类中是否有对应的方法,若是有则执行。如下:
class Dog:
def __init__(self,name):
self.name = name
def eat(self):
print('{}正在吃东西...'.format(self.name))
def sleep(self):
print('{}正在睡觉...'.format(self.name))
dog = Dog('二哈')
func = input('请输入您需要执行的方法名:')
if hasattr(dog,func): #对象,方法名
getattr(dog,func)() #getattr返回的是一个方法名
else:
print('没有这个方法和属性')
这个情况怎么办?
最简单的就是使用异常处理
class Dog:
def __init__(self,name):
self.name = name
def eat(self):
print('{}正在吃东西...'.format(self.name))
def sleep(self):
print('{}正在睡觉...'.format(self.name))
dog = Dog('二哈')
func = input('请输入您需要执行的方法名:')
if hasattr(dog,func): #对象,方法名
try:
getattr(dog,func)() #getattr返回的是一个方法名
except TypeError:
print(getattr(dog,func))
else:
print('没有这个方法和属性')
结果:
01 反射中最常用的四个方法:
hasattr |
输入一个字符串,判断对象有没有这个方法或属性。 |
getattr |
获取对象属性或方法的引用。如果是方法,则返回方法的引用,如果是属性,直接返回属性值。如果该属性或方法不存在,则抛出异常。 |
setattr |
动态添加一个方法或属性 |
delattr |
动态删除一个方法或属性 |
print(hasattr(dog,func)) #返回值是True和False
print(getattr(dog,func)) #getattr返回的是一个方法名
02 hastattr、getattr
如上
03 setattr
绑定属性:
class Dog:
def __init__(self,name):
self.name = name
def eat(self):
print('{}正在吃东西...'.format(self.name))
def sleep(self):
print('{}正在睡觉...'.format(self.name))
dog = Dog('二哈')
print(dir(dog)) #在绑定前先查询dog对象默认的属性和方法名
attr_name = input('请输入一个属性名:')
attr_value = input('请输入一个 属性值:')
setattr(dog,attr_name,attr_value)
print(dir(dog)) #绑定后查询dog对象的属性和方法
print('狗狗的年龄:',getattr(dog,attr_name))
绑定方法:
class Dog:
def __init__(self,name):
self.name = name
def eat(self):
print('{}正在吃东西...'.format(self.name))
def sleep(self):
print('{}正在睡觉...'.format(self.name))
dog = Dog('二哈')
def talk(content):
print('二哈说{}'.format(content))
method = input('请输入要绑定的方法名:')
setattr(dog,method,talk) #主要talk没有(),因为只是绑定它的方法名
print(dir(dog))
getattr(dog,method)('今天天气不错')
04 delattr
class Dog:
def __init__(self,name):
self.name = name
def eat(self):
print('{}正在吃东西...'.format(self.name))
def sleep(self):
print('{}正在睡觉...'.format(self.name))
dog = Dog('二哈')
def talk(content):
print('二哈说{}'.format(content))
method = input('请输入要绑定的方法名:')
setattr(dog,method,talk) #主要talk没有(),因为只是绑定它的方法名
print(dir(dog))
getattr(dog,method)('今天天气不错')
delattr(dog,method)
getattr(dog,method)('今天天气不错')
自动化测试,关键字驱动的时候,需在外部文件定义好,比如文本文件先定义好动作名称,通过python的文件动态的读取和动态的调用,这样工作量就小很多。
十一)python例题
- 输入一个字符串s,返回满足以下条件的字符串:找出与字符串的第一个字母相同的字母,把他们替换成'*'(第一个字母本身不用替换,例如:输入‘babble’,返回‘ba**le’)
s = 'babble'
print(s[0]+s[1:].replace(s[0],'*'))
2.编写一个简单的加减乘除计算器,加减乘除操作分别用函数实现。然后接受用户输入两个操作数和一个操作符进行计算,要求对可能的异常进行处理。
3.编写一个函数,接受用户指定的文件名和要查找的内容作为参数,函数读取这个文件,并将文件中包含要查找内容的每一行都输出到屏幕中。
def readfile(path,target):
with open(path,encoding='utf-8') as f:
for line in f:
if target in line:
print(line)
pa = input('请输出文件名:')
str = input('请输入要查找的内容:')
readfile(pa,str)
4、用python之禅定义一个变量s,现要求编写一个python函数将s中以空格分隔的每组字符首尾的两个字符组成一个新字符串(比如beautiful,则取be和ul组成新字符串,注意,新字符串中不能包含空格或其他任何不可见字符。如果空格分隔的字符串中的可见字符不足4位,则可以不予处理)并添加到一个列表里面,最后返回该列表。
def get_word(str):
mylist = str.split(' ')
strs = []
print(mylist)
for str in mylist:
str.strip() # 去掉首尾不可见的字符
if '\n'in str:
str.replace('\n','')
if len(str)>4:
newstr = str[:2] + str[-2:]
strs.append(newstr)
return strs
s = input('请输入一个字符串:')
print(get_word(s))
文章评论