首页 > 编程语言 >Python速查

Python速查

时间:2022-12-18 20:33:09浏览次数:64  
标签:__ name Python self 字符串 lst print 速查

1. Python速览

官方文档
一定要注意使用的是哪个版本 有些效果会不同

1.1 安装教程

  1. 官网安装
  2. 使用IDLE自带软件编辑

2. 基础内容

2.1 用作计算器

通过python可以实现大部分的计算器功能。我们通过IDLE进行编译。

2.1.1 数字

运算符+-*/ 的用法,同时也支持括号 (()) 用来分组。

2+2 
2*2
(50-5*6)/4

除法运算/返回浮点数。用//运算符返回整数;计算求余用%;

混合类型运算数的运算会把整数转换为浮点数

17 / 3	# 除法运算
5.666666666666667
17 // 3	# 获得整数
5
17 % 3	# 求余
2
4 * 3.75 - 1	# 混合运算
14.0

**进行乘方

5 ** 2  # 5的平方
25

等号(=)用于给变量赋值,变量未定义(即,未赋值),使用该变量会提示错误
赋值变量符也是最低级的运算符

 width = 20
 height = 5 * 9
 width * height
 900

交互模式下,上次输出的表达式会赋给变量 _

意味着上次计算的结果下次可以直接通过 _调用,不用再赋值。

2.1.2 字符串

Python中的字符串不能被修改! immutable

用单引号('……')或双引号("……")标注的结果相同,反斜杠 \ 用于转义

可以通过将字符串赋值给特殊字符,通过print()函数输出

'"Yes," they said'
'"Yes," they said'
s=_	# 使用了 _ 进行直接调用最近的输出结果
print(s)
"Yes," they said

r添加在在引号前,原始输出字符 也叫原符号

print('C:hello\nhaha')
C:hello
haha
print(r'C:hello\nhaha')
C:hello\nhaha	# \n后面的字符正常输出了,不换行

一次性多行输出,python也可以实现。 一种实现方式是使用三重引号:"""..."""'''...'''
添加一个\可以减去print自带换行 只能加在前面

print('''\  
    多行输输出内容  
    输出内容和引号内的格式一模一样    可以不断输出  
''')  
  
print("""\  
    这是三对双引号输出内容  
""")

字符串可以视为字符组 从左往右索引是0开始,从右开始是负数

还可以获得子字符串

word='hello'
print(word[0])
print(word[-1])
print(word[0:2])
print(word[-3:-1]) 
print(word[-1:-3]) #无法遍历
print(word[0:]) #遍历到最后

注意:从0-->2 遍历hello时不会输出word[2] 应该是输出了 word[0] word[1]

同时负数的遍历也是从小到大的,写反是没有用的

分支结构

单分支结构

money=1000
s=int(input('请输入取款金额:'))
if money >= s: #双引号
    money-=s
    print('取款成功,余额为:',money) #if条件成立才执行缩进代码

双分支结构

a=int(input('请输入一个整数:'))
if a%2==0:
    print(a,'\b是整数')
else : #这里即使没有判断语句也要加 :
    print(a,'\b是奇数')

多分支结构

a=float(input('考试成绩:'))
if a>=90:
    print('sss')
elif a>=70:
    print("aaa")
elif a>=60:
    print('a')
else:
    print('c')

可以有零个或多个 elif部分,以及一个可选的 else 部分。 关键字 'elif' 是 'else if' 的缩写,适合用于避免过多的缩进。 一个 if ... elif ... elif ... 序列可以看作是其他语言中的 switchcase 语句的替代。

嵌套if使用

p=input('您是会员吗?y/n')
pay=float(input('输入您的消费金额:'))
if p=='y':
    if pay>=200:
        print('打八折,消费金额为:',pay*0.8)
    elif pay>=100:
        print('打九五折,消费金额为:',pay*0.95)
    else:
        print('不打折,消费金额为:',pay)
else:
    if pay>=200:
        print('打九五折,消费金额为:',pay*0.95)
    else:
        print('不打折,消费金额为:', pay)

条件表达式

print ( 条件为真结果 判断语句 条件为假 )

a=int(input('输入一个整数:'))
b=int(input('输入一个整数:'))
print(   (str(a)+'大于等于'+str(b))      if a>=b  else     ( str(a)+'小于等于'+str(b))    )

Pass语句

用在还未想到怎么写的地方 执行pass 程序不报错

if a>=b:
    pass
else:
    pass

循环

内置函数range

  1. 用于生成一个整数序列

  2. 创建range有三种方式:

    1. range(stop) 创建一个[0,stop)的步长为1的序列,不包含stop
    2. range(start,stop) 创建一个[start,stop)步长为1的序列
    3. range(start,stop,step) 创建一个[start,stop)之间的序列 步长为step
  3. 如果要查看序列内整数 需要用到 list()函数

    r=range(1,10)
    print(list(r)) # 1,2,3,4,5,6,7,8,9
    
  4. 只有在使用上range对象时,才会去计算range内的元素 不然无论序列多大 都只保存start stop step三个值

while循环

一般执行N+1次 因为最后一次是执行失败的

四步循环法

  1. 初始化变量
  2. 条件判断
  3. 条件执行体(循环体)
  4. 改变变量
# 要求从0累加到4 输出结果
sum,a=0,0 #初始化变量
while a<5: #条件判断
    sum+=a #条件执行体(循环体)
    a+=1
print('输出结果是:'+str(sum))

练习

1到100之间的偶数和

# sum=0 #累加总和
i=1 #初始化变量
sum=0
while i>0 and i<=100:
    if i%2==0:
        sum=sum+i
    i+=1
print(sum)

for-in循环

  • in表达会从(字符串 序列等可迭代对象)中依次取值,也叫遍历

  • 语法结构:

    for 自定义的变量 in 可迭代的对象:

    循环体

    for item in range(1,4):
        print(item)
    
    n='word'
    for a in n:
        print(a)
    
  • 如果循环体不需要访问自定义变量 自定义变量用下划线表示 那么for-in循环可以作为一种循环次数使用

    for _ in range(4):
        print('人生苦短,我用Python')
    

练习

# 1到100之间的偶数和
sum=0
for item in range(1,101):
    if item%2==0:
        sum+=item
print(sum)

# 100到999的水仙花数
for item in range(100,1000):
    a=item//100
    b=(item%100)//10
    c=item-a*100-b*10
    if item==pow(a,3)+pow(b,3)+pow(c,3):
        print(item)

流程控制语句break

用于结束循环结构,通常与分支结构If一起使用

#while循环
i=0
while i<3:
    psw = str(input('输入密码:'))
    if psw=='ffff':
        print('密码正确!')
        break
    else:
        print('密码不正确')
        i+=1
        
# for-in循环
for _ in range(3):
    psw=str(input('输入密码:'))
    if psw=='yexin':
        print('密码正确!')
        break
    else:
        print('密码不正确')
 

流程控制语句continue

用于结束当前循环,进入下一次循环,通常与分支结构中的if一起使用

# 要求输出1到50之间5的倍数
for item in range(1,51):
    if item%5!=0:
        continue
    else:
        print(item)
        
i=1
while i<51:
    if 5*i<=50:
        print(i*5)
        i+=1
    else:
        continue

else语句

三种搭配方法:

  • if: else:
  • while: else: 没有碰到break时执行else
  • for : else: 没有碰到break时执行else

练习

#while循环
i=0
while i<3:
    psw = str(input('输入密码:'))
    if psw=='ffff':
        print('密码正确!')
        break
    else:
        print('密码不正确')
        i+=1
else:
    print('对不起三次错误,无法输入')
# 最后else是与while配对的 while三次结束 输出else内容 对for-in同理

# for-in循环
for _ in range(3):
    psw=str(input('输入密码:'))
    if psw=='yexin':
        print('密码正确!')
        break
    else:
        print('密码不正确')
else:
    print('对不起三次错误,无法输入')

嵌套循环

for-in嵌套循环

'''
打印一个三行四列的矩形
'''
for _ in range(3):
    for _ in range(4):
        print('+', end='\t')
    print()
    
# 打印一个直角三角形
# print(str(i)+'*'+str(j)+'='+str(j*i),end='\t') 可修改为打印乘法表
for j in range(1,5):
    for i in range(1,5):
        if i<=j:
            print('*',end='\t')
    print()

while嵌套循环

# 用while嵌套循环 打印一个三行四列的矩形
i,j=0,0
while i<3:
    while j<4:
        print('*',end='\t')
        j+=1
    j=0
    i+=1
    print()
    
# 打印一个直角三角形
i,j=1,1
while i<5:
    while j<=i:
        print('*',end='\t')
        j+=1
    i+=1
    j=1
    print()

二重循环中的break和continue

注意:二重循环中的break和continue只影响本层循环 外层循环不受影响

列表

列表相当于数组 LIST 存储的对象的引用 只有在真正使用时才会调用

列表的特点

  • 列表元素按照顺序有序排列
  • 索引映射唯一个数据
  • 列表可以存储重复数据
  • 任意数据类型混存
  • 根据需要动态分配和回收内存

列表的创建与删除

  1. 使用中括号

    lst=['hello','world',98]
    
  2. 调用内置函数list

    lst2=list(['hello','world',98])
    

    列表存储的是列表内每个元素的id,且列表对象是连续完整的,同样我们创建的lst变量存储的是列表对象的id。通过层层的查询才能找到元素的value

  3. 空列表的创建

    lst=[]
    lst1=list()
    

列表的查询操作

  1. 按值查找

    index 根据元素查找对应索引 按照顺序查找 查到便停止遍历 对重复元素不友好

​ 支持区间查找 如果没有该元素会报错

lst=['hello','world',99,'hello']
print(lst.index('hello'))
print(lst.index('hello',1,4)) #[1,4)的位置查询元素hello的索引
  1. 根据索引获取元素 可以正向、逆向索引

    正向是 0N-1 ,逆向是从 -N-1,索引不存在抛出indexError

    lst=['hello','world',99,'hello']
    print(lst[2])
    print(lst[-3])
    

​ 3.获取列表中的多个元素 切片 步长 list[start,stop,step] 获取的其实也是个新的列表 其id不同

lst=['hello','world',99,'hello']
print(lst[1:4:1])
lst2=lst[1:4:1]
print(lst2,id(lst2))
print(lst,id(lst))

​ 当step是负数时,

  • [:stop:step] 切片的第一个元素默认为最后一个元素开始

  • [start::step] 切片的最后一个元素默认为第一个元素开始

    print(lst[1::-1]) #从左第一个 向左边遍历 直到第零个 ['world', 'hello']
    print(lst[:2:-1]) #从右边第一个开始 向右遍历 直到从左边数第二个为止 不包括第二个 ['hello']
    
  1. 判断元素是否存在 in not in

    print( 'hello' in lst) #返回布尔类型 True False
    
    
    
  2. 遍历

    for item in lst:
        print(item,end='\t')
    

列表元素的增加操作

  • append() 在列表的末尾添加一个元素
  • extend() 在列表的末尾至少添加一个元素
  • insert() 在列表的任意位置插入一个元素
  • 切片 在列表的任意位置添加至少一个元素 原列表的元素会右部分被替换

注意:一个元素可以是单元素也可以是一个列表 将列表也视为一个元素

lst=['hello','world',99,'hello']
lst2=lst[1:4:1]
lst.append(88)
print(lst) #['hello', 'world', 99, 'hello', 88] 88作为最后一个元素
lst.append(lst2) # ['hello', 'world', 99, 'hello', 88, ['world', 99, 'hello']] lst2整体作为最后一个元素进入
print(lst)
print(lst[5] ,type(lst[5])) # ['world', 99, 'hello'] <class 'list'> 类型还是list不变

lst.extend(lst2) # ['hello', 'world', 99, 'hello', 88, 'world', 99, 'hello'] lst2不再是一个整体了 作为lst的扩展连上了

lst.insert(1,'yexin') #在第一个位置上插入
print(lst)

lst[1:]=lst2 #将lst2在lst[1:)位置开始插入 同时原列表对应位置上的元素会被替换掉
print(lst)

列表元素的删除操作

  • remove() 一次删除一个元素 删除不存在的会报错 重复元素只删除的第一个

  • pop() 删除一个指定索引位置上的元素 如果不指定就是默认最后一个元素 删除不存在的元素会报错

  • 切片 一次删除不少于一个元素

  • clear() 清除列表

  • del 直接删除列表

    lst=['hello',88,'new','yes']
    
    lst.remove('new')
    
    lst.pop()
    lst.pop(1)
    
    new_lst=lst[1:4]
    print(new_lst)
    
    lst.clear() #[]
    
    # 删除列表
    del lst
    

列表的修改操作

列表是可变序列 支持修改 例如字符串就不是可变序列 不支持修改

  • 为指定索引上的元素赋予一个新值
  • 为指定的切片赋予一个新值
lst=[10,20,30,40]

lst[2]=70
print(lst)

lst[1:3]=[99,22,33,44] #修改了1到3(不包括3)的元素
print(lst)

列表元素的排序

  • 调用sort()方法,默认对列表进行升序排序, sort(reverse=True) 进行降序 原列表发生变化,但不创建新列表
  • 调用内置函数sorted(),同样sorted(reverse=True)进行降序,但原列表不发生变化,创建了新列表
lst=[10,20,55,40,12]
lst.sort()
print(lst) #[10, 12, 20, 40, 55] 升序也就是reverse=False
lst.sort(reverse=True)
print(lst) #[55, 40, 20, 12, 10]

print('-------调用内置函数sorted()---------')
lst2=[31,10.1,44,1]
new_lst=sorted(lst2)
print(new_lst)
new_lst=sorted(new_lst,reverse=True)
print(new_lst)

列表生成式

lst=[i*2 for i in range(1,6)]
print(lst) #[2, 4, 6, 8, 10]

字典

什么是字典

Python中常用的数据结构 具有一一对应的映射关系 也是可变序列 且无序的序列

d = {key1 : value1, key2 : value2 } 花括号 键和值之间用分号连接

注意:key必须是唯一的 用字符串来当 重复使用会替换前者的key value可以重复

字典的原理

哈希函数hash(key) 根据key来分配位置存储value 所以key不能重复 且不可变 因此适用字符串当key

查找也是根据key查找value所在位置

哈希的优点字典就有 缺点同样也是 浪费较大的空间

字典的创建

  • 使用花括号 实参创建

    dict1={'王五':13,'张三':77,'柳六':'缺考'}
    
  • 内置函数dict()创建

    score=dict(name='jack',age=19)
    print(score)
    
  • 创建空字典

    dict2={}
    dict3=dict()
    print(dict2)
    

字典元素的获取

  • 根据key直接获取对应value
print(score['name'])
print(score['name1']) #报错KeyError: 'name1'
  • 调用函数get()获取
print(score.get('name'))
print(score.get('name2')) #查找的键不存在 返回None
print(score.get('name2','没有')) #查找的键不存在 可以自己补充一个默认的值 没有

字典元素的删除

del score['name'] #根据key来删除对应的value 如果没有对应的key 报错KeyError
print(score)

字典的查询操作

  • 判断key是否在字典中 key是字符串 必须要带引号

    if 'name' in score:
        print(score['name'])
        
    b='name' in score
    print(b) #True
    
    print( 'name' not in score) # Flase
    

字典元素的增加

socre['jack']=99 #key必须唯一 不然会替换前者的value

获取字典视图

  • 获取字典所有key 函数keys()

    print(dict1.keys(),type(dict1.keys()))
    # dict_keys(['王五', '张三', '柳六']) <class 'dict_keys'>
    print(list(dict1.keys())) #['王五', '张三', '柳六'] keys可以转化为list输出
    
  • 获取字典所有value 函数values()

    print(dict1.values(),type(dict1.values()))
    # dict_values([90, 77, '缺考']) <class 'dict_values'>
    print(list(dict1.values())) # [90, 77, '缺考'] 同样转化为list输出
    
  • 获取字典所有key value对 函数items()

    list输出会成为元组

    print(dict1.items(),type(dict1.items())) #
    # dict_items([('王五', 90), ('张三', 77), ('柳六', '缺考')]) <class 'dict_items'>
    print(list(dict1.items()))
    # [('王五', 90), ('张三', 77), ('柳六', '缺考')] 输出为元组 <class 'list'>
    # 小括号外面还有方括号的叫做元组
    

字典元素的遍历

for item in dict1:
    print(item,dict1[item],end='\t')
# 获取对应key 然后进行遍历操作

字典生成式

  • 采用内置函数zip() 将可迭代的对象作为参数 (列表)将对象中的元素打包并且输出成新列表

    items=['Fruits','Books','Others']
    prices=[99,12,31]
    lst=zip(items,prices) #zip()函数打包成元组
    print((list(lst)))
    
  • 字典生成器

    item price是自定义变量 从zip()打包的元组中获取数据

d={ item.upper() : price for item , price in zip(items,prices) }
print(d,type(d)) #{'FRUITS': 99, 'BOOKS': 12, 'OTHERS': 31} <class 'dict'>

元组 tuple

什么是元组

t=('Python','hello',90) # 小括号 逗号 元素对象

是Python内置的数据结构之一,是不可变序列

  • 不可变序列有:字符串、元组
    • 没有增删改的操作 修改时一般是创建新的对象地址
  • 可变序列:列表、字典
    • 可以对序列执行增、删、改操作,同时对象地址不发生改变

元组的创建方式

  • 直接小括号

    t=('Python','hello',90)
    print(t)
    
  • 使用内置函数tuple() 注意有两队小括号

    t=tuple(('hello','Python',90))
    
  • 只包含一个元组的元素需要使用逗号和小括号

    t=('hello',) #这是个元组
    t1=('hello') #这是个字符串 需要注意两者的区别
    print(t,t1,type(t),type(t1)) #('hello',) hello <class 'tuple'> <class 'str'>
    
  • 空元组的创建

    t1=()
    t2=tuple()
    print(t1,t2)
    

为什么元组要设计为不可变序列?

  • 在多任务环境下,同时操作对象时不需要加锁
  • 在程序中尽量使用不可变序列
  • 元组中存储的是对象的引用
    • 如果元组中的对象本身是不可变对象,则不能再引用其他对象
    • 如果元组中的对象是可变对象,则可变对象的引用不允许改变,但数据可以改变
t1=('hello','cao',12,[12,31])
print(t1,ype(t1[3])) # <class 'list'>
# t1[3]=100 无法对元组的元素进行修改 TypeError: 'tuple' object does not support item assignment

t1[3].append(100) #t[3]作为可变序列存在 因此可以对元组的可变对象进行修改
print(t1,id(t1[3])) # ('hello', 'cao', 12, [12, 31, 100])

元组的遍历

元组是可迭代对象,所以可以使用for...in进行遍历

因为会有超出元组元素个数的可能 所以使用for....in遍历最为方便

t=tuple(('Python','hello',90))
for item in t:
    print(item)

集合

什么是集合

Python语言提供的内置数据结构

与列表,字典一样属于可变类型的序列

集合是没有value的字典

集合和字典一样根据hash()函数来构造的 所以存储时无序的 同时无法存储重复的元素

集合的创建

  • 直接{}创建

    • s={'Python','hello',90}
      
  • 使用内置函数set()

    • s=set(range(6)) # 整数序列转为集合
      print(s)
      print(set([3,12,43])) # 列表转为集合
      print(set('Python')) # 元组转为集合
      print(set({123,4,4,2,1})) # 字典转为集合 重复的元素会去除 输出元素顺序不同
      print(set(),type(s2)) #空集合 不能使用s={} 系统会识别为空字典
      
      # 顺序时乱的
      # {0, 1, 2, 3, 4, 5}
      # {43, 3, 12}
      # {'y', 'o', 'h', 'n', 'P', 't'}
      # {1, 2, 123, 4}
      # set() <class 'set'>
      

集合元素的判断操作

  • in
  • not in

集合元素的新增操作

  • 调用add()方法,一次添加一个元素
s.add('zhang')
print(s)
  • 调用update()方法至少添加一个元素
s.update({'21','fwff','fwewe'}) # 添加集合
print(s)
s.update([21,31,44,11]) #添加列表
print(s)
s.update(range(4)) # 添加序列
print(s)

s.update({'yexin1':14}) #只存储key value不存储
print(s)

集合元素的删除操作

  • 调用remove()方法,一次删除一个指定元素,如果指定元素不存在 抛出KeyError
s.remove('hello')
print(s)
# KeyError: 'hello11' 不存在的抛出异常
  • 调用discard()方法,一次删除一个指定元素,但指定元素不存在 不会抛出异常
s.discard('yexin1')
print(s) #没有指定的元素 集合内的元素也没有改变
  • 调用pop()方法,一次只删除一个任意元素
s.pop()
print(s) #删除的是任意一个元素 并不会是最后一个
  • 调用clear()方法,清空集合
s.clear()
print(s) #set()

集合的关系

  • 两个集合是否相等

    • 可以使用运算符==或!=进行判断 只要元素内容相同就是相等
    s1={21,31,44,1}
    s2={21,1,44,31}
    print(s1,s2)
    print(s1 == s2)
    print(s1 != s2)
    
  • 一个集合是否是另一个集合的子集

    • 可以调用方法issubset进行判断 子集调用函数 参数是集合
    • B是A的子集
    # B.issubset(A)
    s1={21,31,44,1}
    s3={21,1}
    print(s3.issubset(s1)) #True
    
  • 一个集合是否是另一个集合的超集

    • 可以调用方法isuperset进行判断 调用函数的集合大于被作为参数的集合
    • A是B的超集
    # A.issuperset(B)
    s1={21,31,44,1}
    s3={21,1}
    print(s1.issuperset(s3)) #True
    
  • 两个集合是否没有交集

    • 可以调用方法isdisjoint进行判断 两者都可以调用 结果都一样
    S4={90,11}
    print(S4.isdisjoint(s1)) #True
    print(s1.isdisjoint(S4)) #True
    

集合数学操作

  • 交集 A和B的交 调用函数intersection() 无论谁当参数 返回的结果都是交集集合
# (1) 交集方法1 intersection()
s1={10,20,30,40}
s2={20,30,40,50,60}
print(s1.intersection(s2))
print(s2.intersection(s1))

# (2) 交集方法2 s1 & s2
s4=s3 & s1
print(s4)
print(s1 & s2)
  • 并集 A和B的全部 调用函数union() 无论参数是谁 两者的结果都一样 或者使用 | 操作

    会去除重复的元素

# (2) 并集
print(s1 | s2)
print(s2 | s1)
print(s1.union(s2))
print(s2.union(s1))
# 
  • 差集 A有而B没有的集合 或者 A没有而B有的集合 注意这时候参数发生变化 输出的元素顺序不同
# (3) 差集操作
print(s1.difference(s2)) #{10}
print(s2.difference(s1)) #{50, 60}
# 方法二:s1-s2 获得s1有的而s2没有的
print(s1-s2)
  • 对称差集 对于A没有的B有和对于B没有的A有的集合

    对于函数参数的不同 输出元素的顺序不同 但集合相同 因为集合不看顺序只看结果

s5=s1.difference(s2) | s2.difference(s1) #这是将各自的差集 再并到一起获得集合 不算对称差集 因为结果不同(输出的元素顺序可能不同)
print(s5)

print(s1.symmetric_difference(s2))  #symmertic_difference()
print(s2.symmetric_difference(s1))
print(s1 ^ s2)
print(s2 ^ s1)

集合生成式

公式:s={i for i in range(6)}

与列表生成式类似 列表生成式用的是[] 集合采用{}

由于集合采用的哈希存储方式 因此数据过多时 元素存储的位置时错乱的 输出结果同样没有顺序

# 列表生成式
lst1=[i for i in range(6)]
print(lst1,type(lst1)) #[0, 1, 2, 3, 4, 5] <class 'list'>

# 集合生成式
set1={i for i in range(6)}
print(set1,type(set1)) #{0, 1, 2, 3, 4, 5} <class 'set'>

# 存储元素过多时 输出结果错乱
set2={i*i for i in range(10)}
print(set2) # {0, 1, 64, 4, 36, 9, 16, 49, 81, 25}

数据结构小结

目前学习的有:列表、元组、字典、集合

数据结构 是否可变 是否重复 是否有序 定义字符
列表(list) 可变 可以重复 有序 []
元组(tuple) 不可变 可以重复 有序 ()
字典(dict) 可变 key不能重复 value不能重复 无序 {key:value}
集合 可变 不可重复 无序 {}

字符串

字符串的驻留机制

  • 字符串
    • 基本的数据类型,和元组一样是不可变的字符类型
  • 为什么叫字符串驻留机制呢?
    • 仅保留一份相同且不可变字符串的方法,不同的值会被存放在字符串的驻留池中,Python的驻留机制对相同的字符串只保留一份拷贝,后续创建相同字符串时,不会开辟新的空间,而是把改字符串的地址赋值给新创建的变量
a='Python'
b="Python"
c="""Python"""
print(a,id(a)) #Python 1274270800304
print(b,id(b)) #Python 1274270800304
print(c,id(c)) #Python 1274270800304

驻留机制的几种情况(交互模式)

  • 字符串的长度为0或者1时

    s1=''
    s2=''
    s1 is s2
    True
    s1 == s2
    True
    
  • 符号标识符的字符串

    s1='abc%'
    s2='abc%'
    s1==s2  
    True #内容是相同的
    s1 is s2
    False	#不符合标识符的规范 开辟了新的地址 但是在Pycharm中会优化处理
    >>> id(s1)
    2820976690224
    >>> id(s2)
    2820976690160 #地址不同 没有触发驻留机制
    
  • 字符串只在编译时进行驻留

    a='abc'
    b='ab'+'c'
    c=''.join(['ab','c'])
    print(a,b,c) #abc abc abc 输出结果都是一样的
    a is b #True
    a is c #False 原因是C是在程序运行的时候开辟新空间产生的 而b和a都是在之前
    
  • [-5,256]之间的整数数字

    a=-6
    b=-6
    a is b # False超过的整数范围
    
  • sys中的intern方法强制2个字符串指向同一个对象 不能对整数进行强制

    a='abc%'
    b='abc%'
    a is b #False
    import sys
    a=sys.intern(b)
    a is b # True
    
  • PyCharm对字符串进行了优化处理 需要用IDE自带的编译器编辑 或者终端

字符串驻留机制的优缺点

  • 当需要值相同的字符串时,可以直接从字符串池子李拿来使用,避免频繁的创建和销毁,提升效率和节约内存,因此拼接字符串和修改字符串是会比较影响性能的。

  • 在需要进行字符串拼接时建议使用str类型的join方法,而非+,因为join()方法是先计算出所有字符中的长度,然后再拷贝,只new一次对象,效率要比'+'高

  • join()函数的使用 用于将序列中的元素以指定的字符连接生成一个新的字符串

    print(''.join('ab'+'c')) #以空字符来连接字符'ab' 'c'获得新的字符串
    
    symbol = "-"
    seq = ("a", "b", "c") # 字符串序列
    print(symbol.join( seq ))  # a-b-c
    

字符串的常用操作

查询操作的方法

  • index() 查找子串substr第一次出现的位置,如果查找的子串不存在,抛出ValueError
  • rindex() 查找子串substr最后一次出现的位置,如果查找的子串不存在,抛出ValueError
  • find() 查找子串substr第一次出现的位置,如果查找的子串不存在,返回-1
  • rfind() 查找子串substr第一次出现的位置,如果查找的子串不存在,返回-1

大小写转换操作的方法

注意:字符串是不可变序列 因此大小写转换其实是创建了新的字符串 新的存储空间

  • upper() 把所有字符串中所有字符都转成大写字母
  • lower() 把字符串中所有字符都转成小写字母
  • swapcase() 把字符串所有大写字母转成小写字母,把所有小写字母转成大写字母
  • title() 把每个单词的第一个字符转成大写,把每个单词的剩余字符转成小写
  • istitle() 判断首字符是否大写 true false
s='new'
print(s,id(s)) # new 1311626644656
print(s.upper(),id(s.upper())) # NEW 1311631544816

print(S.lower(),id(S.lower())) # new 2987811391600 转大写后再转小写 不会有驻留机制 仍然存储新空间

字符串内容对齐操作的方法

  • center() 居中对齐,第1个参数指定宽度,第2个参数指定填充符号,第2个参数是可选的,默认是空格,如果设置宽度小于实际宽度则返回原字符串
  • ljust() 左对齐,第1个参数指定宽度,第2个参数指定填充符,第2个参数是可选的,默认是空格如果设置宽度小于实际宽度则返回原字符串
  • rjust() 右对齐,第1个参数指定宽度,第2个参数指定填充符,第2个参数是可选的,默认是空格。如果设置宽度小于实际宽度则返回原字符串
  • zfill() 右对齐,左边用0填充,该方法只接受一个参数,用于指定字符串的宽度,如果指定的宽度小于等于字符串的长度,返回字符串本身
str1='helloPython'
print(str1.center(20,'*'))
print(str1.center(20))
print(str1.center(10))

print('--------左对齐----------')
print(str1.ljust(20,'*'))
print(str1.ljust(20))
print(str1.ljust(10))


print('--------右对齐----------')
print(str1.rjust(20,'*'))
print(str1.rjust(20))
print(str1.rjust(10))
print('-1392'.rjust(20,'0'))  #000000000000000-1392


print('--------右对齐,0填充----------')
print(str1.zfill(20))
print(str1.zfill(10))
print('93021'.zfill(20))
print('-1392'.zfill(20))   #-0000000000000001392

注意两个注释,zfill()函数用0填充,对于负数是保留了负数字符串的含义 但rjust()则是以字符串的形式严格执行 会将0填充在负号前面

字符串劈分操作得到方法

  • split()

    • 从字符串的左边开始劈分,默认的劈分符号是空格字符串,返回的值都是一个列表
    • 以通过参数sep指定劈分字符串是劈分符
    • 通过参数maxsplit指定劈分字符串时的最大劈分次数,在经历最大次劈分之后,剩余的子串会的单独作为一部分
    s='hello|worldPython'
    print(s,id(s))
    print(s.split('|'),id(s.split('|')),type(s.split('|')))
    # hello|worldPython 2774456863200
    # ['hello', 'worldPython'] 2774456144384 <class 'list'>
    

    分割后转化为列表了 分割符会消失

  • rsplit()

    • 从字符串的右边开始劈分,默认的劈分符号是空格字符串,返回的值都是一个列表
    • 以通过参数sep指定劈分字符串是劈分符
    • 通过参数maxsplit指定劈分字符串时的最大劈分次数,在经历最大次劈分之后,剩余的子串会的单独作为一部分
    s='hello|world|Python'
    print(s,id(s))
    lst=s.rsplit('|',maxsplit=1)
    print(lst)
    
    s='helloworldPython'
    print(s.rsplit('o'))
    
    # hello|world|Python 2497213434416
    # ['hello|world', 'Python']
    # ['hell', 'w', 'rldPyth', 'n']
    

    右侧开始分割 但是输出顺序不变

判断字符串的操作方法

方法名称 作用
isidentifier() 判断指定的字符串是不是合法的标识符
isspace() 判断指定的字符串是否全部由空白字符组成(回车\r、换行\n,水平制表符\t等)
isalpha() 判断指定的字符串是否全部由字母组成
isdecimal() 判断指定字符串是否全部由十进制的数字组成
isnumeric() 判断指定的字符串是否全部由数字组成
isalnum() 判断指定字符串是否全部由字母和数字组成

字符串操作的其他方法

功能 方法名称 作用
字符串替换 replace() 第一个参数指定被替换的子串,第2个参数指定替换该子串的字符串,该方法返回替换后得到的字符串,替换前的字符串不发生变化,调用该方法时可以通过第3个参数指定最大替换次数
字符串的合并 join() 将列表或元组中的字符串合并成一个字符串 列表或者元组作为参数(单个字符串也可以视为字符序列)连接符作为调用函数的参数 可以是空格
s='hello|world|python'
print(s.replace('o','*****',2))

lst1=s.split('|')
print(lst1,id(lst1))
print(lst1[1].join(lst1[1]))

# 列表 [] 元组()  字典{key:value} 集合{}

t=('hello','world','python')
print('+'.join(t),type('+'.join(t)))  #注意join()函数的参数是被连接的字符组合 列表或者元组

print('|'.join(lst1),type('|'.join((lst1))))

print('*'.join('Python')) #P*y*t*h*o*n 将字符串python视为序列进行连接

字符串的比较操作

  • 运算符:> , >= , < , <= , == , !=
  • 比较规则:首先比较两个字符串中的第一个字符,如果相等则继续比较下一个字符,依次比较下去,直到两个字符串中的字符不相等时,其比较结果就是两个字符串的比较结果,两个字符串中的所有后续字符将不再被比较
    • 返回的是boolen类型
  • 比较原理:两上字符比较时,比较的是其ordinal value(原始值),调用内置函数ord可以得到指定字符的ordinal value。 与内置函数ord对应的是内置函数chr,调用内置函数chr时指定ordinal value 可以得到其对应的字符
    • ord() 参数为string chr()参数是int
print('a' > 'A')  #True
print(ord('a'))   #97
print(chr(97))    #a
print(chr(ord('a'))) #a

字符串的切片操作

  • 字符串是不可变类型
    • 不具备增删改等操作
    • 切片操作将产生新的对象
  • 公式: s[start:stop:step] 和序列操作一样
# 字符串切片
s='helloPython'
print(s,id(s))
print(s[:5],id(s[:5]))
print(s[:5:-1])
print(s[:-6:1])
print(s[5::1])

格式化字符串

  • 两种方式

    • %作占位符(以前的c或者c++里的)

      • 公式 print('%d' & 99) 必须要有 %d & 99
      • %s 字符串
      • %d 整数 %3d表示宽度为3 三个字符的位置
      • %f 浮点 %.3f表示保留后三位小数
      # (1) % 占位符
      name='张三'
      age=10
      print('我是%s,今年%d岁' % (name,age))
      
      print('%.3f % 3.115926')
      
    • {}作占位符

      • {}里用数字
      # (2) {}
      print('我叫{0},今年{1}岁'.format(name,age)) #是字符串调用format()
      
      print('{0:.3}'.format(3.1415926)) #表示保留三位数
      print('{0:.3f}'.format(3.1415926)) #表示保留三位小数
      print('{0:3.3f}'.format(3.1415926)) #表示宽度是3 同时保留三位小数
      
      • f-string {}里用的变量要被实参化
      print(f'我叫{name},今年{age}岁') #注意要加f 不然name age不能做变量来调用
      

字符串的编码

  • 编码与解码的方式
    • 编码:将字符串转换为二进制数据(bytes)
    • 解码:将bytes类型的数据转换成字符串类型

函数

应给函数指定描述性名称,且只在其中使用小写字母和下 划线。描述性名称可帮助你和别人明白代码想要做什么。给模块命名时也应遵循上述约定.

函数的创建和调用

  • 为什么需要函数

    • 复用代码
    • 隐藏实现细节
    • 实现可维护性
    • 提高可读性便于调用
  • 函数的创建

    关键字def来告诉Python你要定义一个函数

    def 函数名 ([输入参数]):
        函数体
        [return xxx]
    
    
    def display_message(username):
        print(username + '在本章学的是函数!')
        
    display_message('yexin')
    // yexin在本章学的是函数!
    

函数的参数传递

  • 位置实参

    函数定义和函数使用上的变量一一对应

  • 关键字实参

    根据形参名进行实参传递 函数使用时指定变量

    指定传递的变量必须放在最后面 无论是函数定义还是调用

    在使用默认值时,在形参列表中必须先列出没有默认值的形参,再列出有默认值的实参

    def calc1(a,b):
        return a+b
    
    
    def calc2(a,b=2):
        return a+b
    
    def calc2(a=1,b=2): //默认值设定
        return a+b
    
    
    print(calc2(1,2)) //虽然形参实例了但是不影响实参传递
    print(calc2(a=1,b=2)) //关键字传递不关心a、b位置
    print(calc3(3,b=1)) // 指定传递的变量必须放在最后面
    

函数的返回值

函数在定义时,是否需要返回值,视情况而定

  • 函数返回多个值时,结果为元组
def others():
    return 12,31
print(others(),type(others()))
//(12, 31) <class 'tuple'> 元组类型
  • 函数的返回值,如果是1个,直接返回类型
  • 函数如果没有返回值(函数执行完毕后,不需要给调用处提供数据) return可以省略不写
"""返回整洁的姓名"""
def get_formatted_name(first_name, middle_name, last_name):
    full_name = first_name+' '+middle_name+' '+last_name
    return full_name.title()

musician = get_formatted_name('john', 'lee', 'hooker')
print(musician)

返回字典

def get_formatted_name(first_name,last_name):
    '''返回一个字典 包含名和姓'''
    return {'first':first_name,'last':last_name}
print(get_formatted_name('Jon','Snow'))
//{'first': 'Jon', 'last': 'Snow'}

函数的参数定义

参数的类型 函数的定义 函数的调用 备注
位置实参
将序列中的每个元素都转换为位置实参 使用*
关键字实参
将字典中的每个键值对都转换为关键字实参 使用**
默认值形参
关键字形参 使用*
个数可变的位置形参 使用*
个数可变的关键字形参 使用**
def fun1(a,b,c):
    print('a= ',a,type(a))
    print('b= ',b)
    print('c= ',c,type(c))
lst1=[1,2,3]
lst2=[4,5,6]
dict1 = {'a':1,'b':6,'c':3}
fun1(*lst1) #序列中的每个元素都转换为位置实参
fun1(lst1,b=1,c=2) #序列作为一个整体传入
fun1(**dict1) #字典中的每个键值对都转换为关键字实参
fun1(*dict1) #字典中的每个键值都转换为关键字实参


def fun2(*args):
	print(args)
    # 位置传递 返回序列
    
def fun3(**args2):
	print(args2)
	# 关键字传递,返回字典
def fun3(a,b,*,c,d): # 要求c、d只能是关键字传递
	print('a= ',a)
    print('b= ',b)
	print('c= ',c)
    print('d= ',d)

函数定义时的形参的顺序问题

def funn1(*args1,**args2):
    pass
def funn2(a,b,*,c,d,**arfs):
    pass
def fun3(a,b,*c,d,**arfs):
    pass

代码示例

def get_formatted_name(first_name,last_name,middle_name=''):
    '''判断middle_name不为空表示true'''
    if middle_name:
        full_name = first_name + ' ' + middle_name + ' ' + last_name
    else:
        full_name = first_name+' '+last_name
    return full_name.title()
musician = get_formatted_name('John','Hello')
print(musician)
musician = get_formatted_name('John','Hello','Snow')
print(musician)

/**
根据这三部分创建一个字符串, 在适当的地方加上空格,并将结果转换为首字母大写格式
对函数进行重构 无论是否有中间名都能能使用 有默认值的必须放在最后面
*/

参数是列表

列表包含的可能是名字、数字或更复杂的对象(如字典)

使用函数来提高处理列表的效率

在函数中对列表所做的任何修改都是永久性的

但如果禁止函数修改原列表的话 切片表示法[:]创建列表的副本 不影响原先的列表

function_name(list_name[:]) //函数调用的书写规范 函数声明中不需要

参数个数可变的位置形参

  • 定义函数时,可能无法事先确定传递的行参数的个数,使用可变的位置参数
  • 使用*定义个数可变的位置形参
  • 结果为一个元组
  • 可数可变的位置形参只能是一个
def fun1(*args):
    print(args,type(args))

fun1(10,21,33)
// (10, 21, 33) <class 'tuple'>

参数个数可变的关键字形参

​ 关键字指的是指定了的 函数的返回值中有讲解

  • 定义函数时,无法事先确定传递的关键字实参的个数,使用可变的关键字形参
  • 使用**定义个数可变的关键字形参
  • 结果为一个字典
  • 可数可变的关键字形参只能是一个
def fun2(**args):
    print(args,type(args))

fun2(a=12,b=21,c=33)
// {'a': 12, 'b': 21, 'c': 33} <class 'dict'>

如果既有可变形参,也有可变关键字形参,那么要求可变的位置形参在可变的关键字形参前

变量的作用域

  • 程序代码能访问该变量的区域
  • 根据变量的有效范围可分为
    • 局部变量
      • 函数内定义使用的变量,只在函数内部有效,局部变量使用global声明,这个变量就会成为全局变量
    • 全局变量
      • 函数体外定义的变量。可作用于函数内外
def fun(a,b):
    c=a+b
    print(c)
    
def fun2(a,b):
    global d #定义全局变量
    d=a+b
    print(d)
    
fun(1,2)

fun2(1,2)
print(d)

递归函数

  • 组成部分
    • 递归调用与递归终止条件
  • 调用过程
    • 每递归调用一次函数,都会在栈内存分配一个栈帧
    • 每执行完一次函数,都会释放相应的空间
  • 优缺点
    • 占用内存多,效率低下
    • 思路和代码简单

使用递归来计算阶乘

def fun(a):
    if a-1:
        return fun(a-1)*a
    else:
        return 1

print(fun(3))
print(fun(6))

使用递归来做费波那契数列

def fun(a):
    if a==1 or a==2:
        return 1
    else:
        return fun(a-1)+fun(a-2)

# 获取i个数的费波那契数列
lst1=[]
for i in range(1,5):
    lst1.append(fun(i))
    print(fun(i))

Python的异常处理机制

  • Python提供了异常处理机制,可以在异常出现时即时捕获,然后内部“消化“,让程序继续执行

try ... except ... 结构

try:
	n1 = int(input('请输入一个整数:'))
	n2 = int(input('请输入另一个整数:'))
	result = n1/n2
except ZeroDivisionError: # 捕获的异常 如果出现n2为0会跳出并且不中断
    print('除数不允许为零')
except ValueError:
    print('输入数字串')
print('程序结束')
except BaseException as e
	print(e)
# except 捕获的错误例如ValueError ZeroDivisionError 都是终端中获得的 不是自己编写的

捕获异常的顺序按照先子类后父类的顺序,为了避免遗漏可能出现的异常,可以在最后增加BaseException

try ... except ... else结构

如果没有出现异常 就执行else

try:
	n1 = int(input('请输入一个整数:'))
	n2 = int(input('请输入另一个整数:'))
	result = n1/n2
except ZeroDivisionError:
    print('除数不允许为零')
except ValueError:
    print('输入数字串')
# 如果没有出现异常 就执行else
else:
	print('结果为:',result)
print('程序结束')

try ... except ... else ... finally结构

finally 块无论是否发生异常都会被执行,常能用来释放try块中申请的资源

try:
	n1 = int(input('请输入一个整数:'))
	n2 = int(input('请输入另一个整数:'))
	result = n1/n2
except ZeroDivisionError:
    print('除数不允许为零')
except ValueError:
    print('输入数字串')
# 如果没有出现异常 就执行else
else:
	print('结果为:',result)
finally:
	print("程序无论异常与否,总会被执行")
print('程序结束')

Python常见的异常类型

序号 异常类型 描述
1 ZeroDivisionError 除(或取模)零(所有数据类型)
2 IndexError 序列中没有此索引(index)
3 KeyError 映射中没有这个键
4 NameError 未声明/初始化对象(没有属性)
5 SyntaxError Python语法错误
6 ValueError 传入无效的参数

trackback模块

  • 使用trackback模块打印异常信息
import trackback
try:
    print('1.----------------')
    num=10/0
except:
    trackback.print_exc()

编程思想

面向对象

面向过程

类和对象的创建

Python中万物皆为对象 类其实是类对象 对象是类对象的实例 叫做实例对象

    • 数据类型

      • 不同的数据类型属于不同的类
      • 使用内置函数查看数据类型
      print(type(100))
      
    • 创建类的语法

      class Student: #Student为类名 由一个或多个单词组成,首字母大写
          pass
      
    • 类的组成

      • 类属性

        • 类中方法外的变量称为类属性,被该类的所有对象所共享(包括类对象)

        • 任何对象或是类对象都可以调用或者修改类属性

          print(Student.native_place) #访问类属性
          Student.native_place='北京'
          print(stud1.native_place)   #北京
          
      • 实例方法

        • 类内部定义的函数才称作方法
        • 实例方法需要有实例对象才能调用
      • 静态方法

        • 使用@classmethod修饰的方法,使用类名直接访问的方法

          Student.sm() #调用类方法
          
      • 类方法

        • 使用@classmethod修饰的方法,使用类名直接访问的方法

          Student.cm() #调用静态方法
          
      class Student:  #Student为类名 由一个或多个单词组成,首字母大写
          native_place='江西' #直接写在类里的变量,称为类属性
          
          #初始化方法 必须构造
          def __int__(self,name,age): # name age是实例属性
              self.name = name # 赋值操作 self.name称为实例属性
              self.age = age
              
          # 实例方法 在类之内定义的称为方法 类之外的成为函数
          def info(self):
              print('我的名字叫:',self.name,'年龄是:',self.age)
              
          # 类方法
          @classmethod
          def cm(cls): #要求传递一个cls
              print('我使用了classmethod进行修饰,所以我是类方法')
              
          #静态方法
          @staticmethod
          def sm(): #不允许写self 这是规定
              print('我使用了staticmethod进行修饰,所以我是静态方法')
              
      
  • 对象

    • 100,99都是int类之下包含的相似的不同个例,个例的专业术语称为实例或对象

    • 对象的创建又称为类的实例化

    • 语法:

      • 实例名=类名()
      # 对象名.方法名() 传统的方法调用方式,先实例化,再通过对象调用方法
      print('-------------------------------')
      Student.eat(stud1)
      Student.info(stud1)
      stud=Student('Jack',20)
      print(stud.name) #实例属性
      print(stud.age)  #实例属性
      stud.info()		 #实例方法
      
      
      # 类名.方法名(实例对象) ---> 实际上就是方法定义处的self 这是新的方法调用方式
      print('-------------------------------')
      Student.eat(stud1) 
      Student.info(stud1)
      
      
      # 创建Student类的对象
      stud1 = Student('张三',20)
      print(id(stud1)) #检查是否开启内存空间
      print(type(stud1)) #stud1的值
      print(stud1)
      print('-------------------------------')
      print(id(Student))  #Student是类的名称 Student是类对象,stud1是实例对象 Python皆可对象
      print(type(Student))
      print(Student)
      
    • 意义:有了实例,就可以调用类中的内容

动态绑定属性和方法

  • Python是动态语言,在创建对象之后,可以动态地绑定属性和方法

    只适用于当前绑定的对象 其他对象无法调用

    def show():
        print('定义在类之外的称为函数')
    
    stu= c10demo1.Student('Jack',20)
    stu.gender='男' #动态绑定性别
    print(stu.name,stu.age,stu.gender)
    stu.show=show #动态绑定方法
    stu.show()
    

面向对象的三大特征

封装

  • 提高程序的安全性

    • 将数据(属性)和行为(方法)包装到类对象中。在方法内部对属性进行操作,在类对象的外部调用方法。这样,无需关心内部的具体实现细节,从而隔离了复杂度。
    • 在Python中没有专门的修饰符用于属性的私有,如果该属性不希望在类对象外部被访问,前边使用两个"_"
    class Student:
        def __init__(self,name,age):
            self.name=name
            self.__age=age #不希望age在外部被调用或查看
        def show(self):
            print(self.name,self.__age) #可以在内部使用
            
    # print(stud1.age) 报错找不到age属性
    
    # 非得访问用以下方法 但既然都不希望被访问就不要访问了
    print(dir(stud1)) #查找stud1内的函数和属性 找到_Student__age
    print(stud1._Student__age) #以另一种方式获取到了age 
    

继承

  • 提高代码的复用性

  • 语法格式

    • class 子类类名(父类1,父类2....):
          pass
      
  • 如果一个类没有继承任何类,则默认基础object

  • Python支持多继承 使用super()需要注意

    # 多继承
    class A(object):
        def __init__(self,age):
            self.age=age
    
    class B(object):
        def __init__(self,name):
            self.name=name
    class C(A,B):
        def __init__(self,age,name,score):
            #要想调用特定父类的构造器可以使用父类名.__init__方式。多继承使用super,会有一个坑
            A.__init__(self,age) 
            B.__init__(self,name)
            self.score=score
    
    c=C(11,'ee',90)
    print(c.name,c.age,c.score)
    
  • 定义子类时,必须在其构造函数中调用父类的构造函数 俗称实例化父类

    # 定义父类 不继承任何类 带object 也可以不写 最好还是写 以便区分父类
    class Person(object):
        def __init__(self,age,name):
            self.name=name
            self.__age=age
        def show(self):
            print(self.name,'同学请来办公室一趟,恭喜你',self.__age,'岁了!')
    
    # 创建子类 括号内写父类 调用父类方法用super()
    class Student(Person):
        def __init__(self,name,age,score):
            super().__init__(name,age) #通过super()调用父类方法 
            self.score=score
    
            
    stud1=Student(18,'Jack',100)
    stud1.show()
    print(stud1.score)
    

方法重写

  • 如果子类对继承自父类的某个属性或者方法不满意,可以在子类中对其(方法体)进行重新编写

  • 子类重写后的方法中可以通过super().xxx()调用父类中被重写的方法

    class Person(object):
        
        def __init__(self,name,age):
            self.name = name
            self.age = age
            
        def info(self):
            print('{0},的年龄是{1}'.format(self.name,self.age))
            
    class Student(Person):
        
        def __init__(self,name,age,score):
            Person.__init__(self,name,age)
            self.score=score
            
        def info(self):
            # Person.info(self) 两个方法都能用
            super().info()
            print(self.name,'的成绩是',self.score)
    
    stud1=Student('yexin',18,99)
    stud1.info()
    

object类

  • object类是所有类的父类,因此所有类都有object类的属性和方法

  • 内置函数dir()可以查看指定对象所有属性

    o=object()
    p=Person('Jack',20)
    print(dir(o)) 
    print(dir(p)) 
    
  • object有一个_str_()方法,用于返回(return)一个对于“对象的描述”,对应于内置函数str()经常用于print()方法,帮我们查看对象的信息,所以我们经常会对_str_()重写

    class Person(object):
        def __init__(self,name,age):
            self.name = name
            self.age = age
        def __str__(self):
            return '{0}的年龄是{1}'.format(self.name,self.age) #return返回信息
    
    o = object()
    p = Person('Jack',20)
    print(p) #重写__str__()函数 可以直接print(p)对象信息
    print(p.__str__()) # 也可以对象调用
    
    print(dir(o) == dir(object))
    print(dir(p))
    print(dir(Person))
    print(dir(p) == dir(Person))
    print(dir(p) is dir(Person))
    

多态

  • 提高程序的可扩展性

  • 具有多种形态 即便不知道一个变量所引用的对象到底是什么类型,仍然可以通过这个变量调用方法,在运行过程中根据变量所引用对象的类型,动态决定调用哪个对象中的方法

    # 多态
    
    class Animal(object):
        def eat(self):
            print('Animal会吃')
    
    class Cat(Animal):
        def eat(self):
            print('Cat会吃鱼')
    
    class Dog(Animal):
        def eat(self):
            print('Dog吃骨头')
    
    class Person():
        def eat(self):
            print('人吃五谷杂粮')
    
    def fun(obj):
        obj.eat()
    
    fun(Dog())
    fun(Cat())
    fun(Animal())
    fun(Person()) #即使Person没有继承Animal 只要Person里有eat()方法就会动态调用
    

静态语言与动态语言

  • 静态语言和动态语言关于多态的区别
    • 静态语言实现多态的三个必要条件
      • 继承
      • 方法重写
      • 父类引用指向子类对象
  • 多态语言的多态崇尚“鸭子类型”当看到一只鸟走起来像鸭子、游泳起来像鸭子、收起来也像鸭子,那么这只鸟就可以被称为鸭子。在鸭子类型中,不需要关心对象是什么类型,到底是不是鸭子,只关心对象的行为(即方法)

特殊方法和特殊属性

  • 特殊属性

    • __dict__ 获得类对象或实例对象所绑定的所有属性和方法的字典

    • __class__ 输出对象所属的类

    • __base__ 输出对象类型继承的第一个父类类型

    • __bases__ 输出对象类型继承的所有父类类型

    • __mro__ 输出对象类型继承的层次结构

      # 特殊属性
      
      class Person(object):
          def __init__(self,name,age):
              self.name = name
              self.age = age
      
      class Animal(object):
          pass
      
      class Student(Person,Animal):
          def __init__(self,name,age,score):
              super().__init__(name,age)
              self.score = score
      
      stud1 = Student('yexin',12,100)
      print(stud1.__class__) # <class '__main__.Student'>
      print(stud1.__dict__) # {'name': 'yexin', 'age': 12, 'score': 100}
      print(Student.__dict__)  
      print(Student.__mro__) # (<class '__main__.Student'>, <class '__main__.Person'>, <class '__main__.Animal'>, <class 'object'>)
      print(Student.__base__) # <class '__main__.Person'>
      print(Student.__bases__) # (<class '__main__.Person'>, <class '__main__.Animal'>)
      
  • 特殊方法

    • __len__()通过重写该方法,让内置函数len()的参数可以是自定义类型

      class Person(object):
          def __init__(self,name):
              self.name = name
          def __add__(self, other):
              return self.name+other.name #还可以是别的属性相加 只要是return就行
          def __len__(self):
              return len(self.name)   #重写让对象类拥有len方法,并且参数自定义
              
      lst=[21,33,11,41,55]
      print(len(lst))
      print(len(a))
      print(len(a.__add__(b)))
      
    • __add__()通过重写该方法,可使用自定义对象具有”+”功能

      class Person(object):
          def __init__(self,name):
              self.name = name
          def __add__(self, other):
              return self.name+other.name #还可以是别的属性相加 只要是return就行
      
      a=Person('王权')
      b=Person('富贵')
      c=a+b
      print(c)
      
      print(a.__add__(b)) #使用方式
      

    • __new__()通过创建对象

    • __init__()对创建的对象进行初始化

      class Person(object):
          def __new__(cls, *args, **kwargs):
              print('__new__被调用了,cls的id值是{0}'.format(id(cls)))
              obj = super().__new__(cls)
              print('创建的对象的id为:{0}'.format(id(obj)))
              return obj
      
          def __init__(self,name,age):
              print('__init__被调用了,self的id为{0}'.format(id(self)))
              self.name = name
              self.age = age
              
      p1 = Person('Jack',19)
      print('Object这个类的id是{0}'.format(id(object)))
      print('Person这个类的id是{0}'.format(id(Person)))
      print('创建的实体对象的id是{0}'.format(id(p1)))
      
      
      
      # __new__被调用了,cls的id值是1989172968160
      # 创建的对象的id为:1989172624928
      # __init__被调用了,self的id为1989172624928
      # Object这个类的id是140724810562384
      # Person这个类的id是1989172968160
      # 创建的实体对象的id是1989172624928
      

      从new开始创建了对象,然后对象传递到初始化方法内,初始化结束返回到实体对象中去

类的浅拷贝与深拷贝

  • 变量的赋值操作

    • 只是形成两个变量,实际上还是指向同一个对象
    class CPU:
        pass
    class Disk:
        pass
    class Computer:
        def __init__(self,cpu,disk):
            self.cpu=cpu
            self.disk=disk
    
    #(1) 变量的赋值
    cpu1=CPU()
    cpu2=cpu1  # 直接将对象赋值 不需要先创建新对象再赋值 真简单 指向的作用
    print(cpu1,id(cpu1))
    print(cpu2,id(cpu2))
    
  • 浅拷贝

    • Python拷贝一般都是浅拷贝,对象包含的子对象内容不拷贝,源对象与拷贝对象会引用同一个子对象
    class CPU:
        pass
    class Disk:
        pass
    class Computer:
        def __init__(self,cpu,disk):
            self.cpu=cpu
            self.disk=disk
    
    
    #(2) 浅拷贝
    print('-----------------')
    cpu1=CPU()
    disk=Disk()
    computer=Computer(cpu1,disk)
    import copy
    computer2=copy.copy(computer)
    print(computer,computer.cpu,computer.disk)
    print(computer2,computer2.cpu,computer2.disk)
    # computer与computer2地址不同,但其子对象的内容一样,采用引用的方法
    
  • 深拷贝

    • 使用copy模块的deepcopy函数,递归拷贝对象中包含的子对象,源对象和拷贝对象所有的子对象也不相同
    class CPU:
        pass
    class Disk:
        pass
    class Computer:
        def __init__(self,cpu,disk):
            self.cpu=cpu
            self.disk=disk
    #(3)深拷贝
    print('---------------------------')
    disk=Disk()
    cpu1=CPU()
    computer=Computer(cpu1,disk)
    computer3=copy.deepcopy(computer)
    print(computer,computer.cpu,computer.disk)
    print(computer3,computer3.cpu,computer3.disk)
    # computer与computer3及其子对象的存储地址都不相同
    

模块

  • 函数与模块的关系
    • 一个模块中可以包含N多个函数
  • 在Python中一个扩展名为.py文件就是一个模块
  • 使用模块的好处
    • 方便其他程序的脚本的导入并使用
    • 避免函数名和变量名冲突
    • 提高代码的可维护性
    • 提高代码的可重用性

自定义模块

  • 创建模块

    • 新建一个.py文件,名称尽量不要与Python自带的标准模块名称相同
  • 导入模块

    import 模块名称 [as 别名] #导入该模块的所有内容
    
    from 模块名称 import 函数/变量/类 #导入该模块的指定内容
    
    # from math import pi
    import math
    print(math.pi) #需要通过模块.内容来使用
    print(pow(2,3))
    print(math.pow(2,3))
    
    # 导入自定义模块
    from c11demo2 import Person
    
    
    

以主程序形式运行

  • 在每个模块的定义中都包括一个记录模块名称的变量_name_,程序可以检查该变量,以确定他们在哪个模块中执行。如果一个模块不是被导入到其他程序中执行,那么它可能在解释器的顶级模块中执行。顶级模块的_name_变量的值为_main_

    if _name_ = ='_main_':
        pass
    

    模块中(.py文件中)只会执行pass的内容 其他内容不执行

    import c11demo2
    p1 = c11demo2.Person('yexin')
    p1.get_name()
    
    
    class Person():
        def __init__(self,name):
            self.name=name
        def get_name(self):
            print('你好',self.name)
    
    # 只会在这里执行 被导入到其他文件但不会执行以下内容
    if __name__ == '__main__':
        print('这是c11demo2文件,欢迎导入')
        
    

Python中的包(package)

  • 包是一个分层次的目录结构,它将一组功能相近的模块在一个目录下

  • 作用

    • 代码规范
    • 避免模块名称冲突
  • 包与目录的区别

    • 目录是directory
    • 包含_init_.py文件的目录称为包
    • 目录里通常不包含_init_.py文件
  • 包的导入

    import 包名.模块名 
    import package1.module1
    # 使用import方式进行导入时,只能跟进包名或者模块名
    
    from package1.module1 import a
    

Python中常用的内置模块

模块名 描述
sys 与Python解释器及其环境操作相关的标准库
time 提供与时间相关的各种函数的标准库
os 提供了访问操作系统服务功能的标准库
calendar 提供与日期相关的各种函数的标准库
urlib 用于读取来之网上(服务器)的数据标准库 爬虫使用的到
json 用于使用JSON序列化和反序列化对象
re 用于在字符串中执行正则表达式匹配和替换
math 提供标准算术运算函数的标准库
decimal 用于进行精准控制运算精度、有效数位和四舍五入操作的十进制运算
logging 提供了灵活的记录事件、错误、警告和调试信息等目录信息的功能
import sys
print(sys.getsizeof(24))
print(sys.getsizeof(True))

import time
print(time.time())
print(time.localtime(time.time()))

import urllib.request
print(urllib.request.urlopen('http://www.baidu,com').read())

第三方模块的安装及使用

  • 第三方模块的安装

    • pip install 模块名

      image-20221013165211911

      没有报错说明导入成功 可以在编译器中导入使用或者直接终端编译

  • 第三方模块的使用

    • import 模块名

      import schedule
      import time
      def job():
          print('做核酸了!!!')
      
      # 每隔三秒做一件事 休眠一秒
      schedule.every(2).seconds.do(job)
      while True:
          schedule.run_pending()
          time.sleep(1)
      

编码格式的介绍

  • 常见的字符编码格式
    • Python的解释器使用的是Unicode(内存)
    • .py文件在磁盘上使用UTF-8存储(外存)

文件的读写原理

  • 文件的读写俗称“IO操作”

  • 文件读写操作流程

  • 操作原理

    python操作文件------------->打开或新建文件------------->读、写文件------------->关闭资源

文件读写操作

文件的类型

  • 按文件中数据的组织形式,文件分为以下两大类
    • 文本文件:存储的是普通“字符”文本,默认为unicode字符集,可以使用记事本程序打开
    • 二进制文件:把数据内容用“字节”进行存储,无法用记事本打开,必须使用专用的软件打开,举例:mp3音频文件,jpg图片,doc文档等
打开模式 描述
r 以只读模式打开文件,文件的指针将会放在文件的开头
w 以只写模式打开文件,如果文件不存在则创建,如果文件存在,则覆盖原有内容,文件指针在文件开头
a 以追加模式打开文件,如果文件不存在则创建,文件指针在文件开头,如果文件存在,则文件末尾追加内容,文件指针在源文件末尾
b 以二进制方式打开文件,不能单独作用,需要与共它模式一起使用,rb,或者wb
+ 以读写方式打开文件,不能单独使用,需要它与其他模式一起使用,a+

通常使用rbwb

open('logo.png','rb') #读取模式打开文件

文件对象的常用方法

  • read([size])
    • 从文件中读取size个字节或字符的内容返回。若省略[size],则读取到文件末尾,即一次读取文件所有内容
  • readline()
    • 从文本读取中读取一行内容
  • readlines()
    • 把文本文件中每一行都作为单独的字符串对象,并将这些对象放入列表返回
  • wirte(str)
    • 将字符串str内容写入文件
  • writelines(s_list)
    • 将字符串列表s_list写入文本文件,不添加换行符
  • seek(offset[,where])
    • 将文本指针移动到新的位置,offset表示相对where的位置:
      • offset:为正往结束方向移动,为负往开始方向移动
      • where不同的值代表不同含义:
        • 0:从文件头开始计算(默认值)
        • 1:从当前位置开始计算
        • 2:从文件尾开始计算
  • tell()
    • 返回文件指针的当前位置
  • flush()
    • 把缓冲区的内容写入文件,但不关闭文件
  • close()
    • 把缓冲区的内容写入文件,同时关闭文件,释放文件对象相关资源

with语句(上下文管理器)

  • with语句可以自动管理上下文资源,无论什么原因跳出with块,都能确保文件正确的关闭,以此来达到释放资源的目的

  • 不用手动关闭资源

    with open('logo.png','rb') as src_file:
        src_file.read()
    

    离开运行时上下文,自动调用上下文管理器的特殊方法_exit_()

    class MyContentMgr(object):
        def __enter__(self):
            print('enter方法被调用了')
            return self
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            print('exit方法被调用执行了')
    
        def show(self):
            print('show方法被调用执行了')
    
    with MyContentMgr() as file: #相当于file=MyContentMgr()
        file.show()
    

目录操作

  • os模块是Python内置的与操作系统功能和文件系统相关的模块,该模块中的语句的执行结果通常与操作系统有关,在不同的操作系统上运行,得到的结果可能不一致。

  • os模块与os.path模块用于对目录或文件进行操作

    # os模块与操作系统相关的一个模块
    
    import os
    os.system('calc.exe')
    
    # 直接调用可执行文件
    os.startfile('D:\\Program Files\\CloudMusic\\cloudmusic.exe')
    
    函数 说明
    getcd() 返回当前的工作目录,返回str
    listdir(path) 返回指定路径下的文件和目录信息(返回list列表)
    mkdir(path[,mode]) 创建目录,不是包
    makedirs(path1/path2...[,mode]) 创建多级目录
    rmdir(path) 删除目录 精确到要删除的目录下才能删除
    removedirs(path1/path2......) 删除多级目录 必须把多级目录的每个文件都写出来
    chdir(path) 将path设置为当前工作目录 修改当前的工作目录
    import os
    
    print(os.getcd())
    
    print(os.listdir('../chap11'))
    
    os.makedirs('../chap11/package2/package3/package4')
    
    os.rmdir('package2') #目录不是空的
    
    os.rmdir('../chap11/package2/package3/package4') #精确到要删除的目录下才能删除
    
    os.removedirs('../chap11/package2/package3') #必须把多级目录的每个文件都写出来
    
    print(os.getcd())
    os.chdir('../chap10') #前后两次工作目录不同
    print(os.getcwd())
    
  • os.path模块操作目录相关函数

    函数 说明
    abspath(path) 用于获取文件或目录的绝对路径
    exists(path) 用于判断文件或目录是否存在,如果存在返回True,否则返回False
    join(path,name) 将目录与目录或者文件名拼接起来
    splitext() 分离为文件名和扩展名
    basename(path) 从一个目录提取文件名
    dirname(path) 从一个路径中提取文件路径,不包括文件名
    isdir(path) 用于判断是否为路径
    import os
    print(os.path.abspath('../../pythonProject2'))
    print(os.path.exists('../chap11'))
    print(os.path.exists('../chap111'))
    print(os.path.join('../chap11','c11demo7.py'))
    print(os.path.split(os.getcwd()))
    print(os.path.splitext('c11demo7.py'))
    print(os.path.basename('../chap11/c11demo7.py'))
    print(os.path.dirname('../chap11/c11demo7.py'))
    print(os.path.isdir('../chap11/c11demo7.py'))
    

    小练习 列出指定目录下的所有Py文件 if filename.endwith('.py') 判断文件是否以'.py'做结尾

    # 列出指定目录下的所有Py文件
    
    import os
    i = 'y'
    while i == 'y':
        dir2 = '../'
        dir1 = dir2 + input('请输入要查找Py文件的目录:')
        if os.path.exists(dir1):
            lst = os.listdir(dir1)
            for i in lst:
                if '.py' in os.path.splitext(i):
                    print(i,'是py文件')
            i = input('查找结束,请问是否再次查找?y/n')
        else:
            i = input('查找不到该目录,请问是否重新输入?y/n')
    
    

标签:__,name,Python,self,字符串,lst,print,速查
From: https://www.cnblogs.com/libuqiong/p/16990873.html

相关文章