字符串
1.字符串介绍
字符串在python中是基本数据类型,是一个不可变的字符序列
2.字符串的驻留机制
仅保存一份相同且不可变字符串的方法,不同的值被存放在字符串的驻留池中,Python的驻留机制对相同的字符串只保留 一份拷贝,后续创建相同字符串时,不会开辟新空间,而是把该字符串的地址赋给新创建的变量
驻留机制的几种情况(交互模式)
- 字符串的长度为0或1时
- 符合标识符的字符串
- 字符串只在编译时进行驻留,而非运行时
- [-5, 256]之间的整数数字
sys中的intern方法强制2个字符串指向同一个对象
PyCharm对字符串进行了优化处理
字符串驻留机制的优缺点
- 当需要值相同的字符串时,可以直接从字符串池里拿来使用,避免频繁的创建和销毁,提升效率和节约内存,因此拼接字符串和修改字符串是比较印象性能的。
- 在需要进行字符串拼接时建议使用str类型的join方法, 而非 + , 因为join()方法是先计算出所有字符中的长度,然后再拷贝,只new(创建)一次对象,效率要比使用“+”的效率高。
3.字符串的查询操作方法
index() 查找子串substr第一次出现的位置,如果查找的子串不存在时,则抛出ValueError
s='hello,hello'
print(s.index('lo')) #输出3
rindex() 查找子串substr最后一次出现的位置,如果查找的子串不存在时,则抛出ValueError
s='hello,hello'
print(s.rindex('lo')) #输出9
find() 查找子串substr第一次出现的位置,如果查找的子串不存在时,则返回-1
s='hello,hello'
print(s.find('lo')) #输出3
4.字符串大小写转换方法
upper()把字符串中所有字符都转成大写字母
s='hello'
a=s.upper()
print(a) #输出HELLO(a和s的地址不同,即产生一个新的字符串对象)
lower()把字符串中所有字符都转换成小写字母
s='HeLLo'
a=s.lower()
print(a) #输出hello
swapcase()把字符串中所有大写字母转换成小写字母,把所有小写字母转换成大写字母
s='HeLlo'
a=s.swapcase()
print(a) #输出hElLO
capitalize()把第一个字符转换为大写,把其余字符转换为小写
s='hellO,pYthon'
a=s.capitalize()
print(a) #输出Hello,python
title()把每个单词的第一个字符转换成大写,把每个单词剩余字符转换为小写
s='HeLLO,pyThON'
a=s.title()
print(a) #输出Hello,Python
5.字符串对齐
center()居中对齐,第1个参数指定宽度,第2个参数指定填充符,第2个参数是可选的,默认是空格,如果设置宽度小于实际宽度则返回原字符串
ljust()左对齐,第1个参数指定宽度,第2个参数指定填充符,第2个参数是可选的,默认是空格,如果设置宽度小于实际宽度则返回原字符串
rjust()右对齐,第1个参数指定宽度,第2个参数指定填充符,第2个参数是可选的,默认是空格,如果设置宽度小于实际宽度则返回原字符串
zfill()右对齐,左边用0填充,该方法只接收一个参数,用于指定字符串的宽度,如果指定的宽度小于等于字符串的长度,返回字符串本身
6.字符串劈分
'''split'''
s='hello world python'
lst=s.split() #默认劈分符为空格
print(lst) #输出['hello','world','python']
s1='hello|world|python'
print(s1.split(sep='|')) #通过参数sep指定劈分字符串,输出['hello','world','python']
print(s1.split(sep='|',maxsplit=1)) #通过参数maxsplit指定劈分字符串时最大劈分次数,输出 ['hello','world|python']
'''rsplit'''
lst1=s.rsplit()
print(lst1) #输出['hello','world','python']
print(s2.rsplit(sep='|')) #输出['hello','world','python']
print(s2.rsplit(sep='|',maxsplit=1)) #输出['hello|world', 'python']
7.判断字符串操作的方法
isidentifier()判断指定的字符串是不是合法的标识符
s='hello,python'
print(s.isidentifier()) #False
print('hello'.isidentifier()) #True
print('张三_'.isidentifier()) #True
isspace()判断指定的字符串是否全部由空白字符组成(回车、换行、水平制表符)
print('\t'.isspace) #True
isalpha()判断指定的字符串是否全部由字母组成
isdecimal()判断指定字符串是否全部由十进制的数字组成
isnumeric()判断指定的字符串是否全部由数字组成
isalnum()判断指定字符串是否全部由字母和数字组成
8.字符串的替换和合并
'''replace()'''
s='hello,python'
print(s.replace('python','java')) #用java替换python,输出hello,java
s1='hello,python,python,python'
print(s1.replace('python','java',2)) #输出hello,java,java,python
'''join()'''
lst=['hello','java','python']
print('|'.join(lst)) #输出hello|java|python
print(''.join(lst)) #输出hellojavapython
print('*'.join('python')) #输出p*y*t*h*o*n
9.字符串的比较操作
运算符:>,>=,<,<=,==,!=
比较规则 : 首先比较两个字符串中的第一个字符,如果相等则继续比较下一个字符,依次比较下去,直到两个字符串中的字符不相等时,其比较结果就是两个 字符串的比较结果,两个字符串中的所有后续字符将不再被比较
比较原理 : 两上字符进行比较时,比较的是其ordinal value(原始值),调用内置函数ord可以得到指定字符的ordinal value。与内置函数ord对应的是内置函数chr, 调用内置函数chr时指定ordinal value可以得到其对应的字符
print('apple'>'app') #True
print('apple'>'banana') #False
10.字符串的切片操作
字符串是不可变类型,切片将产生新的对象
s='hello,world' #[start:end:step]
s1=s[0:5] #第一个数字不写默认从零开始,第二个数字不写默认到最后结束
print(s1) #s1为hello
s0='hello,python'
s2=s0[0:7:2] #s2为hlop
s3=s0[::-1] #s3为nohtyp,olleh
s4=s0[-6::1] #s4为python
11.格式化字符串
'''%s占位符'''
name='张三'
age=30
print('我叫%s,今年%d岁' % (name,age))
'''{}占位符'''
print('我的名字叫{0},我今年{1}岁,我真的叫{0}'.format(name,age))
'''f-string格式化'''
print(f'我叫{name},今年{age}岁')
'''其他'''
print('%10d',99) #10表示的是宽度
print('%.3f'%3.141592) #四舍五入保留三位小数
print('%10.3f'%3.1415926) #10为宽度,3为保留的小数点后位数
print('{0:.3}'.format(3.1415278)) #0为索引,3为保留位数(一共的位数),输出3.14
print('{0:.3f}'.format(3.1415278)) #.3f为保留三位小数
print('{0:10.3f}'.format(3.1415278)) #.3f为保留三位小数,10为宽度
12.字符串的编码与解码
编码
s='天涯共此时'
'''在GBK这种编码格式中,一个中文占两个字节'''
print(s.encode(encoding='GBK')) #输出:b'\xcc\xec\xd1\xc4\xb9\xb2\xb4\xcb\xca\xb1'
'''在UTF-8这种编码格式中,一个中文占三个字节'''
print(s.encode(encoding='UTF-8')) '''输出:b'\xe5\xa4\xa9\xe6\xb6\xaf\xe5\x85\xb1\xe6\xad\xa4\xe6\x97\xb6''''
解码
s='天涯共此时'
byte=s.encode(encoding='GBK') #编码
print(byte.decode(encoding='GBK')) #解码
byte=s.encode(encoding='UTF-8') #编码
print(byte.decode(encoding='UTF-8')) #解码
函数
1.函数的定义与调用
'''创建'''
def 函数名([输入参数]):
函数体
[return xxx]
#例如:
def calc(a,b):
c=a+b
return c
#调用
result=calc(10,20)
print(result)
2.参数的传递
位置传参
def cala(a, b): #a和b称为形式参数,简称形参,形参的位置是在函数定义处
c = a + b
return c
result=cala(10,20) #10和20为实际参数的值,简称实参,实参的位置是函数调用处
print(result)
关键字传参
def cala(a, b): #a和b称为形式参数,简称形参,形参的位置是在函数定义处
c = a + b
return c
result=cala(b=10,a=20) #10和20为实际参数的值,简称实参,实参的位置是函数调用处
print(result)
3.函数的返回值
函数返回多个值时,结果为元组
def fun(num):
odd=[] #存奇数
even=[] #存偶数
for i in num:
if i%2:
odd.append(i)
else:
even.append(i)
return odd,even
lst=[10,11,12,13,14,15]
print(fun(lst)) #输出([11, 13, 15], [10, 12, 14])
函数在定义时,是否需要返回值,视情况而定
4.函数参数的定义
函数定义时,给形参设置默认值,只有与默认值不符的时候才需要传递实参
def fun(a,b=10):
print(a,b)
fun(100) #只传一个参数,b采用默认值,输出100 10
fun(20,30) #f30将默认值10替换,输出20 30
个数可变的位置参数:定义函数时,可能无法事先确定传递的位置实参的个数时,使用可变的位置参数;使用*定义个数可变的位置形参;结果为一个元组
def fun(*args):
print(args)
fun(10) #输出(10,)
fun(10,20,45,60) #输出(10, 20, 45, 60)
个数可变的关键字形参:定义函数时,无法事先确定传递关键字的实参的个数时,使用可变的关键字形参;使用**定义个数可变的关键字形参;结果为一个字典
def fun(**args):
print(args)
fun(a=10) #输出{'a': 10}
fun(a=10,b=20,c=50) #输出{'a': 10, 'b': 20, 'c': 50}
位置可变参数和关键字可变参数只能是一个
def fun(*args,*args1) #会报错,因为个数可变参数只能有一个
pass
def fun1(**args2,**args3) #会报错,因为关键字可变参数只能有一个
pass
def fun2(*args4,**args5) #不会报错
pass
5.变量的作用域
程序代码能访问该变量的区域
局部变量:在函数内定义并使用的变量,只在函数内部有效,局部变量使用global声明,这个变量就会就成全局变量
def fun(a,b):
c=a+b #c称为局部变量,因为c实在函数体捏进行定义的变量,a,b为函数的形参,作用范围也是函 #数内部,相当于局部变量
print(c)
'''global声明为全局变量'''
def fun1():
global age #函数内部定义的变量,局部变量,局部变量使用global声明,这个变量就成了全局变量
age=20
print(age)
全局变量:函数体外定义的变量,可作用于函数内外
name='小朱' #name的作用范围为函数内部和外部都可以使用,称为全局变量
print(name)
def fun():
print(name)
6.递归函数
如果在一个函数的函数体内调用了该函数本身,这个函数就称为递归函数
递归的组成部分有递归调用与递归终止条件
递归的调用过程:
每递归调用一次函数,都会在栈内存分配一个栈帧
每执行完一次函数,都会释放相应的空间
递归的优缺点:
缺点:占用内存多,效率低下
优点:思路和代码简单
'''递归计算阶乘'''
def fun(n):
if n==1:
return 1
else:
return n*fun(n-1)
print(fun(6))
BUG
1.Bug的常见类型
粗心导致的语法错误
'''1'''
age=input('请输入你的年龄:') #input输入的都是str类型,需要强制类型转换
if age>=18
print('成年人,做事需要负法律责任')
'''2'''
while i<10: #没有给i赋值
print(i) #用了中文括号
漏了末尾的冒号,如if循环语句,else子句等
缩进错误,该缩进的不缩进,不该缩进的瞎缩进
把英文符号写成中文符号,比如引号、冒号、括号
字符串拼接的时候,把字符串和数字拼在一起
没有定义变量,比如while的循环条件的变量
“==”比较运算符和“=”赋值运算符的混用
2.被动掉坑
'''若除数为0,则程序将会报错:ZeroDivisionError'''
a=int(input('请输入一个整数'))
b=int(input('请输入一个整数'))
result=a/b
print('结果为:',result)
'''利用try-expect结构'''
try:
a=int(input('请输入一个整数'))
b=int(input('请输入一个整数'))
result=a/b
print('结果为:',result)
expect ZeroDivisionError: #如果出现ZeroDivisionError错误将会执行以下语句
print('除数不能为0')
可以采用try-expect-expect-expect.....结构,也可以采用try-expect-expect.......else结构
try:
a=int(input('请输入一个整数'))
b=int(input('请输入一个整数'))
result=a/b
except ZeroDivisionError: #如果出现ZeroDivisionError错误将会执行以下语句
print('除数不能为0')
except ValueError:
print('出错了')
else:
print('结果为:',result)
try-except-except.....else-finally结构:
和上面的差不多,唯一不同的就是不论是否报错,finally块都会执行
python中常见的异常类型
序号 | 异常类型 | 描述 |
---|---|---|
1 | ZeroDivisionError | 取(或取模)零(所有数据类型) |
2 | IndexError | 序列中没有此索引(index) |
3 | KeyError | 映射中没有这个键 |
4 | NameError | 未声明/初始化对象(没有属性) |
5 | SyntaError | python语法错误 |
6 | ValueError | 传入无效的参数 |
1.traceback模块的使用
import traceback
try:
print('-----------')
print(1/0)
except:
traceback.print_exc()
输出的横线有时候在前,有时候在中,有时候在后。
类与对象
1.类与对象
类:类是多个类似事物组成的群体的统称。能够帮助我们快速理解和判断事物的性质
对象:100、99、520都是int类之下包含的类似的不同个例,这个个例专业术语称为实例或对象
2.类的创建
创建类的语法:
class Student:
'''Student为类的名称,简称类名,由一个单词或多个单词组成,每个单词首字母大写,其余小写(不大写也可,不报错)'''
pass
类的组成:类属性、实例方法、静态方法、类方法
class Student:
native_pace='吉林' #直接写在类里的变量,称为类属性
def eat(self): #实例方法,在类里面定义的称为方法,在类之外定义的叫函数
print('学生在吃饭......')
'''静态方法'''
@staticmethod
def method(): #静态方法不允许写self
print('我使用了staticmethod进行修饰,所以我是静态方法')
'''类方法'''
@classmethod
def cm(cls):
print('我是类方法,因为我使用了classmethod进行修饰')
def __init__(self,name,age):
self.name=name #self称为实例属性,进行了一个叫赋值的操作,将局部变量的name的值赋给实例属性,self.后不一定非叫name,叫什么都可以,name只是一种习惯
self.age=age
3.对象的创建
对象的创建又称为类的实例化
语法:实例名=类名()
#创建Student类的实例对象
stu=Student('Jack',20)
print(stu.name) #实例属性
print(stu.age) #实例属性
stu.info() #实例方法
意义:有了实例,就可以调用类中的内容
class Student:
native_pace='吉林' #直接写在类里的变量,称为类属性
def eat(self): #实例方法,在类里面定义的称为方法,在类之外定义的叫函数
print('学生在吃饭......')
'''静态方法'''
@staticmethod
def method(): #静态方法不允许写self
print('我使用了staticmethod进行修饰,所以我是静态方法')
'''类方法'''
@classmethod
def cm(cls):
print('我是类方法,因为我使用了classmethod进行修饰')
def __init__(self,name,age):
self.name=name #self称为实例属性,进行了一个叫赋值的操作,将局部变量的name的值赋给实例属性,self.后不一定非叫name,叫什么都可以,name只是一种习惯
self.age=age
#创建Student类的对象
stu1=Student('张三',20)
stu1.eat() #对象名.方法名
Student.eat(stu1) #与上一行代码功能相同,都是调用Student中的eat方法
#类名.方法名(类的对象)-->实际上就是方法定义处的self
print(stu1.name)
print(stu1.age)
4.类属性
类属性:类中方法外的变量称为类属性,被该类的所有对象所共享
类方法:使用@classmethod修饰的的方法,使用类名直接访问的方法
静态方法:使用@staticmethod修饰的方法,使用类名直接访问的方法
class Student:
native_pace='吉林' #直接写在类里的变量,称为类属性
def eat(self): #实例方法,在类里面定义的称为方法,在类之外定义的叫函数
print('学生在吃饭......')
'''静态方法'''
@staticmethod
def method(): #静态方法不允许写self
print('我使用了staticmethod进行修饰,所以我是静态方法')
'''类方法'''
@classmethod
def cm(cls):
print('我是类方法,因为我使用了classmethod进行修饰')
def __init__(self,name,age):
self.name=name #self称为实例属性,进行了一个叫赋值的操作,将局部变量的name的值赋给实例属性,self.后不一定非叫name,叫什么都可以,name只是一种习惯
self.age=age
#类属性的使用方式
print(Student.native_pace)
stu1=Student('张三',20)
stu2=Student('李四',30)
print(stu1.native_pace) #输出吉林
print(stu2.native_pace) #输出吉林
Student.native_place='天津'
print(stu1.native_pace) #输出天津
print(stu2.native_pace) #输出天津
#类方法的使用方式
Student.cm()
#静态方法的使用方式
Student.method()
5.动态绑定属性和方法
python是动态语言,在创建对象之后可以动态的绑定属性和方法
class Student:
def __init__(self,name,age):
self.name=name
self.age=age
def eat(self):
print(self.name+'在吃饭')
stu1=Student('张三',20)
stu2=Student('李四',30)
#为stu2动态绑定性别属性
stu2.gender='女'
print(stu1.name,stu1.age)
print(stu2.name,stu2.age,stu2.gender)
'''为stu1绑定show函数'''
def show():
print('定义在类之外的,称为函数')
stu1.show=show #为stu1绑定了show函数
stu1.show()
stu2.show() #这行代码会报错,因为没有为stu2绑定show函数