• python基础


    Python

    概述

    简介

    1. python是一种解释性,面向对象,动态数据类型的高级程序语言,

    2. 解释型,无编译过程,逐行解释为二进制

    3. 交互性,直接执行程序

    4. 应用广泛,

    5. 编译型:一次将所有编译为二进制

    特点

    1. 易于学习

    2. 易于维护

    3. 易于阅读

    4. 广泛的标准库

    5. 互动模式

    6. 可移植

    7. 可扩展:兼容c语言,可调用

    8. 数据库

    9. GUI编程

    10. 可嵌入,c调python

    缺点

    1. 运行慢:代码一行一行翻译成CPU理解的机器码运行,即一行一行运行,很慢;

      而C语言直接翻译后成执行的机器码,很快

      编程任务:

      io型:复制,打开网页,所以说虽然速度慢,依然使用它

      计算型:数据计算,用c 快

    2. 代码不能加密:只能发布源代码,不能编译

    3. 没有多线程

     

    Python分类

    推荐cpython, py->c语言的字节码->0000010101

    jypython, py->java的字节码

    ironpython,

    其他语言的python

    pypy, 一次性编译为py的字节码,速度快,开发效率相对低-->0101

    这只是python解释器的分类,python语法规范相同

    #-*- encoding:utf-8 -*-
    # coding=utf-8 都可以
    print("段志方")
    #python2不支持中文默认是ascii

    variable

    字母数字下划线,空格不行,中文可以(但不要这样) 同java

    a=12

    b=a

    c=b

    b=100

    print(a,b,c)->12,100,12

    因为逐行执行

    注释

    单行注释:# 读,但不运行

    多行注释:'''xxxx''' 或"""xxxx"""

    数据交互,input

    name=input("xxxx")

    type(name)->str 全是字符串

    数据类型

    • 数字 type(100) -><class 'int'>

      int

      • 范围根据电脑变化 -2^31~2^31-1 32位

      • 64位 31 换63即可

        long 长整型

        python3中没有全是int

        python2中有

    • 字符串str:单引双引

    可相加,可相乘 与数字

    "段志方"*8

    msg='''

    xxx

    yyy

    zzz

    '''也可三个双引号

    • bool 布尔值:首字母大写

      此时不是注释,里面格式不变

      与字符串转换

      空串为false

      否则为true

      与list,元祖,只要是空都是False

    • list:类型可不一致,储存大量数据

    • 元组(只读列表):(1,2,3,"xxx")可存任何数据

    • 字典dict:键值对 {"name":"段志方","age":21}也可大量数据,不限类型

      如列表中有列表时可用lis[x][y]取出

    • 集合:{1,2,3,"xxx"} 可求交集,差集

    条件语句

    if 条件:

    4空格或tab 但不要混用

    if True:
    print(1)
    print(2)
    #都打印
    if True:
       xxx
    else:
       yyy
    if a :
       
    elif b :

    elif c:
       
    else:

    while

    #break continue 照样适用
    while True:
    print()

    while .... else

    正常执行完毕会执行else

    被break打断不会执行else

    count = 0
    while count < 5:
       count += 1
       print(count)
       break
    else:
       print("while->else")

    for循环

    s=字符串,列表等可迭代元素

    for i in s:

    print(i)

    if "xxx" in s:

    pass

    not in

    字符串与数字转换

    str='1'

    b=int(str) b变为int

    str(int) 数字转换为字符串

     

    格式化输出

    转义字符是"%" %%表示正常输出%

    #格式化输出
    #% s d
    name = input("input your name:")
    age = input("input your age:")
    height = input("input your height:")
    msg = "My name is %s, I'm %s years old,%scm tall" % (name, age, height)
    msg2 = '''-----------------------------
    name:%s
    age:%s
    height:%s
    -----------------------------
    ''' % (name, age, height)
    print(msg)
    print(msg2)

    编码

    ascii 初期 包含字符少只有7位 预留了第一位全为0

    unicode

    最开始

    1字节表示所有英文,数字,特殊符号

    2字节表示中文 ,不够,

    后来全部使用32位表示英文与中文都是

    升级->utf-8(一个字符最少8位) utf16 同理

    中文3字节

    英文1字节

    欧洲文字2字节

    gbk 中文2字节

    英文1个字节

    文件的储存与传输不能是unicode,只能是其他的几种

    py3:str在内存中是使用unicode编码的,所以文件存取要转换

    bytes类型 编码方式 ascii,utf-8,gbk等

    所以str直接存储到文件传输,不可以

    英文

    str:表现方式 s="dzf“

    编码方式 unicode 00001000 ...

    bytes 表现方式 s=b"dzf"

    编码 gbk 01000001...

    中文

    str同上

    bytes表现方式=b"xe1xd5xa5" 3个字节表示

    s="dzf".encode("utf-8") 为bytes类型 (将dzf转为bytes类型,utf-8编码方式)

    s="段志方".encode("utf-8")->b'xe6xaexb5xe5xbfx97xe6x96xb9'

    运算符

    +,-,**,/ ,//

    逻辑运算符(数字比较时想象为true,false即可)

    注意没有"||" "&&"

    &表示位运算符 当数字&时 与and不同 表示的是二进制相与

    ()>not >and >or

    x or y

    x为非零(真) 结果为x

    x为零(假) 结果为 y

    数字与bool可直接比较

    x and y

    x不为0 返回y

    x为0 返回 x

    int(True)=1

    bool(1)=True

    字符串常用操作方法

    字符串切片

    s[n]获取索引n的字符

    获取一段s[m:n]字符串切片,顾头不顾尾

    s[-1]从后向前

    s[-2:-5] 从后向前

    s[0:-1]不包含最后一个

    s[:]=s[0:]全部

    s[n:n]空

    s[0:10:2]0到10内每隔2个取一个

    s[4:0:-2]倒着取,没2个取一个

    注意不能s[4:0]

    str.capitalize() 首字母大写 数字无影响

    upper() 全部大写

    lower()全部小写

    swapcase()大小写反转

    title() "dzf非英文zbcd"->"Dzf非英文Zbcd"

    center(n,"#")设置字符串长度为n,两边#填充 居中显示

    expandtabs() 补全空格

    startswith("xxx")是否已xxx开头

    startswith("e",2,5)2到5组成的字符串是否已e开头

    find("x")返回第一个x下标 找不到返回-1

    index() 与find功能相同,但找不到会报错

    strip()去掉前后空格,也可以去掉换行符中间的不处理

    strip("%#@"):包含空格不管前后只要有其中的某个,即删除

    lstrip,rstrip 同理

    count("z",1,56)返回1-56中z出现的次数

    spilt()分割 返回列表 空已包含

    format 格式化输出

     

    s="你是{},今年{},爱好{},我是{}".format("xxx",21,"yy","xxx")
    s="你是{0},今年{1},爱好{2},我是{0}".format("xxx",21,"yy")
    s="你是{name},今年{age},爱好{like},我是{name}".format(name="xxx",age=21,like="yy")

    replace("old","new",count) old->new 替换count次

    isdight() 全部是数字

    isalpha()全部是字母

    isalnum()全部是数字,字母

    公共方法

    len(str) 返回字符个数,英文,中文都表示个字符

    int

    bit_length() 转换为2进制最少的位数

    列表(有序)32位5亿多个

    排序 list.sort(),最快排序 list.sort(reverse=True)倒序 list.reverse()翻转 增删改查 list.append(object)增加到最后 无返回值 list.insert(3,object)指定位置插入 list.extend("DZF")最后插入(可迭代的对象:字符串。列表等) ->['D','Z','F'] list.pop(1) 指定删除 有返回值:值 默认删最后一个 list.remove("xx")无返回值 list.clear()清空 del list 删除列表 del list[0:2] 切片删除 list[0]=[1,2,3] list[0]="dzf" list[0:2]="xxxx"切片插入都是按照迭代插入即x,x,x,x for i in list: li[0:2]

    列表的循环

    列表的嵌套:list = ["dzf","工藤新一",[1,2,3],]

     

    元祖,只读列表,可循环查询,可切片

    儿子不能改,孙子可能可以改

    zu=(1,2,3,4,[1,2,3,4])

    zu不能改,但里边的列表可以改

    a.join(可迭代元素x) 返回的是x中的每一个用a隔开:返回连接后字符串,列表的话就是拼接后返回

    range 顾头不顾尾

    for i in range(0,100):

    for i in range(0,100,2)步长2

    for i in range(10,0,-1)倒序

    字典dict

    数据类型:

    可变数据类型:list,dict ,set 不可哈希

    不可变数据类型:元祖,bool,int,str 可哈希

    dict key 必须为不可变数据类型

    dict value 任意类型

    二分查找,存储关系型数据,好像无序,版本有关

    • 增:dict["newKey"]=xxxx

    dict.setdefault("xxx")添加"xxx":None

    dict.setdefault("xxx","yyy") 若存在xxx的话不做操作

    • 改:dict["oldKey"]=xxxx

      dict1.update(dict2) dict1的所有添加到dict2 有覆盖,无添加

    • 删:

    dict.pop("key") 返回value

    dict.pop("不存在键")报错

    dict.pop("不存在键",XXX)不报错,若有删除,若无,返回xxx

    dict.popitem():3.6以上默认删除最后一个,3.5版本是随机删除(好像是)

    返回的是元祖形势的("key","value")

    del dict["key"] #无返回值

    del dict["不存在键"]#错误

    del dict #delete the dict 打印报错

    dict.clear() clear 打印不报错

    • dict.keys() 返回的是<class 'dict_keys'> 当做list就行 key列表,list(dict.keys())转换

      dict.values() 同上

      dict.items()同上 items列表 item是一个key-value元祖

      dict可循环默认为key

      i in dict ==dict.keys()

      dict.items() ->每个元祖(key,value) 不美观

      a,b=1,2
      a,b=[1,2]
      a,b分别为1和2
      a,b=[1,2],[1,2]:分别为2个list
      #一行交换,python专有
      a,b=b,a
      for k,v in dict.items():
         print(k,y)

      dict[key]=value key不存在会报错

      dict.get(key,xxx)=value 不存在=None或自定义值

       

      循环

      for i in str 循环中改变str实际次数不变

      in list 等可变类型 会发生改变

      列表循环时可以删除

      dict不可以

      进阶

      "=" 赋值运算,传递内存

      == 比较是否相等

      is 比较内存

      id(obj) 对象的内存

      i=6
      j=6
      id(i)=id(j)
      #若为300 则不相等与java类似 
      #数字,字符串小数据池,其他没有小数据池
      #数字范围 -5到256
      #字符串范围:不知道确切范围,规律:
      	#(不含有特殊字符 则id相同,否则就不同)
      	#str*20 相同 str*21 不同
      

      元祖中只有一个元素t=([1]) 此时t是list类型

      t2=([1],) 此时是元祖类型

    集合及深浅copy

    • 可变的数据类型

    • 里边的元素必须不可变

    • 无序

    • 不重复

      set1=set({1,2,3})
      set2={1,2,3,4,5,6}
      #add
      set1.add("dzf")
      set.update("abc")->{1,2,3,"a","b","c"}
      #delete
      set1.pop() 随机删除,并返回删除的元素
      set1.remove("xxxx")按元素删除,若不存在报错
      set1.clear() ->set()空集合
      del set1 删除整个集合
      #update
      因为是不可变数据类型,切无序,不能更改
      #select
      for i in set1:
          pass
      #顺序变化
      #可以求
      #交
      set1 & set2
      set1.intersection(set2)
      #反交集
      set1 ^ set2
      set1.symmetric_difference(set2)
      #并
      set1 | set2
      set1.union(set2)
      #差set1独有的
      set1-set2
      #子集
      set1>set2 #当set2是set1子集时返回True 1是2的超集
      set1<set2 #1是2的子集
      #
      set1 = set(list) #转换list为set 去重
      #
      s =frozenset(set2) #转化为不可变数据类型,此时s不能更改
      

      文件操作

      root,dirs,files = os.walk(path)

      # file option
      """
      1,path
      2,charset
      3,privileges
      """
      # mode = "r" encoding="utf8" utf8是文件建立时的编码方式
      # mode = "rb" 不用指定,以文件建立时的方式打开,用以非文字文件
      # mode = "w" encoding="utf8" wirte only
      # mode = "wb" 直接写入byte类型 不用编码方式,f.write("xxxx".encode("utf8"))
      # mode = "a" encoding = "utf8" 追加方式
      # mode = "ab"  追加方式f.write("xxxx".encode("utf8"))
      # mode = "r+"  可读可写(等于追加) 读写是由mode决定光标位置,从光标处开始操作
      # mode = "r+b"
      # mode = "w+" 先清除后再写,并无意义
      # mode = "a+" 写 读
      # f.seek(0)光标跳转
      # 形成文件句柄f
      f = open("D:/desktop/云空间/profile", mode="r+", encoding="utf8")
      
      # content = f.read()
      # content type 是str类型 自动把utf8转换为unicode 由read()实现
      # print(content)
      # f.close()
      # if not exist, will create it,if exist will overread it
      # f = open("log", mode="w", encoding="utf8")
      # f.write("dzf段志方")
      
      # f.read(3) 读取3个字符,一个汉字或一个英文 read读的都是##字符##
      # f.seek(3) 从第4个开始 按##字节##算,若正好位于中文,会报错
      # f.tell() 获取光标位置
      # f.readable() 是否可读
      # line = f.readline() # 读一行,与java类似
      # line = f.readlines() # 以每行为单位 形成列表
      # f.truncate(5) 从光标开始截取原文件的5位 abcdef(不确定)
      # for i in f:print(i) 也可读
      # f.close()
      
      # 自动关闭,可同时打开多个,推荐使用
      # with open("D:/desktop/云空间/profile", mode="r+", encoding="utf8") as obj:
      #     print(obj.read())
      # with open("D:/desktop/云空间/profile", mode="r+", encoding="utf8") as obj,
      #          open("D:/desktop/云空间/profile", mode="r+", encoding="utf8") as obj2:
      #     print(obj.read())
      # strip() 可以去掉空格或换行符
      # 修改文件,文件是不能修改的,只能复制后,删除原来
      # delete file rename file
      import os
      os.remove("path")
      os.rename("old","new")
      

      初始函数

      # 函数调用时必须已经存在
      # def my_len(s):
      #     i = 0
      #     for k in s:
      #         i += 1
      #     return None
      #
      #
      # print(my_len('段志方'))
      #
      #
      # def my_len():
      #     s="as"
      #     i = 0
      #     for k in s:
      #         i += 1
      #     return i
      
      
      
      """
      先定义,后调用
      返回值情况,
      1,无返回值,如输出就是None 
          不用写,
          只写return (它是结束代码),
          return None,不常用
      2,一个值
          int,str,list,dict等
      3,多个返回值
          return 1,2
          多个返回值用多个变量接受,不能多,也不能少
          但可以用一个变量接受,按元祖返回
      4,解释中输入1,2,3-->(1,2,3)
          a,b,c=[1,2,3]   可得a=1,b=2,c=3
      """
      
      
      # def func1(a, b = 1):
      #     pass
      #
      #
      # func1((1,2,3))
      """
      参数
          若多个函数同名,距离调用最近的生效
          若无参数,强制传参报错
          若有参,不传不报错
      1,无参
      2,一个参数
      3,多个参数def my(a,b): 按顺序传递
          也可以 my(b=2,a=1)不报错
          可以混用my(1,b=1),先按照位置传,再使用关键字
          但my(1,b=1),my(a=1,1)报错,同一变量只能一个值
      型参
          位置参数:按照位置传递,必须传
          默认参数:def my(a,b = 2) 不传及默认,因此默认参数只能在后边,先位置参数
          动态参数:def my(*args) 函数中当做元祖,print()
                  my(1,2,3,4.....)  
          先位置参数,再动态参数(只接受位置传参的),再默认参数,最后**kwargs
          动态参数2:def my(**kwargs):
          传入dict my(a=1,b=2,c=3)--->{"a":1,"b":2,"c":3}
          
          def my(*args,**kwargs) **args 在前,,,必须先位置参数,再关键字
      动态参数另一种传参方式
          列表或元祖当做位置参数传入
          def my(*args):
          list=(1,2,3)
          my(*list) 表示按次序传给
          
          def my(**kwargs):
          dict={"A":1,"B":2}
          my(**dict) 表示按次序传给
          个人感觉这种就是只传一个参数
      函数注释
      """
      
      
      # def my(arg):
      #     """
      #     功能
      #     :param arg:
      #     :return:
      #     """
      #     print(arg)
      #
      #
      # my([1,2,3])
      
      user_list = [
          {'username':'barry','password':'1234'},
          {'username':'alex','password':'asdf'},
                   ]
      board = ['张三','李小四','王二麻子']
      while 1:
          username = input('用户名:')
          if username.upper() == 'Q':break
          password = input('密码:')
          for i in board:
              if i in username:
                  username = username.replace(i,'*'*len(i))
          user_list.append({'username':username,'password':password})
          print({'username':username,'password':password})
          print(user_list)
      # 陷阱
      # 若默认参数是可变数据类型,调用时,若不传递数据,公用一个资源,字典也类似
      
      
      def f(a=[]):
          a.append(1)
      
      
      f()  # [1]
      f()  # [1,1]
      f([])  # [1]
      f()  # [1,1]
      
      
      def f(k,a={}):
          a[k] = "v"
      
      
      f(1)  # {1:"v"}
      f(2)  # {1:"v",2:"v"}
      f(3)  # {1:"v",2:"v",3:"v"}
      

    函数进阶

    # 内置命名空间--解释器
    #   解释器启动就可以使用的名字,他们在解释器加载时加载进内存
    # 全局命名空间--代码,非函数
    #   程序加载时过程中加载的
    # 局部命名空间--函数中代码
    #   函数内部的名字,调用函数的时候才会产生,调用结束,消失
    
    # 函数名不加括号 ,可打印出内存地址
    #   地址+() 相当于执行
    # a = 1
    # def fun():
    #     a = 2
    # fun()
    # print(a) # a=1
    # def fun():
    #     global  a  # 不推荐使用
    #     a = 2
    # fun()
    # print(a) # a=2
    # 对于不可变数据类型,在局部可查看全局中的变量
    # 但不能直接修改
    # 若有修改,在函数中开始时加 global xx
    # 若在局部中声明一个global函数,那么此函数在局部内的操作对全局的变量有效
    
    # globals() 永远全局,locals()会变化
    # def f():
    #     x = "111"
    #     y = "222"
    #     print(locals())  # 放在本地查看局部中所有变量 字典形式
    # print(locals())  # 放在全局,全局就是本地
    # print(globals())  # 查看全局的与内置的
    
    # def max(a,b):
    #     return a if a>b else b # 三目运算符
    # 变量 = 条件返回True的结果 if 条件 else 条件返回False的结果
    # print(max(1,2))
    
    # 函数嵌套定义
    # def f():...
    # a = 1
    # def outer():
    #     def inner1():
    #         a = 2
    #         def inner2():
    #             a = 3
    #             def inner3():
    #                 nonlocal a
    #                 a += 1
    #             inner3()
    #             print(a)
    #         inner2()
    #         print(a)
    #     inner1()
    # outer()
    # print(a)
    # 注意 global var 此var必须是全局的,且全局的只有一层,局部可有多层(函数多层嵌套)
    # py3 nolocal var 声明了(上层)的(局部变量),局部若没有,会报错
    
    # 函数作为,元素,参数,返回值
    
    # 函数可以赋值 fun = fun1,可变量一样,亦可放在list,dict等作为容器元素
    # 打印出来是<function fun_name at 0x0000000>
    # 加括号执行 list = [fun,fun2]  list[0]()执行,也可作为参数再次传入函数
    # def f():
    #     print(1)
    # list = [f]
    # list[0]()
    
    # 第一类对象, 函数名就符合
    #   运行期创建
    #   可作为函数参数或返回值
    #   可存入变量的实体
    
    
    # 闭包:嵌套函数,(内部)调用(外部函)数(变量),若不调用,就是嵌套函数
    
    # def outer():
    #     a = 1
    #     def inn():
    #         print(a)
    #     print(inn.__closure__)  # <cell at addr:int....> 表示是闭包
    # outer()
    # print(outer.__closure__)  # None 不是闭包
    # 常用形式, 外部调用函数内部函数,
    # 以前不用时,每次outer()内部数据都会建立,
    # 此时使用返回值,只要引用存在,数据创建一次,不会随outer结束而消失,避免多次创建
    # def outer():
    #     a = 1
    #     def inn():
    #         print(a)
    #     return inn
    # b = outer()
    # b()
    
    # import urllib # 模块,py文件
    # from urllib.request import urlopen
    #
    #
    # def geturl():
    #     url = "http://www.xiaohuar.com"
    #     def get():
    #         ret = urlopen(url).read()
    #         return ret
    #     return get
    #
    # get = geturl()
    # print(get())
    
    
    # c = fun(10,20) 先执行, 在赋值,赋函数返回值,若无则是None
    
    

    装饰器

     

    # 装饰器形成过程
    # 装饰器作用
    # 不想修改函数的调用方式,但是还要在原始函数中加工能,java中的面向切面编程
    # def fun():
    #     print("原始功能")
    # def outer(f):
    #     def inner():
    #         print("前置额外功能")
    #         f()
    #         print("后置额外功能")
    #     return inner
    # fun = outer(fun)
    # fun()
    # 被装饰函数可加返回值,需要在inner中接受并返回
    # 也可以加参数,inner(*args(1,2,3,4),**kwargs) 接受,此时inner中args是个列表,f(*args,**kwargs) 表示把列表args,按位置传入
    # print(*args)--> 1 2 3 4
    # 接受聚合,调用打散
    # 原则:开放封闭原则
    #   对扩展开放,修改封闭
    
    # 语法糖
    # @outer   @+装饰器函数名
    # def fun():
    #     print("原始功能")
    # 加上语法糖词句(可省)
    # fun = outer(fun)
    
    # 装饰器的固定模式(公式)
    
    

     

    装饰器进阶

     

    # 装饰器形成过程
    # 装饰器作用
    # 不想修改函数的调用方式,但是还要在原始函数中加工能,java中的面向切面编程
    # def fun():
    #     print("原始功能")
    # def outer(f):
    #     def inner():
    #         print("前置额外功能")
    #         f()
    #         print("后置额外功能")
    #     return inner
    # fun = outer(fun)
    # fun()
    # 被装饰函数可加返回值,需要在inner中接受并返回
    # 也可以加参数,inner(*args(1,2,3,4),**kwargs) 接受,此时inner中args是个列表,f(*args,**kwargs) 表示把列表args,按位置传入
    # print(*args)--> 1 2 3 4
    # 接受聚合,调用打散
    # 原则:开放封闭原则
    #   对扩展开放,修改封闭
    
    # 语法糖
    # @outer   @+装饰器函数名
    # def fun():
    #     print("原始功能")
    # 加上语法糖词句(可省)
    # fun = outer(fun)
    
    # 装饰器的固定模式(公式)
    # def fun():pass
    # print(fun.__name__) 打印(执行函数)的字符串函数名,对于装饰器的话,返回的是inner的名字
    # print(fun.__doc__) 打印函数注释,同上
    
    # 添加from functools import wraps(固定的) 给inner函数加上@waraps+(原始函数名)
    # 此时调用fun.___name__ 即可返回原始函数的信息
    
    
    # 一个装饰器,装饰多个函数,在不同函数上加@语法糖即可
    
    # 带参数的装饰器
    # 500个函数要加装饰器,一个函数修饰多个函数
    
    
    def timmer(f):
        def inner(*args, **kwargs):
            pass
            ret = f(*args, **kwargs)
            pass
            return ret
    
        return inner
    
    
    @timmer
    def fun(): pass
    
    # 修改,三层装饰器,最多就是三层
    FLAG = True
    def timmer_out(flag):
        def timmer(f):
            def inner(*args, **kwargs):
                if flag:
                    pass
                    ret = f(*args, **kwargs)
                    pass
                else:
                    ret = f(*args, **kwargs)
                return ret
            return inner
        return timmer
    # 加上括号就是调用,先调用再@
    # @timmer_out(FLAG) = timmer = timmer_out(FLAG);@timmer
    @timmer_out(FLAG)
    def fun(): pass
    # 多个装饰器装饰一个函数
    # 运行时先d1 的前置装饰,d2 的前置装饰,d2的后置装饰,d1的后置装饰
    # 两个装饰器,先生效距离原函数近的语法糖,所以先生效的在内部
    # 嵌套调用装饰器
    def decorate1(f): # f--> fun
        def inner1():
            pass
    def decorate2(f): # f-->inner
        def inner2():
            pass
    @decorate1 # fun = decorate1(fun)->decorate1(inner)==inner2
    @decorate2 # fun = decorate2(fun)=inner
    def fun():
        pass
    # 此时调用fun()等于调用inner2
    fun()
    

     

     

    迭代器与生成器

    # list(generator) 也可以从生成器取值,但是取全部,全部内容内存生成
    # def generator():
    #     print(1)
    #     yield 1
    #     print(2)
    # g = generator();
    # print(g.__next__())
    # 调用2次next 第二次会打印2 但会报错
    # def generator():
    #     print(1)
    #     count = yield 1
    #     print(2)
    #     yield 2
    # g = generator();
    # print(g.__next__()) #执行到 yield 1
    # print(g.send())  # send() 与next效果相同
    # print(g.send("hello")) # 获取yield 时 传入新的值
    
    # 修改yield 1 为 count = yield 1
    # 此时执行到yield 1 时 停止,等待send() ,传入值给上个next,并赋值,在向下执行
    #   注意第一次获取生成器时,必须使用next,
    #   最后一个yield 不能接受外部的值,最后一个yield会后不能有代码,若必须使用,最后加yield 即可, 空
    
    
    # 获取移动平均值
    # def average():
    #     sum = 0
    #     count = 0
    #     avg = 0
    #     while 1:
    #         num = yield avg
    #         sum += num
    #         count +=1
    #         avg = sum / count
    # avg = average()
    # print(avg.__next__())
    # print(avg.send(10))
    # print(avg.send(20))
    
    
    # def generator():
    #     a = "abcd"
    #     b = "1234"
    #     # for 循环yield a
    #     yield from a
    #     yield from b
    # for i in generator():
    #     print(i) # a b c d 1 2 3 4
    #
    # 生成器表达式和列表推导式
    # 推导式
    # list = [i for i in range(10)]
    # print(list)
    # list = ["dzf%s" %i for i in range(10)]
    # print(list)
    # 其他推导式
    # [元素或操作 for 元素 in 可迭代数据类型] 遍历后处理
    # [满足条件的元素的操作 for 元素 in 可迭代数据类型 if 元素条件] 筛选功能
    #   列表推导式
    # [i for i in range(30) if i%3==0] -->[0,3,6....]
    # 双层for 查找 双层list中数据
    # names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
    #           ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
    # [name for list in names for name in list if name.count('e')==2]
    #   集合推导式,
    # {x**2 for x in [1,-1,2]} -->{1,4} 自带去重
    # [x**2 for x in [1,-1,2]] -->[1,1,4]
    #   字典推导式
    #       调换字典的key-value
    # dict = {"a":1,"b":2,"A":7,"B":45}
    # dict2 = {dict[k]:k for k in dict}
    #       合并大小写对应的value值,将k统一成小写
    # dict3 = {k.lower(): dict.get(k.lower(),0)+dict.get(k.upper(), 0) for k in dict}
    # print(dict3)
    # 表达式,括号不同,g为生成器.
    # g = (i for i in range(10))
    # print(g)
    # for i in g:
    #     print(i)
    # print(type(list()))
    # print(type({1,2,34,5,5,5,}))
    
    # 作业
    # def find(path):
    #     with open(path,encoding="utf-8") as f:
    #         for line in f:
    #             if "xxx" in line:
    #                 yield line
    # for line in find("xxx"):
    #     print(line)
    
    # 生成器面试题
    # def demo():
    #     for i in range(4):
    #         yield i
    # g = demo()
    # g1 = (i for i in g) # -->此时未for循环,只生成生成器
    # def fun():
    #     for i in g:
    #         yield i
    # g2 = (i for i in g1)
    # print(list(g1)) # -->[1,2,3,4],g1,执行生成器,全部取出
    # print(list(g2)) # -->[],此时从g1取值没有了,为空
    
    # 2
    def add(n,i):
        return n+i
    def test():
        for i in range(4):
            yield i
    g=test()
    for n in [1,10,5]:
        g = (add(n,i) for i in g)
    #
    # n = 1
    # g=(add(n,i) for i in g)
    # n = 10
    # g=(add(n,i) for i in g) # -->g=(add(n,i) for i in (add(n,i) for i in g))
    print(list(g))
    
    list1 = [ # 列表剥皮
        1,
        2,
        [
            3,
            4,
            [5,6,7]
        ],
        [
            3,
            4,
            [
                5,
                6,
                7,
                [8,9,10]
            ]
        ]
    ]
    def f3(x): # 生成器
        return [a for b in x for a in f3(b)] if isinstance(x, list) else [x]
    def f2(x):
        l = []
        for i in x:
            if isinstance(i,list):
                for k in f2(i):
                    l.append(k)
            else:
                l.append(i)
        return l
    def f(x,l=[]):
        for i in x:
            if isinstance(i,list):
                f(i)
            else:
                l.append(i)
        return l
    print(f(list1))
    print(f2(list1))
    print(f3(list1))
    

     

    内置函数

    https://www.processon.com/view/link/5d4fa21be4b0ac2b61744998

    http://assets.processon.com/chart_image/5d4fa098e4b0869fa40f9454.png

    # 内置函数
    # callable('xxx') # 检测是不是函数--->True or False
    # help(str) # 显示str的帮助信息
    # (导入)import time=time = __import__('time')
    # print(time.time())
    # f=open()
    # f.read()
    # print(f.writable()) # 检测是否可写
    # print(f.readable()) # 检测是否可读
    # # 内存相关
    # id()
    # hash(),一次执行中,相同的对象hash值不变,不管对象多大,hash值有范围
    # print(hash(123456))
    # print(hash('123456'))
    # print(hash([1,2,3,4,5,6])) # 不可hash
    # print(hash((1,2,3,4,5,6)))
    
    # print()
    # print("xxxx") # 自带换行符
    # print("xxx",end='') # 取消换行
    # print("xxx",sep='|') # 指定分隔符
    # f = open('file','w') # 指定打印文件位置,控制台也是文件
    # print("xxx",file=f)
    # f.close()
    # 进度条
    # 
     表示回到行首
    # 
     使最后换行
    # flush=True, 传入字符立即写入,不缓存再写
    # import time
    # for i in range(0,101,2):
    #     time.sleep(0.1)
    #     char_num = i//2
    #     per_str="
    %s%%:%s
    " % (i,'*'*char_num) if i==100 else "
    %s%%:%s" % (i,'*'*char_num)
    #     print(per_str,end='',flush=True)
    
    # exec eval, 都可执行字符串代码,exec 无返回值
    # eval 只能用明确知道的要执行的代码,不常用
    #   eval -- 有结果的简单计算
    #   exec -- 简单流程控制
    # exec('print(123)') # 123
    # eval('print(123)') # 123
    # print(eval('1+2+3+4')) # 10
    # print(exec('1+2+3+4')) # None
    
    # compile 把代码编译为字节码,下次调用节省时间,
    # code1 = 'for i in range(0,10):print(i)'
    # # '' 为文件名,没有的话置空
    # compile1 = compile(code1,'','exec')
    
    # code2 = '1+2+3+4'
    # compile2 = compile(code2,'','eval')
    # print(eval(compile2))
    
    # code3 = 'name = input("please input your name:")'
    # compile3 = compile(code3,'','single')
    # # name 执行前name不存在
    # exec(compile3) # 执行后有name,虽然报错,但存在
    # print(name)
    
    # complex 复数 ,实部,虚部都是float
    # print(complex(12,3)) # -->12 + 3j
    """
        实数
          有理数:小数,有限循环小数
          无理数:无线不循环小数
        虚数:x的平方式负数,i**2 = -1
        复数:实数+虚数,5+ni ,不能比较大小,
    """
    # 浮点数
    # print(float(12))
    """
        354.123 = 3.45123*10**2=35.4123*10,点回浮动 所以叫浮点数
        float:有限循环,无限循环,
        不是float:无线不循环
    """
    
    # 进制转换 bin() 0b, oct() 0o,hex() 0x
    # abs(n) 绝对值
    # divmod(x,y) -->(n,m) x/y 商n余m,print(divmod(8,2))
    # round(3.456879,2) 精确值,会四舍五入
    # pow(x,y) 幂运算 pow(x,y,z) x**y % z 幂运算后取余
    # sum(可迭代,切里边是数字)
    #   print(sum([1,2,3,4])) 基础值为0 ->10
    #   print(sum([1,2,3,4],10)) 基础值为10 -> 20
    # min() 最小值,可传迭代,也可*args
    #   min([1,2,3,4])
    #   min(1,2,3,4)
    #   min(1,2,3,-4,key=abs) 可以 把key 用方法计算后求函数值
    # max同min 注意,返回的是参数值,不是进过处理后的值
    
    # reversed(list) #不改变原来列表,返回一个迭代器
    # l=slice(1,5,2) 切片规则
    #   list[l]
    
    # formate(数字)->转字符串
    #   formate('test','<20') 20空间  左对齐
    #   formate('test','>20') 右对齐
    #   formate('test','^20') 居中
    # 等
    
    # bytes 转换bytes类型
    #   拿到gbk 转unicode 再转到utf8
    # str = bytes("你好",encoding="gbk") # unicode转gbk的bytes类型
    # str.decode("gbk") # 你好
    # str = bytes("你好",encoding="utf8") # unicode转utf8的bytes类型
    # str.decode("utf8") # 你好
    # bytearray("你好",encoding="utf8") 返回byte 列表,修改里边的16进制可实现更改
    # ord('a')查看编码 按照unicode
    # print(ord('段'))
    # print(chr(97))
    # ascii('xxx')
    # %s,%r
    # print(repr('1')) # --> '1'
    # print(repr(1)) # --> 1
    # 枚举 l = [1,2,3,4] enum = enumerate(l)
    # all([]) 判断里边字符是否全为True
    # print(all([1,2,3,0]))
    # any() 看上边
    # zip()
    """
        l = [1,2,3]
        l2 = ["a","b","c"]
        for i in zip(l,l2)   两边数可不同,开可以加l3,l4,若为字典(注意无序),只能加上key
            print(i) -->(1,'a') (2,'b') (3,'c')
    """
    # filter(),返回handler处理后的结果,bool
    # 等于[i for i in [1,2,3,4,5] if i%2==1]
    # ret = filter(handler,可迭代的元素) ret是迭代器
    # def fun(x):
    #     return x%2==1
    # ref = filter(fun,[1,2,3,4,5,6])
    # print(list(ref)) --> [1,3,5]
    # import math
    # print(math.sqrt(9))
    # print(1.5%1)
    # map(fun,可迭代元素) 分处理后,返回可迭代元素
    # ret = map(abs,[1,-4,-8])
    # sorted(可迭代元素,key=fun,reserve=True) 自定义排序,返回新列表,元数据不变
    # l.sort(key=abs) 按绝对值排序
    

    匿名函数

    # 匿名函数
    #   必须在一行,
    #   lamdba 定义,n,m参数,冒号后边直接是返回值
    calc = lambda n,m:m*n+2
    #   调用,还可以有名字, 匿名的时候对于函数名做参数时使用
    #   max([],key=lambda k:xxx)
    # max,min,sorted,filter,map
    print(calc(1,2))
    # 面试题
    #现有两元组(('a'),('b')),(('c'),('d')),
    # 请使用python中匿名函数生成列表[{'a':'c'},{'b':'d'}]
    # ret = zip((('a'),('b')),(('c'),('d')))
    # ret = map(lambda t:{t[0]:t[1]},ret)
    # print(list(ret))
    
    # max min sorted filter map
    # 匿名函数 == 内置函数
    # zip
    # ret = zip((('a'),('b')),(('c'),('d')))
    # res = map(lambda tup:{tup[0]:tup[1]},ret)
    # print(list(res))
    # 下面代码的输出结果是什么?
    # def multipliers():
    #     return [lambda x:i*x for i in range(4)] # 返回4个lambda ,但最后i最后都是3
    # print([m(2) for m in multipliers()]) [6,6,6,6]
    
    #     return (lambda x:i*x for i in range(4)) 生成器,
    #     --->[0,2,4,6]
    # 作业
    # 3.用map来处理字符串列表,把列表中所有人都变成sb,比方alex_sb
    name=['alex','wupeiqi','yuanhao','nezha']
    # def func(item):
    #     return item+'_sb'
    # ret = map(func,name)   #ret是迭代器
    # for i in ret:
    #     print(i)
    # print(list(ret))
    
    # ret = map(lambda item:item+'_sb',name)
    # print(list(ret))
    
    # 4.用filter函数处理数字列表,将列表中所有的偶数筛选出来
    # num = [1,3,5,6,7,8]
    # def func(x):
    #     if x%2 == 0:
    #         return True
    # ret = filter(func,num)  #ret是迭代器
    # print(list(ret))
    #
    # ret = filter(lambda x:x%2 == 0,num)
    # ret = filter(lambda x:True if x%2 == 0 else False,num)
    # print(list(ret))
    
    # 5.随意写一个20行以上的文件
    # 运行程序,先将内容读到内存中,用列表存储。
    # 接收用户输入页码,每页5条,仅输出当页的内容
    
    # with open('file',encoding='utf-8') as f:
    #     l = f.readlines()
    # page_num = int(input('请输入页码 : '))
    # pages,mod = divmod(len(l),5) #求有多少页,有没有剩余的行数
    # if mod:           # 如果有剩余的行数,那么页数加一
    #     pages += 1    # 一共有多少页
    # if page_num > pages or page_num <= 0:   #用户输入的页数大于总数或者小于等于0
    #     print('输入有误')
    # elif page_num == pages and mod !=0:    #如果用户输入的页码是最后一页,且之前有过剩余行数
    #     for i in range(mod):
    #         print(l[(page_num-1)*5 +i].strip())  #只输出这一页上剩余的行
    # else:
    #     for i in range(5):
    #         print(l[(page_num-1)*5 +i].strip())  #输出5行
    
    # 6.如下,每个小字典的name对应股票名字,shares对应多少股,price对应股票的价格
    # portfolio = [
    #     {'name': 'IBM', 'shares': 100, 'price': 91.1},
    #     {'name': 'AAPL', 'shares': 50, 'price': 543.22},
    #     {'name': 'FB', 'shares': 200, 'price': 21.09},
    #     {'name': 'HPQ', 'shares': 35, 'price': 31.75},
    #     {'name': 'YHOO', 'shares': 45, 'price': 16.35},
    #     {'name': 'ACME', 'shares': 75, 'price': 115.65}
    # ]
    
    # 6.1.计算购买每支股票的总价
    # ret = map(lambda dic : {dic['name']:round(dic['shares']*dic['price'],2)},portfolio)
    # print(list(ret))
    
    # 6.2.用filter过滤出,单价大于100的股票有哪些
    # ret = filter(lambda dic:True if dic['price'] > 100 else False,portfolio)
    # print(list(ret))
    # ret = filter(lambda dic:dic['price'] > 100,portfolio)
    # print(list(ret))
    
    # 每周大作业
    # 这一周写得所有博客地址,精确到页的url,至少三篇,内容不限
    # 大作业 : py readme(对作业描述,顺便可以写点儿你想和导员沟通的) 流程图
    #
    

    初识递归

    # 初识递归 最大深度1000左右 997 或998
    # 设置默认次数
    # import sys
    # sys.setrecursionlimit(100)
    # 若递归次数太多,则不适合递归
    
    
    # 二分查找算法 必须处理有序的列表
    # l = [2,3,5,10,15,16,18,22,26,30,32,35,41,42,43,55,56,66,67,69,72,76,82,83,88]
    # 5000000  4999998
    # 代码实现
    # def find(l,aim):
    #     mid_index = len(l) // 2
    #     if l[mid_index] < aim:
    #         new_l = l[mid_index+1 :] 每次传入新列表,最终查到时下标不对
    #         find(new_l,aim)
    #     elif l[mid_index] > aim:
    #         new_l = l[:mid_index]
    #         find(new_l, aim)
    #     else:
    #         print('找到了',mid_index,l[mid_index])
    #
    # find(l,66)
    
    l = [2,3,5,10,15,16,18,22,26,30,32,35,41,42,43,55,56,66,67,69,72,76,82,83,88]
    # def find(l,aim,start = 0,end = None):
    #     end = len(l) if end is None else end   # end = len(l)   24
    #     mid_index = (end - start)//2 + start   #计算中间值  12 + 0 = 12
    #     if l[mid_index] < aim:       #l[12] < 44   #41 < 44
    #         find(l,aim,start =mid_index+1,end=end)  # find(l,44,start=13,end=24)
    #     elif l[mid_index] > aim:
    #         find(l, aim, start=start, end=mid_index-1)
    #     else:
    #         print('找到了',mid_index,aim)
    #
    # def find(l,aim,start = 0,end = None):    # l,44,start=13,end=24
    #     end = len(l) if end is None else end   # end = 24
    #     mid_index = (end - start)//2 + start   #计算中间值  24-13/2 = 5 + 13 = 18
    #     if l[mid_index] < aim:       #l[18] < 44   #67 < 44
    #         find(l,aim,start =mid_index+1,end=end)
    #     elif l[mid_index] > aim:     # 67 > 44
    #         find(l, aim, start=start, end=mid_index-1)  # find(l,44,start=13,end=17)
    #     else:
    #         print('找到了',mid_index,aim)
    #
    # def find(l,aim,start = 0,end = None):    # l,44,start=13,end=17
    #     end = len(l) if end is None else end   # end = 17
    #     mid_index = (end - start)//2 + start   #计算中间值  17-13/2 = 2 + 13 = 15
    #     if l[mid_index] < aim:       #l[15] < 44   #55 < 44
    #         find(l,aim,start =mid_index+1,end=end)
    #     elif l[mid_index] > aim:     # 55 > 44
    #         find(l, aim, start=start, end=mid_index-1)  # find(l,44,start=13,end=14)
    #     else:
    #         print('找到了',mid_index,aim)
    #
    # def find(l,aim,start = 0,end = None):    # l,44,start=13,end=14
    #     end = len(l) if end is None else end   # end = 14
    #     mid_index = (end - start)//2 + start   #计算中间值  14-13/2 = 0+ 13 = 13
    #     if l[mid_index] < aim:       #l[13] < 44   #42 < 44
    #         find(l,aim,start =mid_index+1,end=end)  # find(l,44,start=14,end=14)
    #     elif l[mid_index] > aim:     # 42 > 44
    #         find(l, aim, start=start, end=mid_index-1)
    #     else:
    #         print('找到了',mid_index,aim)
    
    def find(l,aim,start = 0,end = None):
        end = len(l) if end is None else end
        mid_index = (end - start)//2 + start
        if start <= end:
            if l[mid_index] < aim:
                return find(l,aim,start =mid_index+1,end=end)
            elif l[mid_index] > aim:
                return find(l, aim, start=start, end=mid_index-1)
            else:
                return mid_index
        else:
            return '找不到这个值'
    
    
    ret= find(l,44)
    print(ret)
    # 参数 end
    # 返回值
    # 找不到的话怎么办
    
    # l.index()
    
    
    # 67  发生两次调用
    # 66  发生好几次
    # 44  找不到
    
    
    # age,二分查找,三级菜单的代码看一遍
    # 斐波那契  # 问第n个斐波那契数是多少
    # 阶乘
        #3! 3*2*1
    # 附加题 :考试附加题
        # 递归实现
    # l = [1,2,3]
    # print(l[1:1])
    
    
    # 超过最大递归限制的报错
    # 只要写递归函数,必须要有结束条件。
    
    # 返回值
    # 不要只看到return就认为已经返回了。要看返回操作是在递归到第几层的时候发生的,然后返回给了谁。
    # 如果不是返回给最外层函数,调用者就接收不到。
    # 需要再分析,看如何把结果返回回来。
    
    # 循环
    # 递归
    
    
    # 斐波那契  # 问第n个斐波那契数是多少
    # 1,1,2,3,5,8   #fib(6) = fib(5) + fib(4)
    # def fib(n):
    #     if n == 1 or n==2:
    #         return 1
    #     return fib(n-1) + fib(n-2) #两次递归非常慢
    # print(fib(50))
    
    # fib(6) = fib(5) + fib(4)
    # fib(5) = fib(4)+fib(3)
    # fib(4) = fib(3)+fib(2)
    # fib(3) = fib(2)+fib(1)
    # fib(2) = 1
    # fib(1) = 1
    # def fib(n,l = [0]):
    #     l[0] +=1
    #     if n ==1 or n == 2:
    #         l[0] -= 1
    #         return 1,1
    #     else:
    #         a,b = fib(n-1)
    #         l[0] -= 1
    #         if l[0] == 0:
    #             return a+b
    #         return b,a+b
    # print(fib(50))
    # 没看懂
    def fib(n,a=1,b=1):
        if n==1 : return a
        return fib(n-1,b,a+b)
    print(fib(50))
    
    # 阶乘
        #3! 3*2*1
        # 2! 2*1
        # 1! 1
    # def fac(n):
    #     if n == 1 :
    #         return 1
    #     return n * fac(n-1)
    #
    # print(fac(100))
    
    # 附加题 :考试附加题
        # 递归实现
    

    模块

    # 模块的导入
    # 导入的时候会执行里面的语句,有print()也会输出,多次导入只调用一次
    """
    需求模块:本模块测试,print()会执行,其他文件调用,print()等不执行
    __name__:本模块名字,单若在某个模块中开始运行的,输出是__main__,否则就是文件名
    解决方法
    被调用模块中:
    def func():
        pass
    if __name__ == '__main__'
        fun()
    
    """
    
    # import xxxx  # 找到模块,读内容到专属命名空间
    # xxxx.func() xxxx.var
    # 已经导入的modules字典,所以不会重复导入  名字:路径
    # import sys
    # print(sys.modules)
    # import time as t 给模块起别名,提高兼容性
    # import time, sys, os 同时引入多个代码,但不推荐
    # 先导内置,扩展django,自己的
    # from demo import func,var 都可以
    # from demo import func as t
    # from time import *  不安全
    # 被调用的模块第一行加入 __all__ = ['var','fun']
    # 其他文件用 *导入 该模块时 只能使用 list中含有的量
    

     

    正则模块

    #正则模块
    """
    .   换行外任意字符
    w  数字字母下划线
    s  任意空白字符
    d  数字
    # 上边3个大写就是非,任意两对就是匹配全局
    
     换行
    	 制表
     匹配单词结尾,用得少,前边加些字符,不然不显示
    ^x 以x开头,只匹配一个
    () 一个组
    [^ab] ab都不匹配 ,非
    
    以上都是单个字符匹配
    * + ? 等 只约束 前面的一个规则,若有每个,都加+即可
    d* 多次匹配,空也可匹配
    d+ 匹配一次或多次
    d? 匹配一次
    
    {n} 匹配n次
    {n,m}   n到m次
    ()? ()中只出现一次
    .*?x 前边任意长度,直到出现x结束
    
    转义符匹配
    正则中\n 匹配
    
    语言中\\n 匹配
     为每个""转义
    或r'\n' 匹配
      取消""的转义功能
    """
    # re模块
    import re
    # match (从头)开始匹配,匹配上就返回一个变量,search即时在中间也可以查到
    # group显示
    # 没有匹配返回Nnoe,调用group出错
    ret = re.match('[a-z]+',"123 dzf gyg lzt")
    print(ret)
    # findall 匹配所有符合的放在列表中
    ret = re.findall("[a-z]+","dzf gyg lzt")
    print(ret)
    # search,找到第一个就返回,返回一个对象,ret.group()回去值
    # 若找不到返回None,使用group()则会报错
    ret = re.search("[a-z]+","123 dzf gyg lzt")
    print(ret.group())
    
    # 分割,先按照a,分割再按b分割
    re.split("[ab]","abcd")
    # 替换所有数字为H,若没有1 表示匹配一次
    re.sub('d',"H","cacasccass366asdas",1)
    # 返回替换后的结果 并返回次数 元祖("str",次数)
    re.subn('d',"H","cacasccass366asdas",1)
    # 编译正则表达式
    re.compile('d{3}') # 供后使用
    # 返回一个存放结果的迭代器
    ret = re.finditer("d","huoiuhizai23nusdwhjj")
    #查看
    next(ret).group() # 查看第一个
    next(ret).group() # 查看第二个
    for i in ret:  #第3个开始
        i.group()
    # 对于search group() 返回一个完整的匹配
    #   group(1) group(2) 返回其中的一部分
    
    # ret = re.findall('www.(baidu|oldboy).com', 'www.oldboy.com')
    # print(ret)  # ['oldboy']     这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可
    # 保留分组优先
    # ret = re.findall('www.(?:baidu|oldboy).com', 'www.oldboy.com')
    # print(ret)  # ['www.oldboy.com']
    
    ret=re.split("d+","eva3egon4yuan")
    print(ret) #结果 : ['eva', 'egon', 'yuan']
    
    ret=re.split("(d+)","eva3egon4yuan")
    print(ret) #结果 : ['eva', '3', 'egon', '4', 'yuan']
    
    #re.findall(x,xx,flag)
    # flag = rs.I 或略大小写
    # flag = rs.M 多行模式,改变^$的行为
    # flag = rs.S 点可以匹配换行,以及任意字符
    # flag = rs.L  做本地化识别的匹配,表示特殊字符集 s,w 等,不推荐
    # flag = rs.U 使用w w等,使用取决于unicode定义的字符属性,pythons默认使用
    # flag = rs.X 冗长模式,pattern可以是多行,忽略空白字符,可添加注释
    

    正则模块2

    # 正则表达式
    # 字符组 [字符]
    # 元字符
        # w d s
        # W D S
        # . 除了换行符以外的任意字符
        # 
     	
        # 
        # ^ $ 匹配字符串的开始和结束
        # () 分组  是对多个字符组整体量词约束的时候用的
                    #re模块:分组是有优先的
                        # findall
                        # split
        # | 从左到右匹配,只要匹配上就不继续匹配了。所以应该把长的放前面
        # [^] 除了字符组内的其他都匹配
    # 量词
        # *   0~
        # +   1~
        # ?  0~1
        # {n} n
        # {n,} n~
        # {n,m} n~m
    
    # 转义的问题
    # import re
    # re.findall(r'\s',r's')
    
    # 惰性匹配
    # 量词后面加问号
        # .*?abc 一直取遇到abc就停
    
    # re模块
    # import re
    # re.findall('d','awir17948jsdc',re.S)
    # 返回值:列表 列表中是所有匹配到的项
    
    # ret = search('d(w)+','awir17948jsdc')
    # ret = search('d(?P<name>w)+','awir17948jsdc')
    # 找整个字符串,遇到匹配上的就返回,遇不到就None
    # 如果有返回值ret.group()就可以取到值
    # 取分组中的内容 : ret.group(1)   /  ret.group('name')
    
    # match
    # 从头开始匹配,匹配上了就返回,匹配不上就是None
    # 如果匹配上了 .group取值
    
    # 分割 split
    # 替换 sub 和 subn
    # finditer 返回迭代器
    # compile 编译 :正则表达式很长且要多次使用
    
    import re
    
    # ret = re.search("<(?P<tag_name>w+)>w+</(?P=tag_name)>","<h1>hello</h1>")
    # #还可以在分组中利用?<name>的形式给分组起名字
    # #获取的匹配结果可以直接用group('名字')拿到对应的值
    # print(ret.group('tag_name'))   #结果 :h1
    # print(ret.group())             #结果 :<h1>hello</h1>
    
    # ret = re.search(r"<(w+)>w+</1>","<h1>hello</h1>")
    # #如果不给组起名字,也可以用序号来找到对应的组,表示要找的内容和前面的组内容一致
    # #获取的匹配结果可以直接用group(序号)拿到对应的值
    # print(ret.group(1))
    # print(ret.group())  #结果 :<h1>hello</h1>
    
    import re
    
    # ret=re.findall(r"d+.d+|(d+)","1-2*(60+(-40.35/5)-(-4*3))")
    # print(ret) #['1', '2', '60', '40', '35', '5', '4', '3']
    # ret.remove('')
    # print(ret)
    # ret=re.findall(r"-?d+.d*|(-?d+)","1-2*(60+(-40.35/5)-(-4*3))")
    # print(ret) #['1', '-2', '60', '', '5', '-4', '3']
    # ret.remove("")
    # print(ret) #['1', '-2', '60', '5', '-4', '3']
    
    # 首先得到一个字符串
    # 去空格
    # 没有空格的字符串
    # 先算最里层括号里的 : 找括号 ,且括号里没有其他括号
    # 得到了一个没有括号的表达式 :只有加减乘除 从左到右先找到第一个乘除法   —— 重复
    # 所有的乘除法都做完了
    # 计算加减  —— 加减法
    # 只有一个数了 就可以结束了
    

    collection

    # collections 扩展数据类型
    # 时间模块
    # random 随机数模块
    # os 操作系统
    # sys 与python解释器有关
    # 序列化模块 数据类型与str的转换
    # collections
    """
        namedtuple:
        deque:双端队列
        counter:计数器
        orderedDict:有序字典
        defaultdict:带默认值的字典
    
    """
    # 列表,字典,字符串,集合,frozenset,字符串,堆栈
    
    # namedtuple 可用名字获取值,
    #     from collections import namedtuple
    #     Point = namedtuple("point",['x','y','z'])
    #     p = Point(1,2,3)
    #     p2 = Point(1,2,3)
    #     print(p.x) # 1
    #     print(p.y) # 2
    #     print(p.z) # 3
    #     print(p) # (x=1,y=2)
    
    # 花色与数字
    #     Card = namedtuple("card",["suits","number"])
    #     c1 = Card("红桃",2)
    #     print(c1)
    # queue 队列,内容不可看
    # import queue
    # q = queue.Queue()  # q不可for,不可放多个值,但可放其他元素类型
    # q.put(10)
    # q.put(10)
    # q.put(10)
    # q.put(10)
    # print(q.get())
    # print(q.get())
    # print(q.get())  # 取内容时,若没有了,阻塞,等待再次添加,继续
    # print(q.qsize())  # 查看剩余的,
    
    # deque 双端队列,两端都可以存取
    #     from collections import deque
    #     dq = deque([1,2])
    #     dq.append('a')  # 从后边放数据[1,2,'a']
    #     dq.appendleft('b')  # 从前边放数据['b',1,2,'a']
    #     dq.insert(2,3)   # ['b',1,3,2,'a']
    #     print(dq.pop())  # 从后边取数据 a
    #     print(dq.popleft())  # 从前边取数据 b
    #     print(dq)  # deque([1, 3, 2]) 可看内容
    
    # 有序字典
    # from collections import  OrderedDict
    # 初始化时要如下定义,列表型定义,所以有序
    # od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
    # print(od) # -->OrderedDict([('a', 1), ('b', 2), ('c', 3)])
    # OrderedDict的Key是有序的
    # print(od['a']) # 仍可这样访问
    # for k in od:
    #     print(k)
    
    # defaultdict
    # from collections import defaultdict
    # d = defaultdict(lambda: 5)  # value 默认是5
    # print(d['k'])
    # d = defaultdict(list)  # 使字典的value默认为list,其他元素也可
    # d['k'].append(1)
    # print(d)
    
    # from collections import Counter
    # c = Counter("asdaquidbqu9fu9qnnaibcba")
    # print(c)  # Counter({'a': 4, 'q': 3, 'u': 3, 'b': 3, 'd': 2, 'i': 2, '9': 2, 'n': 2, 's': 1, 'f': 1, 'c': 1})
    

    time

     

    思考题,时间相减

     

    import time
    # time.sleep(100) # stop100 second
    # time.time()  # 返回s为单位的浮点数
    
    # 格式化时间  —— 字符串: 给人看的 string str
    # 时间戳时间 —— float时间 : 计算机看的 timestamp
    # 结构化时间 —— 元祖 :计算用的 struct_time
    
    # %a 简称英文星期
    # %A 全称英文星期
    # print(time.strftime("%Y-%m-%d %a %H:%M:%S"))  #year month day HOUR MINUTE SECOND
    # print(time.strftime("%Y/%m/%d %H:%M:%S"))  #year month day HOUR MINUTE SECOND
    # print(time.strftime("%m-%d %H:%M:%S"))  #year month day HOUR MINUTE SECOND
    # print(time.strftime("%H:%M:%S"))  #year month day HOUR MINUTE SECOND
    # print(time.strftime("%H:%M"))  #year month day HOUR MINUTE SECOND
    
    
    # struct_time = time.localtime()
    # print(struct_time)
    # print(struct_time.tm_year)
    
    # 时间戳和结构化时间
    # t = time.time()
    # print(t)
    # print(time.localtime(3000000000)) # 结构北京时间
    # print(time.gmtime(t)) # 结构 格林威治时间
    
    # print(time.mktime(time.localtime())) # 时间戳
    
    # print(time.strptime('2000-12.31','%Y-%m.%d')) # 转为结构化时间
    # print(time.strftime('%m/%d/%Y %H:%M:%S',time.localtime(3000000000))) # 结构化转格式化
    
    # print(time.asctime()) # asc串
    # print(time.asctime(结构化)) # 转asc
    # print(time.ctime(时间戳)) # 转asc
    
    # 思考题:两个时间相减,显示差了几年,几月,几天
    # 张天福 —— 中国茶叶之父
        # 陈味聪
        # 周天霖
    # 绿茶 : 龙井 碧螺春 竹叶青 信阳毛尖 六安瓜片 太平猴魁 安吉白茶
    # 白茶 : 福鼎白茶 银针(100%芽) 白牡丹(一芽一叶) 贡眉(一芽两叶) 寿眉(一芽三叶)
    # 黄茶 : 黄山毛峰 霍山黄芽
    
    

    random

    import random
    random.random() # 大于0小于1
    random.uniform(1,3) # 大于1 小于3
    random.randint(1,5) # 大于等于1 小于等于5
    random.randrange(1,10,2)  # 大于等于1 小于10 之间的奇数
    random.choice([1,'23',[4,5]]) # 1或'23'或[4,5] 任意一个
    random.sample([1,'23',[4,5]],2) # 任意两个组合 [[4,5],'23']
    

    os

    root,dirs,files in os.walk(path) 返回的是生成器

    第一条,root = path,dir= path里边的第一级目录,files为第一级文件,

    第二次循环,root为path的上一个循环中root中的第一个

    依次循环

    和使用os.walk(path).__next()__获取第一次记录

    import os
    os.getcwd()  # 获取当前路径
    os.chdir(r"xxxx")  # 改变当前脚本执行路径,再次getcwd()会变化
    os.curdir()  # "."
    os.pardir()  # ".."
    # os.chdir("..") = os.chdir(os.pardir())
    os.makedirs("xxx/yyy")  # 新建文件夹,级联
    os.removedirs("目录")  # 删除后,到上一级,为空就继续删除
    os.mkdir("xxx")  # 单级目录
    os.rmdir("xxx")  # 单级空目录
    os.listdir("xxx")
    os.remove("xxx")  # 删除文件
    os.rename("old","new")  #
    os.stat("path/file")  # 获取文件/目录信息 ,大小,修改时间等
    os.sep  # 路径分隔符 win \ linux / 跨平台使用
    os.linesep  # 当前终止符 win 	
     linux 
    
    os.pathsep  # 路径文件分隔符 win ; linux :
    os.name  # 字符串指示当前使用的平台 win nt; linux posix
    os.system("bash command")  # 不用打印直接输出,但无返回值
    os.popen("bash command").read()  # 获取执行结果,
    os.environ  # 环境变量
    os.path
    os.path.abspath("path")  # 返回path绝对路径
    os.path.split("path")  # 返回目录与文件名,元祖返回
    os.path.dirname("path")  # 返回path目录,不包括文件
    os.path.basename("path")  # 返回最后的文件名,若/  结尾返回空
    
    os.path.exists("path")  #True Flase
    os.path.isabs("path") # 是否是绝对路径
    os.path.isfile("path")
    
    os.path.isdir("path")  # 是否存在(目录)
    print(os.path.join("xxx","yyy","zzz")) # 拼接为 xxxyyyzzz,
    os.path.getatime("path")  # 最后访问时间
    os.path.getmtime("path")  # 最后修改时间
    os.path.getsize("path")  # 大小
    

    sys

    import sys
    sys.platform   # 返回操作系统位数
    sys.version  # 返回python版本
    sys.exit()  # 程序退出 0 正常退出,非0 不正常
    sys.path  # 所有搜索模块的路径,list,当前路径,python默认包路径等...
    sys.path.clear()  # 清空后 import os 无效
    sys.argv  #  python xxx.py a b c ;
    # 用于接收 a b c 等参数 list
    # 不用input,节省时间
    

    序列化模块

    'abdsafaslhiewhldvjlmvlvk['
    # 序列化 —— 转向一个字符串数据类型
    # 序列 —— 字符串
    
    
    "{'k':'v'}"
    
    # 数据存储
    # 网络上传输的时候
    
    # 从数据类型 --> 字符串的过程 序列化
    # 从字符串 --> 数据类型的过程 反序列化
    
    # json ***** 非常重要
    # pickle ****
    # shelve *** python3 新出现的
    
    # json  # 数字 字符串 列表 字典 元组(转为list),反序列后还是list
        # 通用的序列化格式
        # 只有很少的一部分数据类型能够通过json转化成字符串
        # 只有json,方式文件中的可读
    # pickle
        # (所有的python中的数据类型)都可以转化成字符串形式
        # pickle序列化的内容(只有python能理解)
        # 且部分反序列化依赖python代码
    # shelve
        # 序列化句柄
        # 使用句柄直接操作,非常方便
    
    
    # json dumps序列化方法 loads反序列化方法 内存数据
    # dic = {1:"a",2:'b'}
    # print(type(dic),dic) # <class 'dict'> {1:"a",2:'b'}
    # import json
    # str_d = json.dumps(dic)   # 序列化
    # print(type(str_d),str_d) #  <class 'str'> {1:"a",2:'b'}
    
    # # '{"kkk":"v"}' 字符串元素全部双引号显示
    # dic_d = json.loads(str_d) # 反序列化
    # print(type(dic_d),dic_d)
    
    import json
    # json (dump) load  文件数据
    # dic = {1:"a",2:'b'}
    # f = open('fff','w',encoding='utf-8')
    # json.dump(dic,f)
    # f.close()
    # f = open('fff') # 没中文可不用写编码
    # res = json.load(f)
    # f.close()
    # print(type(res),res)
    
    import json
    # json dump load
    # dic = {1:"中国",2:'b'}
    # f = open('fff','w',encoding='utf-8')
    # json.dump(dic,f,ensure_ascii=False) # 默认以bytes写入,改为false时可以写中文
    # json.dump(dic,f,ensure_ascii=False)
    # 可以两次写
    # f.close()
    # f = open('fff',encoding='utf-8')
    # res1 = json.load(f)
    # res2 = json.load(f)
    # f.close()
    # print(type(res1),res1)
    # print(type(res2),res2)
    # 一次读会报错
    
    
    # json
    # dumps {} -- > '{}
    '
    # 一行一行的读
    # '{}
    ' 读出来一行
    # '{}' loads 队一行loads
    # 例 逐行写入
    # l = [{'k':'111'},{'k2':'111'},{'k3':'111'}]
    # f = open('file','w')
    # import json
    # for dic in l:
    #     str_dic = json.dumps(dic)
    #     f.write(str_dic+'
    ')
    # f.close()
    # 读
    # f = open('file')
    # import json
    # l = []
    # for line in f:
    #     dic = json.loads(line.strip())
    #     l.append(dic)
    # f.close()
    # print(l) # 转回list
    
    import pickle  #
    # dic = {'k1':'v1','k2':'v2','k3':'v3'}
    # str_dic = pickle.dumps(dic)
    # print(str_dic)  #一串二进制内容
    #
    # dic2 = pickle.loads(str_dic)
    # print(dic2)    #字典
    
    # import time 文件操作时用rb,wb,(可以分部调用)
    # struct_time1  = time.localtime(1000000000)
    # struct_time2  = time.localtime(2000000000)
    # f = open('pickle_file','wb')
    # pickle.dump(struct_time1,f)
    # pickle.dump(struct_time2,f)
    # f.close()
    # f = open('pickle_file','rb')
    # struct_time1 = pickle.load(f)
    # struct_time2 = pickle.load(f)
    # print(struct_time1.tm_year)
    # print(struct_time2.tm_year)
    # f.close()
    # =======================================
    # 会产生三个临时文件,且不支持多个应用同时写
    # import shelve
    # f = shelve.open('shelve_file')
    # f['key'] = {'int':10, 'float':9.5, 'string':'Sample data'}  #直接对文件句柄操作,就可以存入数据
    # f.close()
    #
    # import shelve
    # f1 = shelve.open('shelve_file')
    # existing = f1['key']  #取出数据的时候也只需要直接用key获取即可,但是如果key不存在会报错
    # f1.close()
    # print(existing)
    # ======================================
    # 只读方式打开,本应该不能够修改,但有时候却可以修改
    # import shelve
    # f = shelve.open('shelve_file', flag='r')
    # existing = f['key']
    # print(existing) 原来内容
    # f.close()
    #
    # f = shelve.open('shelve_file', flag='r')
    # existing2 = f['key']  修改
    # f.close()
    # print(existing2) 再次打印
    # ============================================
    # 修改不生效
    import shelve
    # f1 = shelve.open('shelve_file')
    # print(f1['key'])
    # f1['key']['new_value'] = 'this was not here before'
    # f1.close()
    # writeback = True 生效, 会消耗内存, 一般都是重新建文件,写入,重命名
    f2 = shelve.open('shelve_file', writeback=True)
    print(f2['key'])
    # f2['key']['new_value'] = 'this was not here before'
    f2.close()
    # ============================================
    

    # 把解决一类问题的模块放在同一个文件夹里 —— 包'
    #      import xx.yy.zz  点的左边必须是包
    #      from xx.yy import zz
    #      from xx import yy.zz 错误
    #      例: 包1/包2/包3/文件
    #      import 包1
    #      包1.包2.包3.文件.fun()  会出错
    #      import package   会自动执行包下__init__py文件
    #      from 包1 import 包2 # 包1 下init
    #      from 包1.包2 import 包3 # 包2 init
    #      from 包1.包2.包3 import 文件 # 包3下 init
    #       import 包1
    #      包1.包2.包3.文件.fun()  此时不会出错
    #      绝对路径,直观,但移动不方便,
    #      但调用不出错,随便使用
    # ===================
    #      使用相对路径
    #      from . import 包2 # 包1 下init
    #      from . import 包3 # 包2 init
    #      from . import 文件 # 包3下 init
    #      找到包的位置,都可以使用包中的文件
    #      注意:
    #      包1/包2,包3,文件1
    #      包2中文件调用 包3中文件 运行包2下那个文件 出错
    #      若非要使用,在包2的那个文件中,添加包2的上级目录,即包1 进入sys.path
    #      包2 文件 from 包3 import 包3文件  即可使用
    #      文件1调用 包2,包3中文件 运行文件1 不出错
    #      #####文件1 调用包2文件引用文件3的那个方法(不错)
    #      包中,包中文件调用出错,只有包外部文件可调用包内文件
    #      相对路径,只能找到上层目录,但不能找到上层的上层
    #======================
    #       还有* 与__all__ 配合使用
    #=======================================
    # 总之,最重要的一点 from 或 import 包,文件的时候,看他是否在sys.path 中
    #=======================================
    # import os
    # os.makedirs('glance/api')
    # os.makedirs('glance/cmd')
    # os.makedirs('glance/db')
    # l = []
    # l.append(open('glance/__init__.py','w'))
    # l.append(open('glance/api/__init__.py','w'))
    # l.append(open('glance/api/policy.py','w'))
    # l.append(open('glance/api/versions.py','w'))
    # l.append(open('glance/cmd/__init__.py','w'))
    # l.append(open('glance/cmd/manage.py','w'))
    # l.append(open('glance/db/models.py','w'))
    # map(lambda f:f.close() ,l)
    
    # import glance.api.policy as policy
    # policy.get()
    #
    # from dir.glance.api import policy
    # policy.get()
    
    # import sys
    # sys.path.insert(0,'C:\Users\Administrator\PycharmProjects\s9\day21\dir')
    # # print(sys.path)
    # from glance.api import policy
    # policy.get()
    
    # from dir import glance
    # glance.db.models.register_models('mysql')
    # glance.api.policy.get()
    
    # 使用绝对路径 不管在包内部还是外部 导入了就能用
    # 不能挪动,但是直观
    
    # from dir import glance
    # glance.api.policy.get()
    # 相对路径
    # 可以随意移动包 只要能找到包的位置,就可以使用包里的模块
    # 包里的模块如果想使用其它模块的内容只能使用相对路径,使用了相对路径就不能在包内直接执行了
    
    # bin
    #   start.py
    # conf
    #   config.py
    #   my_log_setting.py
    #   setting.py
    # core 核心代码
    #   core.py
    # db 数据信息
    #   alex_json
    #   dzf_json
    # lib 自定义模块,三方模块
    #   read_ini.py
    # log
    #   access_log
    #   error_log
    

    异常处理

    # 语法错误,逻辑错误
    # 1/0
    # name
    # 2+'3'
    # [][3]
    #{}['k']
    # =========================================================
    # try:
    #     print('1111')
    #     # 1/0
    #     print('2222')
    #     # name
    #     # 2+'3'
    #     # [][3]
    #     # {}['k']
    #     ret = int(input('number >>>'))
    #     print(ret*'*')
    # except ValueError:
    #     print('输入的数据类型有误')
    # except Exception:
    #     print('你错了,老铁')
    # else:
    #     print('没有异常的时候执行else中的代码') # 正常执行完后执行,异常终止时,不处理
    # =========================================================
    # def func():
    #     try:
    #         f = open('file','w')
    #         ''''''
    #         return True
    #     except:
    #         return False
    #     finally:
    #         print('执行finally了')
    #         f.close()
    #
    # print(func())
    
    
    
    
    
    # 程序一旦发生错误,就从错误的位置停下来了,不在继续执行后面的内容
    # 使用try和except就能处理异常
        #try是我们需要处理的代码
        #except 后面跟一个错误类型 当代码发生错误且错误类型符合的时候 就会执行except中的代码
        #except支持多分支
        #有没有一个能处理所有错误的类型 : Exception
            # 有了万能的处理机制仍然需要把能预测到的问题单独处理
            # 单独处理的所有内容都应该写在万能异常之前
        # else : 没有异常的时候执行else中的代码
        # finally : 不管代码是否异常,都会执行
            # finally和return相遇的时候 依然会执行
            # 函数里做异常处理用,不管是否异常去做一些收尾工作 f.close,会先执行finally 再return
    
    
    # try:
    #     main()
    # except Exception:
    #     pass
    
    try:
        print('1111')
        # 1/0
        print('2222')
        # name
        # 2+'3'
        # [][3]
        # {}['k']
        ret = int(input('number >>>'))
        print(ret*'*')
    except Exception as error:  # 可输出错误信息
        print('你错了,老铁',error)
    

    面向对象

    # 面向对象编程
    # 所谓模子 就是 类 抽象的 我能知道有什么属性 有什么技能 但不能知道属性具体的值
    # jin alex nezha 就是对象 有具体的值,属性和技能都是根据类规范的
    # 自定义类
    # def 函数名():
    #     pass
    #=================
    # class 类名:
    #     属性 = 'a'
    #=================
    # print(类名.属性)
    # 类名的作用 就是操作属性 查看属性
    #==============================
    # class Person:                 # 类名
    #     country = 'China'         # 创造了一个只要是这个类就一定有的属性
    #                               # 类属性 静态属性
    #     def __init__(self,*args):  # 初始化方法,self是对象,是一个必须传的参数,等于构造方法
    #         # self就是一个可以存储很多属性的大字典 ,等于this, __dict__
    #         self.name = args[0]   # 往字典里添加属性的方式发生了一些变化
    #         self.hp = args[1]
    #         self.aggr = args[2]
    #         self.sex = args[3]
    #
    #     def walk(self,n):         # 方法,(一般情况下必须传self参数),且必须写在第一个
    #                               # 后面还可以传其他参数,是自由的
    #         print('%s走走走,走了%s步'%(self.name,n))
    #========================================
    # 静态属性查看
    # # print(Person.country)        # 类名 可以查看类中的属性,不需要实例化就可以查看
    #========================================
    #  普通属性查看
    # alex = Person('狗剩儿',100,1,'不详')  # 类名还可以实例化对象,alex对象   # 实例化
    # print(alex.__dict__) # 查看所有属性
    # print(alex.name)  # 查看属性值
    # print(alex.hp)  # 查看属性值
    #================================================
    # 方法调用
    # alex.walk(5) # 都可以调用
    # Person.walk(alex,5)  # 调用方法 类名.方法名(对象名)
    #================================================
    # print(Person.__dict__['country']) # 查看静态属性
    # Person.__dict__['country'] = '印度'
    # print(alex.__dict__['name'])
    # alex.__dict__['name'] = '二哥'
    # print(alex.__dict__)
    # print(alex.name)
    # print(alex.name)
    # alex.name = '二哥'
    # alex.__dict__['name'] = '二哥'
    # alex.age = 83
    # print(alex.__dict__)
    # print(alex.name)
    
    # 对象 = 类名()
    # 过程:
        # 类名() 首先 会创造出一个对象,创建了一个self变量
        # 调用init方法,类名括号里的参数会被这里接收
        # 执行init方法
        # 返回self
    # 对象能做的事:
        # 查看属性
        # 调用方法
        # __dict__ 对于对象的增删改查操作都可以通过字典的语法进行,only contain dynamic attributes
    # 类名能做的事:
        # 实例化
        # 调用方法 : 只不过要自己传递self参数
        # 调用类中的属性,也就是调用静态属性
        # __dict__ 对于类中的名字只能看 不能操作,用"."可以操作
    
    # 几乎与java类似
    # 定义类
    # init方法
    # self是什么 self拥有属性都属于对象
    # 調用類的時候創建self,是一個空的對象,有init初始化
    # 类中可以定义静态属性
    # 类中可以定义方法,方法都有一个必须传的参数self
    # 实例化
    # 实例、对象
    # 对象查看属性
    # 对象调用方法
    
    # 命名空間
    # class has static attribute,function
    # object has owner namespace,attribute not (contain static) attribute and a pointer to class,
    #   beacuse it, if you change class static attribute by obj , equal you change memory address ,if the attr is str,int and so on
    #   you will only change the one obj,it will add a dynamic attribute in obj’s __dict__
    #   if the static is list ,dict and so on, all obj and the static attr will be changed
    # object execute the static attribute ,but can't find it ,will find it in class namespace
    

    面向对象2

    
    

     

     

     

     

     

    # 导入包的时候,相当于实例化对象,对调用__init__ 在进行方法使用
    # 面向对象:继承 多态 封装
    # =======================
    # 继承:单继承与多继承(独有)
    # 父类,超类,基类
    # 子类,派生类
    # class Person:pass
    # class Substance:pass
    # class Student(Person,Substance):pass
    #
    # print(Student.__bases__)  # (<class '__main__.Person'>, <class '__main__.Substance'>)
    # print(Person.__bases__)  # (<class 'object'>,) python3中,没有显示继承类,都默认继承object类
    
    # class Animal:
    #     def __init__(self,name,aggr,hp):
    #         self.name = name
    #         self.aggr = aggr
    #         self.hp = hp
    #         self.func() # 子类的fun
    #     def func(self):
    #         print(123)
    # #
    # class Dog(Animal):
    #     def func(self):
    #         print(456)
    #     def bite(self,person):
    #         person.hp -= self.aggr
    # d1 = Dog("dzf",1)
    # print(d1)
    # 子类没有init 会默认执行父类的init ,即把参数传给父类的init 注意与java不同
    # 对于方法的重写,与java相同,字节实现自己的方法若要包含父类的方法Father.fun(self)即可 python3 中 有super
    # super().__init__(x,x) 此种也可以,不用传递self
    # super(原对象,self) 这两个参数是省略的
    # 在类外部super(x,self).fun() 可调用x父类的fun方法
    # 当子类有init时 调用自己的, super(x,y,x) ----> Father.__init__(self,x,y);self.z=z
    # 推荐使用单继承,设计模式中 使用多继承,不常用
    
    # 多继承
    # 子类继承父类方法,并重写,切父类都有这个方法
    # 父类的方法时,会按照次序,先自己,从左向右调用父类的
    # 经典问题:钻石继承问题 图1,3
    #      此时同父类:A B,C 继承A ,D继承BC, D调用方式,先按照顺序BC,再A
    #       先广度找,再深度,广度优先 bc
    #       若 B 继承A, C继承F D继承bc, 此时先 b  a 再 c d
    #        即若后边可以找到,就放在后边找,
    #     按照(广度)优先遍历算法 ,不能重复 2
    # python2中按照深度优先查找,一条路到黑
    #  注意super() 再多继承时调用的不是父类的方法,而是按照查找顺序 调用 图4
    # Class.mro() 列表返回class 到object 的继承顺序
    # class A:pass
    # class B(A):pass
    # class C(A):pass
    # class D(B):pass
    # class E(C):pass
    # class F(D,E):pass
    #
    # print(F.mro())
    
    # 接口类:原生不支持
    # 抽象类:原生支持
    # from abc import abstractmethod,ABCMeta # 装饰器
    # class Payment(metaclass=ABCMeta):
    #     @abstractmethod
    #     def pay(self,x):
    #         pass
    # 规范
    # 接口类,默认多继承,接口类中所有方法都要不实现(pass)
    # 抽象类,不支持多继承,里面方法可以有一些实现 ,当两者书写形式相同
    # 其他类继承时 必须要实现
    # 接口隔离,一个接口与一个方法
    # 本是没有接口的,因为自带多继承,通过这种方式模拟,接口 抽象类
    # 与java相同,二者不能实例化
    
    # python 天生支持多态 不用通过第三个类,实现一起调用
    #  鸭子类型:依赖父类的情况下实现两个同名方法
    # 封装性,隐藏属性,方法
    class Person:
        def __init__(self,name,passwd):
            self.name=name
            self.__passwd = passwd # 属性以双下划线开头 即为私有属性
    dzf = Person("dzf","123456")
    print(dzf)
    print(dzf.name)
    # print(dzf.passwd) # 打印出错
    print(dzf.__dict__) # -->{'name': 'dzf', '_Person__passwd': '123456'}能查看
    # 私有属性变为 “_类名属性名
    # 对于方法相同,双下划线开头即为私有方法
    # 静态属性也可定义为私有的
    print(dzf._Person__passwd) # 能查到
    # 没有真的约束,只是代码级别变形,外部通过——类名——名字 直接调用 内部——名字调用
    
    
    # 父类的私有属性,子类不能调用(静态属性),
    

     

    面向对象3

    # isinstance(object,cls) # obj 是不是cls的子类
    # issubclass(sub,super) sub 是super的子类
    # __dict__ 类中中有方法,有属性,但方法不能通过dict执行
    #   对象的__dict__只有属性
    # sys.modules 列表显示模块简称:位置
    # sys.modules['__main__'] 获取当前模块
    
    # getattr(sys.modules['__main__'],xxx) # 从当前模块反射,防止其他模块重名反射
    # 但一般不用__main__ 防止其他模块引用,用___name__代替
    # 反射还可以拿到模块中的类,加括号 表示实例化
    
    
    # 类中的内置方法,__init__,__str__,__repr__等,后两个必须返回字符串
    # str(obj) -->obj.__str__   等同于toString() 方法,默认情况继承object 打印地址
    # __repr__ ,父类的一样也是打印地址
    # %s 按照 __str__
    # %r 按照__repr__
    # repr 是str的备胎,若没有str,会找本类repr, 再找父类str,
    # 但str不是repr的备胎,找不到子类repr 直接找父类repr   一般都实现repr
    #内置方法很多,不一定都在obj  __len__
    
    
    # del 析构函数
    # def __del__():pass
    # del obj   先执行这个方法,再删除,即时不del 会在解释器结束的时候,调用del
    
    # __call__ 方法
    # a = A()()---> a()--->执行a的call方法,若没有则报错
    
    # item系列
    # class中实现item,可以通过 a['name']=a.name
    #   def __getitem__(self,item):
    #       if(hasattr(self,item))
    #           return getattr(self,item)
    # f[item(属性名)]
    # setitem
    # def __setitem__(self,key,value): # 修改属性
    #     self.__dict__[key] = value
    
    # 实现setitem,getitem后即可切片
    
    # delitem
    # 正常情况 del cls.name 对应的是 __delattr__(self,item):self.__dict__pop(item)  object原生的
    # def __delitem__(self,item):
    #     del self.__dict__[item]
    
    #
    # __init__  初始化方法
    # __new__构造方法:创建一个对象,不常用
    # def __new__(cls,*args,**kwargs):
    #       return object.__new__(类名,*args,**kwargs) # 这两个参数可以不加,加了可能报错 此时没有self, 创建后给init
    # 先执行new方法,再init
    
    # 一个类 始终 只有 一个 实例
    # 当你第一次实例化这个类的时候 就创建一个实例化的对象
    # 当你之后再来实例化的时候 就用之前创建的对象
    
    # class A:
    #     __instance = False
    #     def __init__(self,name,age):
    #         self.name = name
    #         self.age = age
    #     def __new__(cls, *args, **kwargs):
    #         if cls.__instance:
    #             return cls.__instance
    #         cls.__instance = object.__new__(cls)
    #         return cls.__instance
    #
    # egon = A('egg',38)
    # egon.cloth = '小花袄'
    # nezha = A('nazha',25)
    # print(nezha)
    # print(egon)
    # print(nezha.name)
    # print(egon.name)
    # print(nezha.cloth)
    
    # __eq__
    #   默认对象"="比较 返回地址比较结果,写了__eq__之后 "=" 机会按照eq   与java不同
    #   is 比较的是地址,不绑定方法,当值str等直接存值的类型时,相同则返回True,其他类型 比较地址
    
    # hash() 绑定__hash__ hash()中的是按照内存地址hash
    #   通过修改__hash__ 可自定义hash,对于不可变类型,hash值相同
    
    
    # nametuple 相当于创建一个类
    list1 =[1,2,3]+list('JQKA')
    print(list1)
    from random import shuffle # 打乱顺序,依赖__len__方法 ,__setitem__方法
    shuffle(list1)
    print(list1)
    
    # set去重依赖hash() 与 eq方法
    

    property

    # property
    # 内置装饰器函数 只在面向对象中使用,没什么其他的作用
    from math import pi
    class Circle:
        def __init__(self,r):
            self.r = r
        @property
        def perimeter(self):
            return 2*pi*self.r
        @property
        def area(self):
            return self.r**2*pi
    
    # c1 = Circle(5)
    # print(c1.area)     # 圆的面积
    # print(c1.perimeter) # 圆的周长
    
    # class Person:
    #     def __init__(self,name,high,weight):
    #         self.name = name
    #         self.high = high
    #         self.weight = weight
    #     @property
    #     def bmi(self):
    #         return self.weight / self.high**2
    
    # jin = Person('金老板',1.6,90)
    # jin.bmi = 18    # 当做属性时,不能修改
    # classmethod
    # staticmethod
    
    # class Person:
    #     def __init__(self,name):
    #         self.__name = name
    #     @property  #   当做属性
    #     def na(self):
    #         return self.__name + 'sb'
    #     @na.setter  # 设置setter方法   3个na必须一致
    #     def na(self,new_name):
    #         self.__name = new_name
    #
    # tiger = Person('泰哥')
    # print(tiger.name)
    # tiger.name = '全班' # 可修改
    # print(tiger.name)
    
    # class Goods:
    #     discount = 0.8
    #     def __init__(self,name,price):
    #         self.name = name
    #         self.__price = price
    #     @property
    #     def price(self):
    #         return self.__price * Goods.discount
    # apple = Goods('苹果',5)
    # print(apple.price)
    
    # 属性 查看 修改 删除
    # class Person:
    #     def __init__(self,name):
    #         self.__name = name
    #         self.price = 20
    #     @property
    #     def name(self):
    #         return self.__name
    #     @name.deleter  # 属性删除
    #     def name(self):
    #         del self.__name
    #     @name.setter
    #     def name(self,new_name):  # 只能定义一个参数
    #         self.__name = new_name
    # brother2 = Person('二哥')
    # del Person.price
    # brother2.name = 'newName'
    # brother2
    # del brother2.name
    # print(brother2.name)  # 查看报错  ,实际是私有的属性__name 没有了,调用了delete 内部语句  2个name()还存在
    # 函数属于类,对象不能删除函数
    

     

    反射

    #反射 *****
    # name = 'alex'
    # 'name'
    
    class Teacher:
        dic = {'查看学生信息':'show_student','查看讲师信息':'show_teacher'}
        def show_student(self):
            print('show_student')
    
        def show_teacher(self):
            print('show_teacher')
    
        @classmethod
        def func(cls):
            print('hahaha')
    alex = Teacher()
    # getattr(Teacher,'fun') # 只能获静态属性,类方法,(静态方法也可)返回方法地址,
    # func = getattr(alex,'show_student')   # 获取对象属性,变量  方法,动态属性
    # func() 加括号即可调用
    # 没有get到会报错
    
    # hasattr getattr delattr
    # if hasattr(Teacher,'dic'):
    #     ret = getattr(Teacher,'dic')   # Teacher.dic   # 类也是对象
    # # ret2 = getattr(Teacher,'func')         # 类.方法  teacher.func
    # # ret2()
    #     print(ret)
    
    # 通过反射
    # 对象名 获取对象属性 和 普通方法
    # 类名 获取静态属性 和类方法 和 静态方法
    
    # 普通方法 self
    # 静态方法 @staticmethod
    # 类方法 @classmethod
    # 属性方法 @property
    

    class_static_method

    # method 方法
    # staticmathod  静态的方法 ***
    # classmethod   类方法    ****
    # 类的操作行为
    # class Goods:
    #     __discount = 0.8
    #     def __init__(self,name,price):
    #         self.name = name
    #         self.__price = price
    #     @property
    #     def price(self):
    #         return self.__price * Goods.__discount
    #     @classmethod   # 把一个方法 变成一个类中的方法,这个方法就直接可以被类调用,不用传入对象
    #     def change_discount(cls,new_discount):  # 修改折扣,默认传入cls 表示类
    #         cls.__discount = new_discount
    # apple = Goods('苹果',5)
    # print(apple.price)
    # Goods.change_discount(0.5)   # Goods.change_discount(Goods) 默认传入cls
    # print(apple.price)
    # 当这个方法的操作只涉及静态属性的时候 就应该使用classmethod来装饰这个方法
    
    # java
    class Login:
        def __init__(self,name,password):
            self.name = name
            self.pwd = password
        def login(self):pass
    
        @staticmethod
        def get_usr_pwd():   # 静态方法 ,与类没有关系,不用传入cls
            usr = input('用户名 :')
            pwd = input('密码 :')
            Login(usr,pwd)
    
    Login.get_usr_pwd()
    # 在完全面向对象的程序中,
    # 如果一个函数 既和对象没有关系 也和类没有关系 那么就用staticmethod将这个函数变成一个静态方法
    # 类方法和静态方法 都是类调用的
    # 对象可以调用类方法和静态方法么?   可以   一般情况下 推荐用类名调用,与java相同
    # 类方法 有一个默认参数 cls 代表这个类  cls
    # 静态方法 没有默认的参数 和普通函数一样
    

    常用模块

    hashlib

    # import hashlib
    # md5 = hashlib.md5(bytes("盐值",encoding="utf8")) # 加颜值 sha1,sh3_224,sha3_512
    # md5.update(b'dzf123') # 只能使用bytes类型,
    # md5.update(b"123") # 支持分批加密
    # print(md5.hexdigest()) #16进制
    # 设置颜色
    """
        33[显示方式;前景色;背景色m; xxx  33[0m
        前:30-37 黑红绿黄,蓝紫青白
        背:40-47 黑红绿黄,蓝紫青白
        显示方式:0 终端默认显示
            1 高亮显示
            4 使用下划线
            5 闪烁  (不好用)
            7 反白显示
            8 不可见
    """
    # print("33[0;40;37m dzf 33[0m")
    # menu  = [('a',2),('b',4),('c',6)]
    # for i,j in enumerate(menu,1):
    #     print(i,j)  # i 表示序号,j 每一个元祖
     
    

    logging

    # logging 日志模块
    # 有5种级别的日志记录模式 :
    # 两种配置方式:basicconfig 、log对象
    # logging.debug('debug message')       # 低级别的 # 排错信息
    # logging.info('info message')            # 正常信息 ,默认info向上,不包括info
    # logging.warning('warning message')      # 警告信息
    # logging.error('error message')          # 错误信息
    # logging.critical('critical message') # 高级别的 # 严重错误信息
    # =============================================================
    # format 中参数
    # name Logger的名字
    # levelno 数字形式日志级别
    # levelname 文字形式日志级别
    # pathname 日志输出模块的完整路径
    # filename 日志输出函数的模块的文件名
    # module 日志输出函数的模块名
    # funcName 日志输出函数的函数名
    # lineno 行号
    # created 当前时间,unix 浮点数表示
    # relativeCreated 自logger创建以来的毫秒数
    # asctime 当前时间 默认格式:"2019-08-16 21:20:20,875" 毫秒
    # thread 线程ID ,可能没有
    # threadName 线程Nname ,可能没有
    # process 进程ID ,可能没有
    # message 用户输出的消息
    # =============================================================
    # basicconfig 简单 能做的事情相对少
        # 中文的乱码问题,好像还不能解决
        # 不能同时往文件和屏幕上输出
    # import logging
    # level=logging.WARNING # 表示警告及以上的
    # logging.basicConfig(level=logging.WARNING,
    #                     format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
    #                     datefmt='%a, %d %b %Y %H:%M:%S',
    #                     filename="log.log",
    #                     filemode="a")
    # try:
    #     int(input('num >>'))
    # except ValueError:
    #     logging.error('输入的值不是一个数字')
    # print("%(x)s"%{"x":"value"})  # 传入x ,值为value
    # print("%s"%("x"))  # 传入x ,值为value
    # =================================================================
    # 配置log对象 稍微有点复杂 能做的事情相对多
    import logging
    logger = logging.getLogger()  # 创建对象
    fh = logging.FileHandler('log.log',encoding='utf-8')  # 打开文件
    sh = logging.StreamHandler()    # 创建一个屏幕控制对象
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    formatter2 = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s [line:%(lineno)d] : %(message)s')
    # 文件操作符 和 格式关联
    fh.setFormatter(formatter)
    sh.setFormatter(formatter2)
    # logger 对象 和 文件操作符 关联
    logger.addHandler(fh)
    logger.addHandler(sh)
    logging.debug('debug message')       # 低级别的 # 排错信息
    logging.info('info message')            # 正常信息
    logging.warning('警告错误')      # 警告信息
    logging.error('error message')          # 错误信息
    logging.critical('critical message') # 高级别的 # 严重错误信息
    

    configparser

    # configparser处理配置文件
    import configparser
    # 写文件
    config = configparser.ConfigParser()  #  实例化
    config["DEFAULT"] = {'ServerAliveInterval': '45',
                          'Compression': 'yes',
                         'CompressionLevel': '9',
                         'ForwardX11':'yes'
                         }
    config['bitbucket.org'] = {'User':'hg'}
    config['topsecret.server.com'] = {'Host Port':'50022','ForwardX11':'no'}
    with open('example.ini', 'w') as f:
       config.write(f)
    """效果:
    [DEFAULT]
    serveraliveinterval = 45
    compression = yes
    compressionlevel = 9
    forwardx11 = yes
    
    [bitbucket.org]
    user = hg
    
    [topsecret.server.com]
    host port = 50022
    forwardx11 = no
    """
    
    # import configparser
    #
    # config = configparser.ConfigParser()
    # #---------------------------查找文件内容,基于字典的形式
    # # priprint(config.sections())        # ---> []
    # ==============================
    # config.read('example.ini')
    # print(config.sections())        # --->  ['bitbucket.org', 'topsecret.server.com']  default 默认不显示
    # 只要有就会用上
    # print('bytebong.com' in config) # False
    # print('bitbucket.org' in config) # True
    # ===============================
    # print(config['bitbucket.org']["user"])  # hg
    # print(config['DEFAULT']['Compression']) #yes
    # print(config['topsecret.server.com']['ForwardX11'])  #no
    # ==============================
    # print(config['bitbucket.org'])          # <Section: bitbucket.org> 地址,不是里边的全部
    #
    # for key in config['bitbucket.org']:     # 注意,有default会默认default的键,不管循环那个default都会打印
    #     print(key)
    # print(config.options('bitbucket.org'))  # 同for循环,找到'bitbucket.org'下所有键
    # =============================
    #
    # print(config.items('bitbucket.org'))    #找到'bitbucket.org'下所有键值对
    #   列表返回,元祖,元祖中2各元素,key,value
    # print(config.get('bitbucket.org','compression')) # yes       get方法Section下的key对应的value
    # ==================================
    # 修改
    # import configparser
    # config = configparser.ConfigParser()
    # config.read('example.ini')   # 读文件
    # config.add_section('yuan')   # 增加section
    # config.remove_section('bitbucket.org')   # 删除一个section
    # config.remove_option('topsecret.server.com',"forwardx11")  # 删除一个配置项
    # config.set('topsecret.server.com','k1','11111')
    # config.set('yuan','k2','22222')
    # f = open('new2.ini', "w")
    # config.write(f) # 写进文件,注意不是原文件修改,改后重新写入
    # f.close()
    

    socket

     

    # socket 应用层与传输层之间的抽象层
    # 操作网络的接口
    #   基于文件(本地通信),网络
    # AF_INET ipv4(常用)
    import socket
    sk = socket.socket()
    # sock.setsockopt(socket.SQL_SOCKET,socket.SO_REUSEADDR,1)  # 服务重启时,可能端口未释放,报错,通过词此语句解决
    # 报错socket没有SQL_SOCKET 不知道怎么回事,可能是版本问题
    sk.bind(("127.0.0.1",8089)) # 只有一个参数,元祖,传入元祖
    sk.listen() # listen(n) 表示最大连接数,默认不限制
    conn,addr = sk.accept() # 接收到连接,返回连接对象,对方addr
    ret = conn.recv(1024) # 接受对方数据
    print(ret)
    conn.send(b'hello world') # 必须bytes 不能发空b'' 否则一直等待
    conn.send(bytes("段志方",encoding="utf8")) # 必须bytes 不能发空b'' 否则一直等待
    conn.close()  # 关闭连接
    sk.close() # 关闭socket
    # 发送发发送一次,接收方对于未接收完的字节可多次接受
    # 但发送方 发送多次,接收方 要接受多次,不能一次接受
    
    
    
    import socket
    sk = socket.socket()
    sk.connect(("127.0.0.1",8089))  # 对方的信息
    # socket.connect(("106.15.39.74",80))  # 对方的信息
    sk.send(b'dzf')
    ret = sk.recv(1024)
    ret2 = sk.recv(1024)
    print(ret,ret2.decode("utf8"))
    sk.close()
    

    udp

    # accept 与recv(1024) 都会阻塞,参数不写报错
    import socket
    msg = """
    <html>
    
        <head>
            <title>first tcp test</title>
            <meta charset="utf8"/>
        </head>
        <body>
            Hello,段志方!
        </body>
    </html>
    """
    msg = bytes(msg,encoding="utf8")
    sk =socket.socket()
    sk.bind(("127.0.0.1",80))
    sk.listen()
    while True:
        conn,addr=sk.accept()
        ret = conn.recv(1024)
        print(ret)
        conn.send(msg)
        conn.close()  # 若此时不关连接其他无法接入
    sk.close()
    
    # sk = socket.socket(type=socket.SOCK_DGRAM) # datagram
    # sk.bind(("127.0.0.1",80))
    # rece,addr = sk.recvfrom(1024) # 只能先接受消息
    # print(rece.decode("gbk"))
    # sk.sendto(b"hello",addr)
    # sk.close()
    # 服务器被动接收连接,自带地址,发信息时必须携带对方地址
    
    
    import socket
    # sk = socket.socket(type=socket.SOCK_DGRAM)
    # ip_port = ("127.0.0.1",80)
    # sk.sendto(b"hello",ip_port)
    # ret,addr = sk.recvfrom(1024)
    # print(ret)
    # sk.close()
    
    # 客户端执行 服务器发的系统命令
    # op.popen() 返回执行后的信息,错误的,正确的
    import subprocess
    # 错误信息,正确信息,放入管道
    res = subprocess.Popen("runas /user:Administrator ipconfig",shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    print("stdout:",res.stdout.read().decode("gbk"))
    print("sterr:",res.stderr.read().decode("gbk"))
    
    # 黏包 tcp   短时间间隔 发送短消息,tcp 会合并发送
    #       大小有限制,一次发送太多数据,一次拿不完,要多次
    # udp 无黏包,有包大小限制65507,若sendto大于它,会直接报错
    
    # socket 应用层与传输层之间的抽象层
    # 操作网络的接口
    #   基于文件(本地通信),网络
    # AF_INET ipv4(常用)
    import socket
    sk = socket.socket()
    # sock.setsockopt(socket.SQL_SOCKET,socket.SO_REUSEADDR,1)  # 服务重启时,可能端口未释放,报错,通过词此语句解决
    # 报错socket没有SQL_SOCKET 不知道怎么回事,可能是版本问题
    sk.bind(("127.0.0.1",8089)) # 只有一个参数,元祖,传入元祖
    sk.listen() # listen(n) 表示最大连接数,默认不限制
    conn,addr = sk.accept() # 接收到连接,返回连接对象,对方addr
    ret = conn.recv(1024) # 接受对方数据
    print(ret)
    conn.send(b'hello world') # 必须bytes 不能发空b'' 否则一直等待
    conn.send(bytes("段志方",encoding="utf8")) # 必须bytes 不能发空b'' 否则一直等待
    conn.close()  # 关闭连接
    sk.close() # 关闭socket
    # 发送发发送一次,接收方对于未接收完的字节可多次接受
    # 但发送方 发送多次,接收方 要接受多次,不能一次接受
    

    黏包

    # import socket
    # sk = socket.socket()
    # sk.bind(("127.0.0.1",80))
    # sk.listen()
    # conn,addr=sk.accept()
    # ret=conn.recv(2)
    # ret2=conn.recv(1024)
    # tcp:若客户端只发送一次,服务器两次接受,  不知道对方发送的长度
    # tcp:连发两次,服务器可能一次接受(优化算法,连续小数据包会合并)
    #       客户端,断开后,默认给服务器发空消息
    # udp :服务器只接受一次,且只接受两个,剩余的就不接受了
    # =========================================
    # 黏包
    #   两个send 小数据
    #   两个recv 第一个接受的特别小
    # 本质上 不知道要接受多大数据
    # 解决方法:发送一下数据长度,在发送数据,
    #   优点:确定接受多大数据,
    #       可在配置项 设置, 一般防止多个连接情况 最大4MB
    #       当要发送大数据时,明确告诉接收方多大,用于接受数据
    #       用在多文件传输
    #       大文件传输,一般读固定的字节
    #       发送前 xxx send(4096)
    #       recv xxx recv(2048) 知道xxx变为0
    #   缺点:多一次交互
    #   但注意,send,sendto 一定量数据都会报错
    
    # 解决方法struct
    import struct
    # 将数字或其他类型数据,转为固定长度的bytes 4个字节,其中可能包含字母,符号
    ret = struct.pack("i",4096)  # 模式,"i"代表将数字转换为bytes
    print(ret)
    num = struct.unpack("i",ret)
    print(num)  # (4096,)  返回元祖,通过num[0] 获取数字
    
    
    """
    发送方:data
        sk.send(struct.pack("i",len(data)))
        sk.send(data)
    接收方:
        num = sk.recv(4)
        sk.recv(int(num))
    """
    
    # 自定义报文头
    # 自己定义前n个字节存放报头信息
    
    

    server_socket

    # socket server
    import socketserver
    class Myserver(socketserver.BaseRequestHandler):
        def handle(self): # self.request == conn
            while True:
                msg = self.request.recv(1024).decode("utf8")
                if msg=='q':
                    break
                print(msg)
                info = input(">>>")
                self.request.send(bytes(info,encoding="utf8"))
    if __name__ == "__main__":
        server = socketserver.ThreadingTCPServer(("127.0.0.1",8080),Myserver)
        server.serve_forever()
    

    socket其他方法

    sk =socket.socket()
    sk.setblocking(False)
    sk....
    sk.accept() # 会直接执行,经错此语句时若没有连接会报错,可用try,revc 方法也不会阻塞
    
    
    
    sk.sendall() # 一次性发送全部数据
    sk.send() # 分次发送,建议使用send
    
    
  • 相关阅读:
    Android 列表布局制作表格
    Android 启动界面切换
    Android的MVC框架 [转]
    Eclipse花括号左边对齐
    Android 开发在Eclipse提示信息 This element neither has attached source nor attached Javadoc
    onItemClick 参数
    [转载] JQuery设计思想(一)
    当导航在显示范围外浮动在窗口顶部随窗口变化位置发生变化
    把一般的查询sql处理成分页用的sql
    GridControl 添加 GroupSummary
  • 原文地址:https://www.cnblogs.com/Dean0731/p/11661174.html
Copyright © 2020-2023  润新知