# 数据类型

  1. while……else…… 和 for……else…… 需要注意的是这里只有内层有break跳出循环才不会执行else的语句

  2. 数据类型: intstrlisttupledicsetbool

    1. 可哈希(不可变):数字、字符串、元组、布尔
    2. 不可哈希(可变):列表、字典、集合
  3. 数字int

    #bit_length() # 当十进制用二进制表示时,有效位数
    data = 11.bit_length()
    print(data) # 3
    
  4. 字符型换str

    #切片
    a='ABCdfsefef'
    print(a[0:-1])         #-1就是最后一个 取到前一个,即倒数第二个
    print(a[0:5:2])         #加步长 C、E
    print(a[5:0:-2])        #反向加步长
    v=a[~3]          # 反向,但是索引还是0开始
    c=a[~3:2:-1]     # 同样的顾头不顾尾
    print(v,c)       # e esf
    
    #常用字符串的方法
    print('Acss'.swapcase())       #大小写翻转,大写的小写,小写的大写
    print('egon say hi'.title())    #每个单词的首字母大写
    print('welcome'.center(20,'='))  #居中,且可以不用设置分隔符
    print('Aaaac'.count('a',0,4))   # 可设置开始和结束位置,字符出现的次数
    print('Asss\tnice'.expandtabs())  #Asss    nice
    print('adafd'.startswith('ad',0,3))  #True 可设置初始值,默认第一位 同理有endswith()
    print('asdfadf'.find('df',2,6))  #2  返回第一个位置的索引,可设置初始值,找不到返回-1
    print('asdfadf'.index('sd',1,6))  # 1  返回第一个索引,找不到报错
    print('adsfsd'.split('s',1))  #['ad', 'fsd'] 从左切割一次,可切割多次
    print('adsfsd'.rsplit('s',1)) #['adsf', 'd']  选择方向
    print('*waw**'.strip('*'))  # waw ,两边删除
    print('wang,niusdf'.replace('wang','SB',1))  # SB,niusdf # 可选择替换次数
    print(' '.join(['hi','wang'])) #hi wang  将可迭代对象转化为字符串
    
    #判断系列
    print(name.isalnum()) #字符串由字母或数字组成
    print(name.isalpha()) #字符串只由字母组成
    print(name.isdigit()) #字符串只由数字组成
    
  5. 元组tuple:元组被称为只读列表,即数据可以被查询,但不能被修改,所以字符串的切片操作同样适用于元组。例:(1,2,3)("a","b","c")

     注意:元组中只有一个元素时,需要使用,号隔开如:(3,),否则还是括号里面的数据类型
    

  6. 列表list

    #增加:append(),insert('index',obj),extend('iterable')、列表还可以使用+号,类似于extend
    li = [1,'a','b',2,3,'a']
    li.insert(0,55) #按照索引去增加
    li.append('aaa')  #增加到最后
    li.append([1,2,3]) #增加到最后,列表嵌套列表
    li.extend(['q,a,w']) #迭代的去增 ,括号里面是一个可迭代对象,每一个对象都加进去了
    li.extend('abc')
    
    #删除:pop(1)、del、 remove('值')、clear()
    l1 = li.pop(1)  #按照位置去删除,有返回值,默认删除尾部,l1,不写索引默认删除最后一个
    del li[1:3]    #按照位置去删除,也可切片删除没有返回值。
    del l1    # 删除整个列表
    li.remove('a') #按照元素去删除 注意只有list才有remove,当要删除的对象有多个是,只删除最左的一个,没有报错
    
    #改
    li = [1,'a','b',2,3,'a']
    li[1] = 'dfasdfas'        # 按照相应的索引去改
    print(li)          #[1, 'dfasdfas', 'b', 2, 3, 'a'
    
    li[1:3] = ['a','b']       # 按照切片去改,当有步长的时候必须一一对应,不然报错
    print(li)    #[1, 'a', 'b', 2, 3, 'a'] 
    
    li = [1,'we', 32]
    li.extend(['a','b','c'])  # 迭代添加
    print(li) #[1, 'we', 32, 'a', 'b', 'c']
    
    li[0:3:2] = ['q','5']   # 当涉及到步长的时候要注意,必须一一对应
    print(li)     #报错 [1, 'we', 32] -->  ['q', '5'] 这里将前面要被取代的位置换为'q','5',多了照换
     
     #查:索引循环 for
     #其他的方法:count、index、sort、reverse
    a = ["q","w","q","r","t","y"]
    print(a.count("q"))       # 2 count 统计 某元素出现的次数
    print(a.index("r"))     #3  index 找出某个值第一个匹配项的索引位置  找不到报错
     
    l = [[1,2],[3,4,5,6],(7,),'123']
    print(sorted(l,key=len))  # 注意sorted的占用内存多,key
    a=[-1,2,4,5]
    a.sort(key=lambda x:len(str(x)))   # 他没有返回值,所以只能打印a,注意列表的sort函数,用法和sorted方法相同,
    #有key键接受函数名或则lambda,但是s不会生成新列表
    print(a)  #[2, 4, 5, -1]   
          
    #列表和元组的烧操作:+ 
    li=[1,3,5,6]
    print(li+[2,4])  #[1, 3, 5, 6, 2, 4]
    tu=(2,4,5,4,[1,])
    print(tu[-1]+[1,3,5])  #[1, 3, 5, 6, 2, 4]
    print(tu)  #(2, 4, 5, 4, [1])      
    
  7. 字典dict字典是python中唯一的映射类型,采用键值对(key-value)的形式存储数据。python对key进行哈希函数运算,根据计算的结果决定value的存储地址,所以字典是无序存储的(自Python3.6后,默认是有序的),且key必须是可哈希的。可哈希表示key必须是不可变类型,如:数字、字符串、元组。

    #增:键值对,setdefault,
    dic = {}
    dic['name'] = '周润发'    # 如果dict中没有出现这个key, 就会新增一个key-value的组合进dict ,字典里有则会覆盖
    
    dic['age'] = 18        # 如果dict中没有出现过这个key-value. 可以通过setdefault设置默认值
    a=dic.setdefault('李嘉诚')    # 也可以往里面设置值.返回None
    dic.setdefault("李嘉诚", "房地产")    # 如果dict中已经存在了. 那setdefault将不会 起作⽤用
    ret = dic.setdefault('a','没有a')  # 没有返回第二个参数
    print(dic,a,ret)   #{'name': '周润发', 'age': 18, '李嘉诚': None, 'a': '没有a'} None 没有a
    
    #删:pop('key')、del、popitem()
    ret = dic.pop("jay")  # 默认删除最后一个,可根据键删除
    
    del dic["jay"]   # 删除含有这个key的键值对  
    ret = dic.popitem()  # 随机删除,但是在3.6中一般是删除最后一个,返回一个元组
    dic.clear()    # 清空列表
    
    # 改
    dic = {"id": 123, "name": 'sylar', "age": 18} 
    dic1 = {"id": 456, "name": "麻花藤", "ok": "wtf"} 
    dic.update(dic1)    # 把dic1中的内容更更新到dic中. 如果key重名. 则修改替换. 如果不存 在key, 则新增. 
    print(dic) 
    
    dic[key] = value # 强行赋值
    
    #查:setdefault、get() *****
    dic = {'name':'wang li', 'age':23'}
    print(dic['name'])  # wang li
     # print(dic['sylar'])     # 报错
    print(dic.setdefault('name')        # setdefault 也可以查取后面的值 又返回值'wang li'
    print(dic.get("sylar")) # None ,后面没有返回值就返回None 
    print(dic.get("sylar", "⽜B")) # ⽜B,如果在字典里没有找到key则会输出牛B
        
    #其他方法:
     #枚举 enumerate
    li = ['alex','银角','女神','egon','太白']
    for i,v in enumerate(li,1):
        print(i,v)                  # 这里输出的是元组,类似于(0, 'alex'),(1, '银角')……    
          
    #将a,b的每一项合并
    a = ['a,1','b,3,22','c,3,4','f,5',]  
    b=['a,2,1','b,4','d,2','e,12','g,12,43','a,4354,6']
    
    g = { i[0]:i for i in a}
    for i in b:
        if i[0] in g: g[i[0]]=g[i[0]][2:]+i[1:]
        else: g[i[0]]=i
    print(list(g.values()))
          
     #工厂化字典
    dic=dict([('name','alex'),('age','12')])  #里面必须是([  ])
    print(dic)   #{'name': 'alex', 'age': '12'}
          
     #setdefault的相关用法
    dic = {}
    dic.setdefault(None,[]).append('1')
    print(dic)       #{None: ['1']}
    --------字典属性---------
    1.字典是一种可变的容器,可以存储任意类型的数据
    2.字典中的每个数据都是用'键'(key)来进行索引的,而不向列表和元组中可以使用整数下标来进行索引
    3.字典中的数据是没有先后顺序的,字典的存储是无序的
    4.字典中数据以键(key):(value)对的方式进行存储的
    5.字典的键不能重复,且只能用不可变的数据作为字典的键      
    
  8. 集合set:无序性、互异性、元素可hash

    #去重
    set = {'1', 'wangli', True, [1, 2, 3]}   # 报错,元素必须时不可变类型
    
    #集合的增:add、update
    s = {"刘嘉玲", '关之琳', "王祖贤"}
    s.add("郑裕玲")
    print(s)  #{'关之琳', '王祖贤', '刘嘉玲', '郑裕玲'}
    
    s = {"刘嘉玲", '关之琳', "王祖贤"} 
    s.update("麻花藤")    # 迭代更更新
    print(s)           # {'李若彤', '麻', '张曼⽟', '藤', '花', '王祖贤', '刘嘉玲', '关之琳'}
    
    #删:pop()、remove()、clear()
    s = {"刘嘉玲", '关之琳', "王祖贤","张曼玉", "李若彤"}
    item = s.pop()  # 随机弹出一个.
    print(s)    #{'张曼玉', '李若彤', '王祖贤', '关之琳'}
    print(item)  #刘嘉玲
    
    s.remove("关之琳") # 直接删除元素 不存在这个元素. 删除会报错
    print(s)  #{'张曼玉', '李若彤', '王祖贤'}
    
    s.clear()    # 清空set集合.需要注意的是set集合如果是空的. 打印出来是set() 因为要和 dict区分的.
    print(s)    # set()
    
    #改:集合没有索引所以不能一个个取,只能remove删了指定元素,再加
    #查:可以用for循环
    
    #集合的操作
    s1 = {"刘能", "赵四", "⽪⻓山"} 
    s2 = {"刘科长", "冯乡长", "⽪长山"}
    
    # 交集  两个集合中的共有元素 
    print(s1 & s2)  
    # {'⽪长⼭'} print(s1.intersection(s2))  # {'⽪⻓山'} 
    
    # 并集
    print(s1 | s2)            # {'刘科长', '冯乡长', '赵四', '⽪⻓山', '刘能'} print(s1.union(s2))     # {'刘科⻓', '冯乡长', '赵四', '⽪长山', '刘能'} 
    
    # 差集 
    print(s1 - s2)    # {'赵四', '刘能'} 得到第一个中单独存在的 print(s1.difference(s2))   # {'赵四', '刘能'} 
    
    # 反交集 
    print(s1 ^ s2)  # 两个集合中单独存在的数据 {'冯乡长', '刘能', '刘科长', '赵四'} 
    print(s1.symmetric_difference(s2)) # {'冯乡长', '刘能', '刘科长', '赵四'}
    
    -----集合的一些属性————-----
    1.集合是一个可变容器
    2.集合内的数据对象都是唯一的(不能重复)
    3.集合是无序的存储结构,集合内的数据没有先后关系
    4.集合是可迭代对象
    5.集合相当于是只有键没有值得字典(键就是集合中的数据)
    6.集合内的元素是不可变的
    
    ------创建集合-------------
        1.使用直接量创建集合
          注意:使用直接量不能创建空集合
          s = {1,2,3}
          s = {"hello",3.14,True,(2019,02,17)}
        2.使用构造函数创建集合 - set
          s = set() #创建空集合
          s = set(iterable) #使用可迭代对象创建一个集合
          s = set("ABC") # s = {'A','B','C'}
          s = set([1,0,3.14,"hello"]) # s = {1,0,3.14,'hello'}
        
    --------集合的方法----------
    add()  # 集合对象.add(elem) 向集合内增加元素,如果添加的元素已经存在的话,则不执行任何操作
    clear() # 集合对象.clear() 清空集合内所有的元素
    copy()  # 集合对象.copy() 复制一个集合
    difference() # 集合对象1.difference(集合对象2) 返回两个集合的补集
    dierence_update() #集合对象1.difference_update(集合对象2) 移除两个集合中都存在的元素
    remove()  # 集合对象.remove(移除元素) 移除指定的元素
    discard()  # 同上
    pop()  #随机删除
    update()  # s1.update(s2) 用于更新s1集合的新集合 ,修改当前集合,也可以添加新元素到集合中
    
    --------集合推到式-----------
    L = [1,2,3,4,5,6,7,8,9]
    s = { x for x in L}
    s = { x for x in L if x % 2 == 0}
    
    --------固定集合-------------
    1.frozenset() : 创建一个空的固定集合
    2.frozenset(iterable) : 使用可迭代对象创建固定集合
    

# 深浅拷贝

​ 1.浅拷贝:数据半共享(复制其数据独立内存存放,但是只拷贝成功第一层)但是第一层虽然拷贝了,但是可以自己直接修改自己的,在第一层中如果存在嵌套地址,那么修改嵌套里面的数据,大家都会改。

​ 2.深拷贝:深拷贝:数据完全不共享(复制其数据完完全全放独立的一个内存,完全拷贝,数据不共享)深拷贝就是完完全全复制了一份,且数据不会互相影响,因为内存不共享。

# 浅拷贝
lst1 = ["何炅", "杜海涛","周渝民"]
lst2 = lst1.copy()  # 浅拷贝
lst1.append("李嘉诚")  # 互不影响,只拷贝一层壳
print(lst1,lst2,id(lst1), id(lst2))  #['何炅', '杜海涛', '周渝民', '李嘉诚'] ['何炅', '杜海涛', '周渝民'] 47203752 47204912

lst1 = ["何炅", "杜海涛","周渝民", ["麻花藤", "马芸", "周笔畅"]]  #第二层有可变类型
lst2 = lst1.copy()
lst1[3].append("无敌是多磨寂寞")
print(id(lst1[3]), id(lst2[3])) #id一致

#深拷贝
import copy
l1 = [1, 2, [11, 22, 33]]
# l2 = copy.copy(l1)  浅拷贝
l2 = copy.deepcopy(l1) #深拷贝
print(l1,'>>>',l2)  #[1, 2, [11, 22, 33]] >>> [1, 2, [11, 22, 33]]
l2[2][0] = 1111
print(l1,">>>",l2)  #[1, 2, [11, 22, 33]] >>> [1, 2, [1111, 22, 33]]

# 补充个面试题:
a = [1, 2]
a[1] = a
print(a)     # 结果: [1, [...]]

# 代码块的缓存机制

  • Python在执行 同一个代码 块的初始化对象的命令时,会检查是否其值是否已经存在,如果存在,会将其重用。换句话说:执行同一个代码块时,遇到初始化对象的命令时,他会将初始化的这个变量与值存储在一个字典中,在遇到新的变量时,会先在字典中查询记录,如果有同样的记录那么它会重复使用这个字典中的之前的这个值

  • 能够提高一些字符串,整数处理人物在时间和空间上的性能;需要值相同的字符串,整数的时候,直接从‘池’里拿来用,避免频繁的创建和销毁,提升效率,节约内存。

  • int(float):任何数字在同一代码块下都会复用。

    bool:True和False在字典中会以1,0方式存在,并且复用。

    str:几乎所有的字符串都会符合缓存机制,具体规定如下(了解即可!)

# 小数据池

  • 小数据池,也称为小整数缓存机制,或者称为驻留机制等
  • 小数据池也是只针对 int(float),str,bool,且区别于缓存机制的是:不同代码块 Python自动将**-5~256**的整数进行了缓存,当你将这些整数赋值给变量时,并不会重新创建对象,而是使用已经创建好的缓存对象。
  • 优点和缓存机制一致:都是节省内存开销,提升效率

# 文件操作

  • 使⽤Python来读写⽂件是非常简单的操作. 我们使用open()函数来打开一个文件, 获取到⽂件句柄. 然后通过文件句柄就可以进行各种各样的操作了了. 根据打开方式的不同能够执行的操 作也会有相应的差异. 打开文件的方式: r, w, a, r+, w+, a+, rb, wb, ab, r+b, w+b, a+b 默认使⽤用的是r(只读)模式

  • 注意文件的读写是只针对文件,而不是文件夹,且没有使用文件句柄的时候,要f.close()关闭文件句柄。

  • 在读取或写,非字符串文件时,比如视频、图片,就要使用含'b'的格式

  • 一般格式: f =open(’文件名(路径)', mode='模式',encoding ='编码方式')

    特殊格式:with open(’文件名(路径)', mode='模式',encoding ='编码方式') as f:

    #读文件:read()将文件的内容全部读取出来, 弊端:相当占内存,如果文件过大,容易导致内存崩溃
    f = open("护⼠少妇嫩模.txt",mode="r", encoding="utf-8") 
    content = f.read()       # 在这里要记住,在r模式下encoding 表示解码,在w情况下,是编码
    print(content) 
    f.close()  #关闭文件句柄
    
    #readline() ⼀次读取⼀行数据, 注意: readline()结尾, 注意每次读取出来的数据都会有⼀ 个\n 所以呢. 需			 要我们使⽤用strip()⽅方法来去掉\n或者空格
    #readline(n) 当有参数n时,则时读取一行的开头的前n个字符:
    #readlines() 将每一⾏形成一个元素, 放到⼀个列表中. 将所有的内容都读取出来. 所以 也是. 容易易出现内			存崩溃的问题.不推荐使⽤,形成一个列表
    from collections import Iterable,Iterator
    print(isinstance(open('a','w'),Iterable))  #True
    print(isinstance(open('a','w'),Iterator)) # True  所以文件句柄是个可迭代的,迭代器
    
    #写模式:写的时候注意. 如果没有文件. 则会创建文件, 如果⽂件存在. 则将原件中原来的内容删除, 再写入新内容 
    f = open("⼩小娃娃", mode="w", encoding="utf-8") 
    f.write("⾦⽑狮王") 
    f.flush()    # 刷新. 养成好习惯 
    f.close()
    
    #追加:在追加模式下. 我们写入的内容会追加在⽂件的结尾,相当于在这种模式下,打开后光标默认在尾部.
    f = open("⼩小娃娃", mode="a", encoding="utf-8") 
    f.write("麻花藤的最爱") 
    f.flush() 
    f.close()          # 正常的读取之后, 写在结尾
    
    #重要的其他方法:
    #seek(n) 光标移动到n位置, 注意, 移动的单位是byte. 所以如果是UTF-8的中⽂部要是3的倍数. 通常我们使用seek都是移动到开头或者结尾。 移动到开头: seek(0)  移动到结尾: seek(0,2)
    
    # tell() 使⽤用tell()可以帮我们获取到当前光标在什么位置,应该是自己的bytes
    
    # truncate() 截断⽂件  使用的是光标
    f = open("⼩娃娃", mode="w", encoding="utf-8") 
    f.write("哈哈")   # 写入两个字符 
    f.seek(3)   # 光标移动到3, 也就是两个字中间 
    f.truncate()    # 删掉光标后⾯面的所有内容 
    f.close()