疯狂python讲义学习笔记——前十章完结

#第一章:绪论
#单行注释
'''
多行注释
'''
"""
多行注释
"""

#dir列出指定类或模块的属性与方法,help查看某个函数或方法的帮助文档
print(dir(str))
print(help(str.title))



#第二章:数据类型
a=5
print(type(a))#<class 'int'>
b=5.
print(type(b))#<class 'float'>
c=None
print(type(c))#<class 'NoneType'>
d='abc'
print(type(d))#<class 'str'>
e=str(a)+d
print(e,repr(e),e[1],e[-2],len(e))#5abc '5abc' a b 4
f=''' "I am " a good 'boy' '''
print(type(f),f[11:13])#<class 'str'> go
print('od' in f)#True
print('aa' not in f)#True

#输出(好像装了torch后不能Input,算了,反正也用不着控制台)
import sys
f=open("GJL.txt",'w')
print(a,b,sep='c',end='',file=f,flush=False)#5c5.0
print(a,b,sep=' ',end='\n',file=sys.stdout,flush=False)#5 5.0
#separate分隔符,end结束符,file输出到哪,flush缓冲

#变量名:字母数字下划线,不可数字打头不可如下关键字,可内置函数名但会覆盖
import keyword
print(keyword.kwlist)
'''
['False'假, 'None'空值, 'True'真, 'and'与, 'as'作为, 'assert'异常, 
'break'中断, 'class'类, 'continue'继续, 'def'定义, 'del'删除, 
'elif'否则若, 'else'否则,'except'异常, 'finally'最终, 'for'循环, 
'from'从, 'global'全局, 'if'如果, 'import'导入, 'in'里, 'is'是, 
'lambda'匿名函数,'nonlocal'非本地, 'not'否, 'or'或, 'pass'省略, 
'raise'异常, 'return'返, 'try'异常,'while'当, 'with'伴随, 'yield'生成器]
'''

#转义字符
s='F:\ProjectPython\hello_test'
print(s)#无转义字符
s='F:\rojectPython\bello_test'
print(s)#有转义字符
s=r'F:\rojectPython\hello_test'
print(s)#取消转义字符
'''转义字符
\b退格退一空格,\n换行下一行,\r回车回行首,\t制表输入四个空格
\"双引,\'单引号,\\反斜线
'''

#str封装类的方法
ss='   abc def   '
print(repr(ss.title()))#'   Abc Def   ' 
print(repr(ss.upper()))#'   ABC DEF   '
print(repr(ss.lower()))#'   abc def   '
print(repr(ss.strip()))#'abc def'
print(repr(ss.lstrip()))#'abc def   '
print(repr(ss.rstrip()))#'   abc def'
ss='I love GJL'
print(ss.startswith('I'))#True
print(ss.endswith('GJL'))#True
print(ss.find('o'))#3,找不到返-1
print(ss.index('o'))#3,找不到报错
print(ss.replace('love','like'))#I like GJL
print(ss.split('o'))#['I l', 've GJL']
print(ss.split(None,1))#['I', 'love GJL']
print('.'.join(ss.split(None,1)))#I.love GJL

#运算符
a=5
b=2
c=1/2#若除以0会产生ZeroDivisionError
s='cj'
print("a>b") if a>b else print("a<b")#a>b,在输出层面的三目运算符
print("a>b" if a>b else "a<b")#a>b,先判断返回哪个字符串再输出
print(a,a+b,a-b,a*b,a/b,a//b,a**b,a%b,b*s,s*b)#5 7 3 10 2.5 2 25 1 cjcj cjcj
print(a**c,a&b,a|b,a^b,~a,a<<2,a>>2)#2.23606797749979 0 7 7 -6 20 1
print(a==b,a!=b,a>b,a>=b,a<b,a<=b,a is b)#False True True True False False False
s='0123456789'
print(s[2:8:2])#246,下标2到下标8前一位,步长为2
import time
a=time.gmtime()
b=time.gmtime()
print(a==b,a is b)#True False
a=True
b=False
print(a and b,a or b,not b)#False True True



#第三章:列表与元组(其实有列表就够用)
#先用dir(list)查看可用方法
print(dir(list))#会用下面的方法就表示掌握了List封装类
'append'#加加
'clear'#清空
'copy'#复制
'count'#计数
'extend'#追加
'index'#找下标
'insert'#插入
'pop'#出队/退栈
'remove'#删除
'reverse'#翻转
'sort'#排序
a=['abc','def','ghi',11]#列表可修改
b=('123','456','789',22)#元组不可改
bb=2,5,7,3,6,9
print(type(bb))#<class 'tuple'>默认是元组
d=['GJL']
print(b+(520,))#('123', '456', '789', 22, 520),相当于append方法,注意(520)是520非元组只是Int
print(a+d)#['abc', 'def', 'ghi', 11, 'GJL'],相当于extend方法
print(d*2)#['GJL', 'GJL']
print(a[0:3:2],b[0:-2:2])#['abc', 'ghi'] ('123',),索引[start:end:step]
print('123' in b,b.index('123'))#True 0,跟前面str很类似
c=[1,3,5,7,9,2,4,6,8,0]
print(len(c))#10

#封包
a_tuple=tuple(range(1,10,2))
a_list=list(range(1,10,2))
print(a_tuple,a_list)#(1, 3, 5, 7, 9) [1, 3, 5, 7, 9]

#解包
a,b,*c,d=a_list#a_tuple也可,*c表示后面若干个的生成一个列表
print(a,b,c,d)#1 3 [5, 7] 9
#封解包结合实例:swap
x,y=1,2
x,y=y,x#swap
print(x,y)#2 1

#列表增删改查(比C++中的链表方便多了)
a=[1,3,4]
b=[25,6,]
a.insert(1,2)
print(a[0],a[1],a[2],a[3])#1 2 3 4,下标越界如访问a[4]会产生IndexError
a.append(b)
print(a)#[1, 2, 3, 4, [25, 6]]
a.extend(b)
print(a)#[1, 2, 3, 4, [25, 6], 25, 6]
del a[2]
print(a)#[1, 2, 4, [25, 6], 25, 6]
del a[2:5:2]
print(a)#[1, 2, [25, 6], 6]
a.remove([25, 6])
print(a)#[1, 2, 6],注意找不到要删除的目标时会报错,此时需要写异常来接收使程序继续
a.sort(reverse=True)#升序
print(a)#[6, 2, 1]
a.reverse()
print(a)#[1, 2, 6]
a.pop()#python真的是一个list就代替了C++中的栈与队列
print(a)#[1, 2]
print(a.count(2))#1
a.clear()#a[0:len(a)+1]=[]是一样的功能
print(a)#[]

#补充一下sort中的key,相当于C++中常写的cmp函数
#第一种是用.sort形式,是类方法会改变类对象自身
a=[]
a.extend(range(1,10,2))
a.extend(range(10,2,-2))
print(a)#[1, 3, 5, 7, 9, 10, 8, 6, 4]
def cmp(x):#自定义比较函数
    return x%3#用%3之后的值来比较
a.sort(key=cmp)#注意当%3后的值相等时按原顺序,即稳定的排序算法
print(a)#[3, 9, 6, 1, 7, 10, 4, 5, 8],默认升序
#第二种是用sorted形式,是全局方法不会改变传入的参数
a=['ab','d','cac']
print(sorted(a,key=len,reverse=True),a)#['cac', 'ab', 'd'] ['ab', 'd', 'cac']

#字典(对应C++中的map),元组可作key因为规定不可变
print(dir(dict))
'clear'#清空
'copy'#复制
'fromkeys'#根据key与val生成字典
'get'#根据key查val,查不到返none,用[]的话会报错KeyError
'items'#获取所有数据对
'keys'#获取所有key
'pop'#由key删除
'popitem'#删除底层存储的最后一个元素
'setdefault'#更新dic,没有该key的话就创建,有该Key的话不修改
'update'#更新dic,没有该key的话就创建,有该Key的话修改为新值
'values'#获取所有val
s='a'
x={1:'ABC',s:'DEF',2:'GHI',4:234}
s='b'#s与x无关
y=x#浅拷贝
z=x.copy()#深拷贝
x[1]='GJL'
print(x)#{1: 'GJL', 'a': 'DEF', 2: 'GHI', 4: 234}
print(y)#{1: 'GJL', 'a': 'DEF', 2: 'GHI', 4: 234}
print(z)#{1: 'ABC', 'a': 'DEF', 2: 'GHI', 4: 234}

#增删改查
x[34]=56
print(x)#{1: 'GJL', 'a': 'DEF', 2: 'GHI', 4: 234, 34: 56}
x[34]=45
print(x)#{1: 'GJL', 'a': 'DEF', 2: 'GHI', 4: 234, 34: 45}
del x[34]
print(x)#{1: 'GJL', 'a': 'DEF', 2: 'GHI', 4: 234}
print(1 in x)#True
print(x.get(4))#234
x.pop(2)#同del x[2]
print(x)#{1: 'GJL', 'a': 'DEF', 4: 234}
x.popitem()
print(x)#{1: 'GJL', 'a': 'DEF'}
x.update({1:'ABC','a':'DEF',2:'GHI'})
print(x)#{1: 'ABC', 'a': 'DEF', 2: 'GHI'}
for i in x.items():
    print(i,i[0],i[1],end=',')#(1, 'ABC') 1 ABC,('a', 'DEF') a DEF,(2, 'GHI') 2 GHI,
    print(type(i))
for i in x.keys():#注意等价于for i in x:即x默认取出来就是Key
    print(i,end=' ')#1 a 2 4
for i in x.values():
    print(i,end=' ')#ABC DEF GHI 234 
my_key = ('G', 'J', 'L')
my_val = 'C','J'
new_dic=dict.fromkeys(my_key, my_val)
print(new_dic)#{'G': ('C', 'J'), 'J': ('C', 'J'), 'L': ('C', 'J')}
new_dic.setdefault('love',520)
print(new_dic)#{'G': ('C', 'J'), 'J': ('C', 'J'), 'L': ('C', 'J'), 'love': 520}
new_dic.setdefault('G',520)
print(new_dic)#{'G': ('C', 'J'), 'J': ('C', 'J'), 'L': ('C', 'J'), 'love': 520}
my_key='my name is %(name)s, my age is %(age)d years old, my weight is %(weight)f kg'
my_val={'name':'CJ','age':24,'weight':50.0}
s=my_key % my_val#这样可以获得一个字符串
print(s)#my name is CJ, my age is 24 years old, my weight is 50.000000 kg

#最后补充四点
#第一点:字典中取出来的数据类型
x={1:'ABC','a':['DEF',45],2:'GHI'}
for i in x.items():
    print(i,i[0],i[1],end=',')
    print(type(i),type(i[0]),type(i[1]))
'''
(1, 'ABC') 1 ABC,<class 'tuple'> <class 'int'> <class 'str'>
('a', ['DEF', 45]) a ['DEF', 45],<class 'tuple'> <class 'str'> <class 'list'>
(2, 'GHI') 2 GHI,<class 'tuple'> <class 'int'> <class 'str'>
'''
#第二点:元组与列表转换元组并非不可改变,及append与extend区别
kk=(12,34)#不可修改的元组
tmp=list(kk)#转换成列表
tmp2=tmp*3
tmp2.append('abc')
tmp2.extend('abc')
print(tmp2)#[12, 34, 12, 34, 12, 34, 'abc', 'a', 'b', 'c']
kk=tuple(tmp2)#再转回元组
print(kk)#(12, 34, 12, 34, 12, 34, 'abc', 'a', 'b', 'c')
#第三点:实现字母遍历用ord字符改ASCII与chrASCII码改字符
s='ABCABCABCDE'
dic={}
for x in range(ord('A'), ord('E') + 1):
    tmp=s.count(chr(x))
    dic[x-64]=tmp
print(dic)#{1: 3, 2: 3, 3: 3, 4: 1, 5: 1}
#第四点:zip写法
a=[1,3,5]
b=[2,4,6]
c=zip(a,b)
print(type(c))#<class 'zip'>
for x,y in zip(a,b):
    print(x+y)#3 7 11就是打包后再解包得到两个int
for x in zip(a,b):
    print(x,x[0],x[1],type(x))#跟dic一样用一个变量取就是<class 'tuple'>



#第四章:流程控制
if 1:
    pass
elif 1:
    pass
else:
    pass
while 0:
    break
else:
    pass
s='abc'
assert s=='abc'#断言,若不符合会产生AssertionError,若符合则继续往下执行
for i in range(0,len(s),1):
    continue
else:#python中所有循环后都可以用else,其唯一作用是延长这个代码块的临时变量作用域
    print(s[i])#注意i在else块中的值是最后一次符合循环条件的值
for i in s:#除了像上面遍历下标外还可以直接遍历每个元素
    print(i)
b=[(x*x,y) for x in range(2) for y in reversed(range(3))]#for嵌套生成列表
print(b,type(b))#[(0, 2), (0, 1), (0, 0), (1, 2), (1, 1), (1, 0)] <class 'list'>
b=(x*x for x in range(10) if x%2==1)#for与if表达式嵌套生成生成器
for i in b:
    print(i,end=' ')#1 9 25 49 81 
print(b,type(b))#<generator object <genexpr> at 0x000001AAC17255C8> <class 'generator'>



#第五章:函数
def cjmax(a,b,c,d=2):#痛苦,一开始用了max做函数名覆盖了内置函数致前面第二章处报错
    '''
    return a tuple#返回一个元组
    '''
    return a,b,c,d
print(cjmax.__doc__)#return a tuple#返回一个元组
print(help(cjmax))
'''
Help on function cjmax in module __main__:
cjmax(a, b, c, d=2)
    return a tuple#返回一个元组
None
'''
print(cjmax(1,c=3,b=2))#(1, 2, 3, 2),传参顺序:不带名传参,带名传参(可换位),带默认值的参数(可省)

#四个例子说明传参问题
def cjswap1(w,x,y,z):
    w[0],w[1]=w[1],w[0]
    x[1],x[2]=x[2],x[1]
    y,z=z,y
    w=None#栈中指针清空并不改变指向的堆内存数据
    x=None
w=[8,9]
x={1:2,2:3}
y=6
z=7
cjswap1(w,x,y,z)
print(w,x,y,z)#[9, 8] {1: 3, 2: 2} 6 7,列表字典传参是本体,普通传参是值传递
def cjswap2(*x,y):#用*来传参会打包生成tuple,若后面还有参数传入时必须显式传参如例中的y
    #x[0],x[1]=x[1],x[0]#TypeError: 'tuple' object does not support item assignment
    return x[0],x[1]
x,y=cjswap2(1,2,y=3)
print(x,y)#1 2
def cjswap3(*x,**y):#**y用于收集字典,参数顺序尽量是无*,带*,带**
    print(x)#('I', 'love', 'GJL')
    print(y)#{'cj': 'gjl', 'gjl': 'cj'}
cjswap3('I','love','GJL',cj='gjl',gjl='cj')
def cjswap4(x,y):
    print(x,y)#1 2
cjlist=[1,2]
cjswap4(*cjlist)#带*就是解列表包
cjtuple=(1,2)
cjswap4(*cjtuple)#带*就是解元组包
cjdic={'x':1,'y':2}
cjswap4(**cjdic)#带**就是解字典包

#变量字典
#先弄个全局变量
age=100
name='cj'
love='gjl'
def test(x):
    #print(globals())#全局范围所有变量,输出太多先注释掉
    age=20#默认局变量20遮盖了全局的100
    print(age)#20
    print(globals()['name'])#访问全局变量中变量名为name的变量,cj
    global love#声明本函数作用域内的love用的是全局变量,这就可以对全局变量作修改了
    love='jl'
    print(love)#jl
    print(locals())#局部范围所有变量,在全局范围调用同globals,{'age': 20, 'x': 1}
    print(vars(test))#对象范围所有变量,不传参的话同locas,{}
test(1)
print(age)#100
print(love)#jl

#函数内的函数以及函数换名三方法
def f1(x):
    print(type(x))#由执行时传入参数决定<class 'int'>或<class 'float'>
    def f2(y):
        return y+1
    return f2(x+1)
print(f1(1.0))#3
#一、直接换名
f3=f1
print(f3(1))#3
#二、传参是函数
def f4(f,x):
    return f(x)
print(f4(f3,1))#3
print(type(f4))#<class 'function'>
#三、返参是函数
def f5():
    return 1
def f6():
    return f5
f=f6()
print(type(f),f,f())#<class 'function'> <function f5 at 0x000001AAC17CE840> 1

#lambda
y=lambda x:x*x#单行函数且只用一次
def z(x): return x*x#与上面等价
print(y(2))#4
print(z(2))#4



#第六章:类与对象
#基本属性与方法
class stu:
    def __init__(self,name='cj'):
        self.name=name
    def say(self,content):
        print(self.name,content)
p1=stu()
print(p1.name)#cj
p1.say('loves GJL')#cj loves GJL

#动态增减属性(尽量不用)
p1.age=24#给p1动态增加属性age
del p1.name
print(vars(p1))#{'age': 24}显然p1可以动态增加name属性
p2=stu()
print(vars(p2))#{'name': 'cj'}显然p2并没有age属性即对象之间无影响

#动态增减方法(不能删原有的say)(尽量不用)
#第一种常规
def fun_func1():
    print("running")
p1.run=fun_func1#动态增加方法
p1.run()#running
del p1.run#动态加的方法可以删
#第二种要访问类对象属性时加self
p3=stu()
def fun_func2(self):#若是要访问类属性及类方法记住都加上self
    print(self.name)
p3.introduce=fun_func2
p3.introduce(p3)#cj,必须传p3做参数
#第三种要访问类对象属性时用绑定
from types import MethodType
p4=stu()
p4.introduce=MethodType(fun_func2,p4)
p4.introduce()#cj,绑定后调用时就不用传p4做参数了,跟类定义时就确定的方法一样

#连续调用的写法
class stu2:
    def __init__(self):
        self.age=10
    def grow(self):
        self.age+=1
        return self
cj=stu2()
cj.grow().grow().grow()
print(cj.age)#13

#类调用方法
class stu3:
    def __init__(self,name):#name没有默认值则创建对象时必须构造一个
        self.name=name
    def run():
        print("nobody is running")
    def run2(self):
        print("someone is running")
stu3.run()#nobody is running,类调用方法
stu3.run2(stu3('cj'))#someone is running,有self传入的话也要传入一个

#类方法与静态方法
class A(object):
    bar=1
    def foo(self):
        print("foo")
    @staticmethod
    def static_foo():
        print("static_foo")
        print(A.bar)
    @classmethod
    def class_foo(cls):
        print("class_foo")
        print(cls.bar)
A.static_foo()
A.class_foo()
#可以看出上面三个函数的区别(传参)
#普通方法是传类对象(就是用对象来调用他)
#静态方法是什么也不传
#类方法是传类本身(就是用类来调用他)

#lambda方法的写法(尽量不用)
class g:
    f=lambda self,p:print(p)
c=g()
c.f(3)#3

#函数装饰器@(尽量不用)
#例1简单版
def f1(fn):
    print(1)
    x=fn()
    return x,3
@f1
def f2():
    return 2
print(f2)#1 (2, 3),简单来说就是把执行f2变成执行f1(f2)
#例2超复杂版
def say_hello(country):#这个传进来的就是usa或en字符串
    def wrapper(func):#这个传进来的就是usa或en函数
        def decorate(*args,**kw):#这个传进来的就是执行时传进来的变量
            if len(args)==0:print('No input')
            else:print(args[0],'has been input')
            x=func(12,country)
            return x
        return decorate
    return wrapper
@say_hello("usa")
def usa(x,country):
    print('i am %d years old, from'%x,country)
    return 100
print(usa())#No input   i am 12 years old, from usa   100
print(usa(36))#36 has been input   i am 12 years old, from usa   100
#总结一下:
#如果@装饰器有参数,则最先传入真正执行的函数
#然后是被装饰的函数,必须有一个函数来接收他
#最后是被装饰的函数如果有传入参数,则最后第三层函数接收他

#类属性(懂例2即可)
#例1
class stu:
    age=10#这样写就是类属性
p1=stu()#创建对象时由于没有在init中创建对象属性age,所以p1.age就是stu.age
print(p1.age,stu.age)#10 10
stu.age+=1
print(p1.age,stu.age)#11 11
p1.age-=1#一旦p1修改了age就表示他有自己的age了与stu.age无关
print(p1.age,stu.age)#10 11
stu.age+=1
print(p1.age,stu.age)#10 12
#例2
class stu:
    age=10#这样写就是类属性
    def __init__(self):
        self.age=1#在构造函数里带self就是对象属性
p1=stu()
print(p1.age,stu.age)#1 10,显然现在类属性与对象属性就分开得很清楚了
stu.age+=1
print(p1.age,stu.age)#1 11
p1.age-=1
print(p1.age,stu.age)#0 11
stu.age+=1
print(p1.age,stu.age)#0 12
#总结:类变量用类名访问,创建时直接写,对象变量用对象名访问,创建时在init写self.

#property写法(可以封装多个变量变成合成属性,并且增删改查时可以控制权限)
#例1
class stu6:
    def __init__(self,age):
        self.age=age
    def setinfo(self,age):
        self.age=age
    def getinfo(self):
        return self.age
    def delinfo(self):
        self.age=0
    info=property(getinfo,setinfo,delinfo,"someone's age")
print(stu6.info.__doc__)#帮助文档用类访问
help(stu6.info)
p1=stu6(6)
p1.info=8#set
print(p1.info)#8,get
del p1.info#del,不是真删,只是清0
print(p1.info)#0
#例2
class stu7:#用@修饰符写,注意函数名都用age,函数内调用时变量名前加_
    @property#表示get
    def age(self):
        return self._age
    @age.setter#表示set
    def age(self,age):
        self._age=age
p1=stu7()
p1.age=1#set
print(p1.age)#1,get

#封装(与property结合增强安全性)
#隐藏属性
class stu8:
    def __init__(self):
        self.__age=24#变量名前加__就是隐藏属性
        self.__name='cj'
    def setinfo(self,info):
        if info[0]<0 :#输入的元组的第一个元素就是age
            print('error')
            return 
        self.__age,self.__name=info
    def getinfo(self):
        return self.__age,self.__name
    info=property(getinfo,setinfo)#把__age与__name封装成Info并控制读写权限
p1=stu8()
print(p1.info)#(24, 'cj')
p1.info=-1,'gjl'#error
p1.info=23,'gjl'
print(p1.info)#(23, 'gjl')
#特别注意补充说明
p1.__name='newname1'#这里的p1.__name与上面隐藏的self.__name不是同一个变量
print(p1.__name,p1.info)#newname1 (23, 'gjl')
p1._stu8__name='newname2'#这行代码修改的才是隐藏的__name变量
print(p1.__name,p1.info)#newname1 (23, 'newname2')
x,y=p1.info#我再读出来下面比较直白一点
print(p1.__name,y)#newname1 newname2,前者是公开的,后者是隐藏的
print(vars(p1))#{'_stu8__age': 23, '_stu8__name': 'newname2', '__name': 'newname1'}

#隐藏方法
class stu9:
    def __hide(self):
        pass
p1=stu9()
p1._stu9__hide()#执行p1.__hide()会报错AttributeError

#继承
#例1:多继承
class stu10:
    age=10
    def f(self):
        print('stu10',self.age)
class stu11:
    age=11
    def f(self):
        print('stu11',self.age)
class stu12(stu10,stu11):#多继承且有同名属性/方法时以前面的为准,后面的被覆盖
    pass
p1=stu12()
print(p1.age)#10
p1.f()#stu10 10
#例2:重写
class stu13(stu10,stu11):#子类可以重写或覆盖父类的属性/方法
    age=13
    def f(self):
        print('stu13',self.age)
p1=stu13()
print(p1.age)#13,在Python中,子类重写后,不再保留父类继承的同名属性与方法
p1.f()#stu13 13,其实与下面这句差不多,只不过调用函数不同,且第一个参数绑定了self
stu10.f(p1)#stu10 13,如果子类对象P1要调用父类方法,直接用类名跑,传子类对象做参数
#例3:super
class stu14():
    def __init__(self,age):
        print('stu14')
        self.age=age
class stu15():
    def __init__(self,name):
        print('stu15')
        self.name=name
class stu16(stu14,stu15):
    def __init__(self,age,name):
        stu14.__init__(self,age)#下面两行代码完全等价
        #super().__init__(age)
        #super(stu16,self).__init__(age)
        stu15.__init__(self,name)
p1=stu16(14,'cj')
print(vars(p1))#{'age': 14, 'name': 'cj'}

#__slots__
'''
一、给对象动态添加的属性/方法,只有此对象有效
二、给类动态添加的属性/方法,对此类全对象有效
三、__slots__限制允许给此类对象(子类无效)动态添加的属性名与方法名,但不限制上面第二点
四、若子类也有__slots__,则子类对象能动态添加的属性名与方法名是子类与父类的__slots__元组和
'''
class stu17:
    __slots__=('walk','age')
p1=stu17()
p2=stu17()
def my_walk(self):
    print('my_walk',self.age)
def my_walk2(self):
    print('my_walk2',self.age)
p1.age=1
p1.walk=my_walk
p1.walk(p1)#my_walk 1
#p2.walk(p2)#AttributeError,证明第一点
stu17.age=17
stu17.walk=my_walk2
p1.walk()#my_walk2 17,证明第二点,且p1.walk()被重写了
p2.walk()#my_walk2 17
#p1.run()=my_walk()#SyntaxError,证明第三点,不能用run方法名因为__元组
class stu18(stu17):
    pass
p1=stu18()
p1.sex='male'#可以用sex属性名,即父类的__slots__无效,证明第三点
class stu19(stu17):
    __slots__=('sex')
    pass
p1=stu19()
#print(p1.sex)#AttributeError: sex,未定义的属性OR方法不用访问
p1.sex='male'#自己的属性可以增加及修改,这行定义之后可以访问执行上一行代码
#p1.age=20
#p1.walk=my_walk#'stu19' object attribute 'walk' is read-only父类slots下的属性OR方法不可修改
print(p1.age)#17
p1.walk()#my_walk2 17,
#一般的来说继承的属性是可以修改的
class A:age=1
class B(A):pass
b=B()
b.age=2
print(vars(b),type(A),type(B))#{'age': 2} <class 'type'> <class 'type'>

#type动态创建类
def fn():pass
Dog=type('Dog',(object,),dict(walk=fn,age=6))#类名,父类,成员
d=Dog()
print(type(d),type(Dog),d.age,Dog.age)#<class '__main__.Dog'> <class 'type'> 6 6
Cats=type('Cat',(Dog,),dict())#这里是个不好的示范,Cats与'Cat'没有保持一致
c=Cats()
print(type(c),type(Cats),c.age,Cats.age)#<class '__main__.Cat'> <class 'type'> 6 6
#事实证明,函数内用CALSS定义类也是可以的,比上面的写法更清晰
def kkk():
    class A:
        print('hi')
kkk()#hi

#metaclass
class stu20(type):
    def __new__(cls,name,bases,attrs):
        attrs['cal']=lambda self:self.age+1
        def f(self):
            self.age+=1
        attrs['cal2']=f
        return type.__new__(cls,name,bases,attrs)
class stu21(metaclass=stu20):
    def __init__(self):
        self.age=1
p1=stu21()
print(vars(p1))#{'age': 1}
p1.age=p1.cal()
print(vars(p1))#{'age': 2}
p1.cal2()
print(vars(p1))#{'age': 3}

#多态
class stu21:
    color='red'
    def paints(self,pattern):#提供接口,画什么收传入的类对象pattern来定
        pattern.paint(self)#这里传进去的self是stu21类的self,即下面的pic传入参数
class triangle:
    def paint(self,pic):
        print('draw triangle',pic.color)
class rectangle:
    def paint(self,pic):
        print('draw rectangle',pic.color)
class circle:
    def paint(self,pic):
        print('draw circle',pic.color)
p1=stu21()
p1.paints(triangle())#draw triangle red
p1.paints(rectangle())#draw rectangle red
p1.paints(circle())#draw circle red

#检查类型
class stu22:
    age=10
class stu23(stu22):pass
print(issubclass(stu23,stu22))#True,是子类
p1=stu22()
print(isinstance(p1,stu22))#True,是该类对象
#特别补充说明
#一、object类是所有类的基类
#issubclass(a,b)若a是b的派生类则返True(子孙类)
print(issubclass(int,object))#True
print(issubclass(float,object))#True
print(issubclass(str,object))#True
print(issubclass(list,object))#True
print(issubclass(tuple,object))#True
print(issubclass(dict,object))#True
print(issubclass(type,object))#True
print(issubclass(stu22,object))#True
print(issubclass(stu23,object))#True
#二、class及type定义出来的类其实是type这个类的对象
#isinstance(a,b)若a对象是b类的实例则返True
print(isinstance(type,type))#True
print(isinstance(stu22,type))#True
print(isinstance(stu23,type))#True
#三、直接父类查询用__bases__
print(stu23.__bases__)#(<class '__main__.stu22'>,)
print(stu22.__bases__)#(<class 'object'>,)
print(object.__bases__)#()
print(type.__bases__)#(<class 'object'>,)
print(int.__bases__)#(<class 'object'>,)
print(float.__bases__)#(<class 'object'>,)
print(str.__bases__)#(<class 'object'>,)
print(list.__bases__)#(<class 'object'>,)
print(tuple.__bases__)#(<class 'object'>,)
print(dict.__bases__)#(<class 'object'>,)
print(type.__bases__)#(<class 'object'>,)
#lh 、直接子类查询用__subclasses__
print(stu23.__subclasses__())#[]
print(stu22.__subclasses__())#[<class '__main__.stu23'>]
x=stu22.__subclasses__()
print(type(x),type(x[0]))#<class 'list'> <class 'type'>
#print(type.__subclasses__())#会报错缺少argument,即type没有子类,但其对象可有子类
#print(object.__subclasses__())输出太多了,先注释掉这行

#枚举类(尽量不用)
#写法一
import enum
Seasons=enum.Enum('Season',('SPRING','SUMMER','FALL','WINTER'))
print(Seasons,type(Seasons))#<enum 'Season'> <class 'enum.EnumMeta'>
print(Seasons.SPRING,type(Seasons.SPRING))#Season.SPRING <enum 'Season'>
print(Seasons.SPRING.name,Seasons.SPRING.value)#SPRING 1
print(Seasons['SUMMER'])#Season.SUMMER,根据name找元素
print(Seasons(3))#Season.FALL,根据value找元素
for name,member in Seasons.__members__.items():#返回的元组元素是(name,枚举元素)
    print(name,member,member.value)#……WINTER Season.WINTER 4
#Season是创建的一个枚举类enum.EnumMeta,Seasons相当于话柄(其实用同名更好)
#四季的单词是这个类的四个枚举元素,类型是Season
#每个元素下又有两个成员,name与value,这就是基本数据类型了
#写法二
import enum
class Orientation(enum.Enum):
    one=1
    two=2
    three=3
    def __init__(self,x):
        self.age=x+10
    def getage(self):
        return self.age
    def info(self):
        print(self.value)
print(Orientation.two,type(Orientation.two))#Orientation.two <enum 'Orientation'>
print(Orientation.two.name,type(Orientation.two.name))#two <class 'str'>
print(Orientation.two.value,type(Orientation.two.value))#2 <class 'int'>
print(Orientation['two'],type(Orientation['two']))#Orientation.two <enum 'Orientation'>
print(Orientation(2),type(Orientation(2)))#Orientation.two <enum 'Orientation'>
Orientation.two.info()#2
for name,member in Orientation.__members__.items():
    print(name,member,member.value)
'''
one Orientation.one 1
two Orientation.two 2
three Orientation.three 3
'''
print(Orientation.two.getage())#12



#第七章
'''
try:可能以发异常的代码
except:异常类型与一个代码块,表示该块是处理这种异常类型的代码
else:不出异常时执行
finally:回收try块里打开的物理资源(总会执行)
raise:手动引发异常
'''
try:
    files=open('GJL.txt')
    xx=[0,1,2]
    #x=input()
    x=0
    y=xx[int(x)]
    #z=input()
    z=1
    w=int(x)/int(z)
    print('try块跑完了')
except IndexError:#下标越界,如x输入3
    print('IndexError',IndexError.args)
except ValueError:#非数字或非整数,如x输入abc,1.1
    print('ValueError',ValueError.args)
except ArithmeticError:#算法错误,除零,浮点,溢出,如z输入0
    print('ArithmeticError',ArithmeticError.args)
except (Exception,SystemExit) as e:#两个大异常补底,换名用as,如open不存在的文件
    print(e.args,e.errno,e.strerror)#编号与信息,编号,信息
except NameError as e:
    print("NameError the file's path is wrong")
else:
    pass
finally:
    if files is not None:
        try:
            files.close()
        except OSError as ioe:
            print(ioe.errno,ioe.strerror)
'''
继承关系
BaseException的子类:GeneratorExit,Exception,SystemExit,KeyboardInterrupt
Exception的子类:ArithmeticError,BufferError,LookupError
ArithmeticError的子类:ZeroDivisionError,FloatingPointError,OverflowError
LookupError的子类:IndexError,KeyError
'''
#说明三点
#一、os.exit(1)直接退出PYTHON解释器,所以finally可能不被执行
#二、sys.exit()是通过以发SystemExit异常来退出程序,所以不能阻止finally执行
#若try中的return,也不能阻止finally执行,finally有return时以finally的为准
def str24():
    try:
        return True
    finally:
        return False
print(str24())#False

#raise
def tests1():
    try:
        raise#上文没有异常时引发RuntimeError异常
    except Exception as e:
        print(type(e))#<class 'RuntimeError'>
    try:
        raise ValueError("hello")#带参数时就是引发参数对应的异常
    except Exception as e:
        print(type(e))#<class 'ValueError'>##带参数时就是引发参数对应的异常
    class myException(Exception):pass
    try:
        raise myException('you are wrong')
    except Exception as e:
        print(e,type(e))#you are wrong <class '__main__.tests1.<locals>.myException'>
        raise#不带参数的话再次引发上文的异常抛给外层捕获
def tests2():
    try:
        tests1()
    except Exception as e:
        print(e,type(e))#you are wrong <class '__main__.tests1.<locals>.myException'>
tests2()

#异常传播轨迹
#import traceback#下面注释掉的两行打开时要导入这个包
class selfException(Exception):pass
def main():
    firstMethod()
def firstMethod():
    secondMethod()
def secondMethod():
    thirdMethod()
def thirdMethod():
    raise selfException('nice to meet you')
try:
    main()
except Exception as e:
    print(e)#nice to meet you
    #traceback.print_exc()#捕获异常并输出到控制台
    #traceback.print_exc(file=open('2.txt','a'))#捕获异常并输出到指定文件



#第八章:类与对象补充(与第六章是全书最核心内容)
#repr例1
class stu25:pass
p1=stu25()
print(p1)#<__main__.stu25 object at 0x000001ECA0C78128>
print(p1.__repr__())#同上,类名+object at+内存地址
#repr例2
class stu26:
    def __repr__(self):
        return 'I love GJL'
p1=stu26()
print(p1)#I love GJL
print(p1.__repr__())#I love GJL

#del
class stu27:
    name='cj'#这个是类属性
    def __init__(self):
        self.age=27
        print(27,'init')
    def __del__(self):
        self.age=0
        print(27,'del')
class stu28(stu27):
    def __init__(self):
        stu27.__init__(self)#要是没有这一句,p1没有age属性
        self.ages=28
        print(28,'init')
    def __del__(self):
        self.ages=0
        print(28,'del')
        stu27.__del__(self)
p=stu27()
print(vars(p))
del p
#没有del p时输出27 init    27 del         {'age': 27}
#有del p时按代码顺序输出27 init     {'age': 27}    27 del
#综上,没事还是让python自己解决吧,会自动优化del位置的!
p1=stu28()#27 init   28 init
print(vars(p1))#{'age': 27, 'ages': 28}
del p1#28 del   27 del,若是没有del p1,直接没有del语句!!可怕

#顺带一提,python中的类如list,tuple,dict,class自定义类,都是等价复制
class stu29:
    def __init__(self):
        self.age=29
p1=stu29()#先创建一个p1
p3=p1#然后复制给p3,相当于指针复制
p3.age=19#然后更改p3的值
print(p3 is p1,vars(p1),vars(p3))#True {'age': 19} {'age': 19}显然p1就是p3,等价
#class自义定类中,要实现深浅拷贝全部由用户手写,若是list,dict则有copy函数可以用
#但int,float这两个类不是
x=1
y=x
y=2
print(x,y)#1 2,显然x,y没有一起变化

#dir,dict
class stu30:
    def __init__(self):
        self.age=10
    def info():pass
p1=stu30()
print(p1.__dir__())#所有属性/方法列表
print(dir(p1))#所有属性/方法列表
print(p1.__dict__)#{'age': 10},所有属性名与属性值

#getattr,setattr,delattr,getattribute触发器
class stu31:
    def __init__(self,names):#增,构造时运行
        print('init 开始 ')
        self.name=names
        print('init 结束')
    def __delattr__(self,names):#删,删除时运行
        print('delattr 开始')
        if names!='name':
            raise AttributeError
        self.__dict__[names]=0
        print('delattr 结束')
    def __setattr__(self,names,value):#改,修改时运行
        print('setattr 开始')
        if names!='name':
            raise AttributeError
        self.__dict__[names]=value
        print('setattr 结束')
    def __getattr__(self,names):#查,当访问属性不存在时运行
        print('getattr 开始')
        print('the %s is still none'%names)
        print('getattr 结束')
    def __getattribute__(self, x):#查,当访问属性存在时运行
        #这里不能输出东西,否则会循环
        return object.__getattribute__(self, x)
p1=stu31('cj')#init 开始    setattr 开始    setattr 结束    init 结束
p1.name='gjl'#setattr 开始    setattr 结束
print(p1.name)#gjl
print(p1.age)#getattr 开始   the age is still none   getattr 结束   None
del p1.name#delattr 开始   delattr 结束

#hasattr,getattr,setattr动态操作,__call__属性
class stu32:
    def __init__(self):
        self.age=20
    def info(self):
        print('my age is %d'%self.age)
p1=stu32()
print(hasattr(p1,'age'))#True
print(hasattr(p1,'info'))#True
print(getattr(p1,'age'))#20,getattr不能获取方法,所以不能运行Info
setattr(p1,'age',21)
def f():print('ok')
setattr(p1,'info',f)
print(p1.age)#21
p1.info()#ok
print(hasattr(p1.age,'__call__'))#False,说明age是属性
print(hasattr(p1.info,'__call__'))#True,说明info是方法
#事实上,执行p1.info就是执行p1.info.__call__,如下语句
p1.info.__call__()#ok
class stu33:
    def __call__(self):print('cj loves gjl')
p2=stu33()
p2()#cj loves gjl
p2.__call__()#cj loves gjl

#len,getitem,contains,setitem,delitem序列方法
l=['cj','loves','gjl']
print(l.__len__())#3
print(l.__getitem__(1))#loves
print(l.__contains__('gjl'))#True
l.__setitem__(1,'likes')
print(l)#['cj', 'likes', 'gjl']
l.__delitem__(1)
print(l)#['cj', 'gjl']

#迭代器
#例1自定义类
class stu34:
    def __init__(self):
        self.age=0
    def __iter__(self):
        return self
    def __next__(self):
        self.age+=1
        return self.age
p1=stu34()
print('now p1 is ',next(p1))#now p1 is  1
print('now p1 is ',next(p1))#now p1 is  2
print('now p1 is ',next(p1))#now p1 is  3
for i in p1:
    print(i)
    if i>10:break
#例2列表转
my_iter=iter([2,'fkit',4])
print(my_iter.__next__())#2
print(my_iter.__next__())#fkit
print(my_iter.__next__())#4

#扩展列表,元组,字典
class cj_dict(dict):
    def __init__(self,*args,**kwargs):
        super().__init__(*args,**kwargs)
    def getkeys(self,val):
        result=[]
        for key,value in self.items():
            if value==val:
                result.append(key)
        return result
my_dict=cj_dict(cj=24,gjl=23)
print(my_dict.getkeys(24))#['cj']
my_dict['loves']=520
print(my_dict.getkeys(520))#['loves']

#生成器yield
def cj_f1():
    for i in range(3,20,4):
        yield i
t1=cj_f1()#t1就是生成器
print('now t1 is ',next(t1))#now t1 is  3
print(list(t1))#[7, 11, 15, 19]
t2=cj_f1()
for i in t2:    
    print(i)#3 7 11 15 19
#send
def cj_f3():#----------------------第一行
    x = yield#---------------------第二行
    for i in range(1,10):#---------第三行
        if x==None :#--------------第四行
            print("i:",i)#---------第五行
            x = yield i+100#-------第六行
        else:#---------------------第七行
            print("x:",x)#---------第八行
            x = yield x+1000#------第九行
g = cj_f3() # g是一个生成器,可以实现由输入求next或按顺序求next
print(next(g))   #None 首先程序跑第二行yield,返回None
print(next(g))   #i:1   101  第二行给x赋值None,下一轮循环第五行打印i,第六行返回i+100
print(next(g))   #i:2   102  第六行给x赋值None,下一轮循环第五行打印i,第六行返回i+100
print(g.send(77))#x:77  1077 第六行给x赋值77,  下一轮循环第八行打印x,第九行返回x+1000
print(g.send(99))#x:99  1099 第九行给x赋值99,  下一轮循环第八行打印x,第九行返回x+1000
print(next(g))   #i:5  105   第九行给x赋值None, 下一轮循环第五行打印i,第六行返回i+100
print(g.send(None))#i: 6  106 相当于next(g)
#throw与close
#g.throw(ValueError)#ValueError
#g.close()#关闭
#print(next(g))#StopIteration

#运算符重载
#先说明,python中类与全局函数没有重载只有重写,同名时只有最后定义的生效,不能由传入参数选择
#运算符重载是不同的类遇到相同的符号时,可以执行不同的函数(符号同函数名也同)
def ffff():pass
ffff()
def ffff(x):pass
ffff(1)
#ffff()#TypeError
x=14
y=5
#左版,实际上执行左边表达式时就是执行右边的函数,右边的函数重载成左边的运算符了
print(x+y,x.__add__(y))#19 19
print(x-y,x.__sub__(y))#9 9
print(x*y,x.__mul__(y))#70 70
print(x/y,x.__truediv__(y))#2.8 2.8
print(x//y,x.__floordiv__(y))#2 2
print(x%y,x.__mod__(y))#4 4
print(x**y,x.__pow__(y))#537824 537824
print(x<<y,x.__lshift__(y))#448 448
print(x>>y,x.__rshift__(y))#0 0
print(x&y,x.__and__(y))#4 4
print(x^y,x.__xor__(y))#11 11
print(x|y,x.__or__(y))#15 15
#右版,当表达式中左边的x没有对应的重载函数,会再找右边的y有没有,注意运行时会变成y在左边
print(x+y,x.__radd__(y))#19 19
print(x-y,x.__rsub__(y))#9 -9
print(x*y,x.__rmul__(y))#70 70
print(x/y,x.__rtruediv__(y))#2.8 0.35714285714285715
print(x//y,x.__rfloordiv__(y))#2 0
print(x%y,x.__rmod__(y))#4 5
print(x**y,x.__rpow__(y))#537824 6103515625
print(x<<y,x.__rlshift__(y))#448 81920
print(x>>y,x.__rrshift__(y))#0 0
print(x&y,x.__rand__(y))#4 4
print(x^y,x.__rxor__(y))#11 11
print(x|y,x.__ror__(y))#15 15
#矩阵用numpy
import numpy
a=numpy.mat([1])
print(a.__matmul__(a),a@a)#[[1]] [[1]]
print(a.__rmatmul__(a),a@a)#[[1]] [[1]]
#比较运算符
print(x<y,x.__lt__(y))#False False
print(x<=y,x.__le__(y))#False False
print(x==y,x.__eq__(y))#False False
print(x!=y,x.__ne__(y))#True True
print(x>y,x.__gt__(y))#True True
print(x>=y,x.__ge__(y))#True True
#单目运算符
print(+x,x.__pos__())#14 14
print(-x,x.__neg__())#-14 -14
print(~x,x.__invert__())#-15 -15
#类型转换方法
print(str(x),x.__str__())#14 14
print(int(x),x.__int__())#14 14
print(float(x),x.__float__())#14.0 14.0
#内建函数
x=-5.5
print(x.__abs__())#5.5,直接变正
print(x.__round__())#-6,四舍五入,进到负六
print(x.__trunc__())#-5,直接截断小数,得负五
print(x.__format__(' '),type(x.__format__(' ')))#-5.5 <class 'str'>转串
x=5#5.5报错
print(x.__floor__())#5#我就纳闷了明明是向下取整怎么不能传入小数呢?
print(x.__ceil__())#5#我就纳闷了明明是向上取整怎么不能传入小数呢?
import math#我导入数学包试试吧
x=-5.5
print(math.floor(x))#-6,向下取整是变小
print(math.ceil(x))#-5,向上取整是变大
x='abc'
print(x.__hash__())#2975424199098587366
#自定义运算符重载示例
class stu35:
    def __init__(self,n):
        self.n=n
    def __add__(self,other):
        return self.n*10+other.n
    def __radd__(self,other):
        return self.n+other*10
x=stu35(4)
y=stu35(7)
print(x+y,y+x,10+x)#47 74 104



#第九章:模块与包
import sys as s,os as o,pprint
print(s.argv[0])#F:/ProjectPython/hello_test/Python_test.py,程序名
print(o.sep)#\
pprint.pprint(s.path)#默认模块加裁路径
from sys import argv as v,winver as wv
print(v[0])#F:/ProjectPython/hello_test/Python_test.py
print(wv)#3.6
#不建议from module import *

import GJL#导入模块
GJL.sayhello()#I love GJL.
print(GJL.__all__)#['sayhello'],若模块没有定义会返回None
print(type(GJL),GJL.__doc__)#<class 'module'> This is a module about my wife.
#注意一点,python环境下如果自己写的模块更改了,要restart kernel才能再跑
'''操作说明
在当前路径F:/ProjectPython/hello_test下新建一个GJL.py文件,内容如下:
#This is a module about my wife.
def sayhello():
    #This is a function about my wife.
    print('I love GJL forever.')
__all__=['sayhello']#主程序from GJL import *时只导入列表中的成员
if __name__=='__main__':#仅在python开发环境下运行时执行,即测试代码
    print("GJL")
    sayhello()
'''

import myGJL#导入包,其实就是导入myGJL文件夹下的__init__.py并运行
print(myGJL.__doc__)#This is a package about my wife.
myGJL.package1.fun1()#I love GJL on the first day.------第一句
myGJL.package2.fun2()#I love GJL on the second day.-----第二句
myGJL.package3.fun3()#I love GJL on the third day.------第三句
myGJL.fun1()#I love GJL on the first day.---------------第四句
myGJL.fun2()#I love GJL on the second day.--------------第五句
myGJL.fun3()#I love GJL on the third day.---------------第六句
'''特别说明一下:包亦是模块,只不包是更大的模块,因为他下面有子模块
from . import package1可以导入包内模块1,然后可以运行第一句,二三句同理
from .package1 import *可以把包内模块1内的成员导入到myGJL包,可以运行第四句,五六句同理
'''
print(dir(myGJL))#得到的是list列表,里面的元素是str字符串
'''
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__',
 '__name__', '__package__', '__path__', '__spec__',
 'fun1', 'fun2', 'fun3',  'package1', 'package2', 'package3']
'''
print(e for e in dir(myGJL) if not e.startswith('_'))
#fun1 fun2 fun3 package1 package2 package3
print(myGJL.__file__)#F:\ProjectPython\hello_test\myGJL\__init__.py,源文件路径
'''操作说明
在当前路径F:/ProjectPython/hello_test下新建一个myGJL文件,在文件夹里新建四个文件:
__init__.py,package1.py,package2.py,package3.py
其中__init__.py里写入内容为:
#This is a package about my wife.
from . import package1
from .package1 import *
from . import package2
from .package2 import *
from . import package3
from .package3 import *
其中package1.py里写入内容为:
#This is a module about my wife.
def fun1():
    print('I love GJL on the first day.')
其中package2.py里写入内容为:
#This is a module about my wife.
def fun2():
    print('I love GJL on the second day.')
其中package3.py里写入内容为:
#This is a module about my wife.
def fun3():
    print('I love GJL on the third day.')
'''



#第十章:常见模块(从本章起十分轻松,就是逐个模块掌握他封装好的属性与方法)
#sys(解释器相关)
import sys
print(sys.argv)#['F:/ProjectPython/hello_test/Python_test.py'],只有本程序路径,无其他参数传入
print(sys.byteorder)#little,小端模式,本地字节序指示符
print(sys.copyright)#python解释器有关版权信息
print(sys.executable)#D:\Anaconda\pythonw.exe,python解释器磁盘存储路径
#sys.exit()#通过引发SystemExit异常来退出程序
print(sys.flags)#运行Python命令时指定的旗标
print(sys.getfilesystemencoding())#utf-8,当前系统中保存文件所用的字符集
print(sys.getrefcount(p1))#2,对像p1有两个引用
print(sys.getrecursionlimit())#2000,当前解释器支持的递归深度,通过sys.setrecursionlimit(2000)设置
print(sys.getswitchinterval())#0.005,当前解释器中线程切换的时间间隔,通过sys.setswitchinterval(0.005)设置
print(sys.implementation)#当前解释器的实现
print(sys.maxsize)#9223372036854775807,整数支持最大值,2**63-1
#print(sys.modules)#返回模块名和载入模块对应关系的字典
print(sys.path)#指定pthon查找模块的路径列表,可通过修改此属性来动态增加加载模块路径
print(sys.platform)#win32,返回解释器所在平台标识符
print(sys.stdin)#<_io.TextIOWrapper name='<stdin>' mode='r' encoding='cp936'>,标准输入流
print(sys.stdout)#<ipykernel.iostream.OutStream object at 0x000002024EDCEBA8>,标准输出流
print(sys.stderr)#<ipykernel.iostream.OutStream object at 0x000002024EDCEF28>,错误输出流
print(sys.version)#3.6.3 |Anaconda, Inc.| (default, Oct 15 2017, 03:27:45) [MSC v.1900 64 bit (AMD64)]
print(sys.winver)#3.6,当前解释器主版本号,上一行是版本信息
#在命令行中执行python 文件名.py 520可以把520作为参数传进去,此时len(sys.argv)是2
print()
print()
print()
#os(操作系统相关,12章会专门介绍操作文件和目录的功能函数)
import os
#print(os.__all__)直接查所有属性和函数,基本上学所有模块都可以这样来学
print(os.name)#nt,导入依赖模块的操作系统名称
#print(os.environ)#返回所有环境变量组成的字典
print(os.fsencode('1.txt'))#b'1.txt',对文件名编码
print(os.fsdecode('1.txt'))#1.txt,对文件名解码
print(os.PathLike)#<class 'os.PathLike'>,代表一个类路径对象
print(os.getenv('PYTHONPATH'))#None,获取指定环境变量的值
print(os.getlogin())#CJ,当前系统登陆用户名
print(os.getpid())#5284,获取当前进程ID
print(os.getppid())#6000,获取当前进程父进程ID
#print(os.putenv(key,value)),该函数用于设置环境变量
print(os.cpu_count())#8,当前系统的CPU数量
print(os.sep)#\,返回路径分隔符
print(os.pathsep)#;,返回当前系统上多条路径之间的分隔符
print(os.linesep)#\r\n,返回当前系统的换行符
print(os.urandom(3))#b'i\x91<',返回适合作为加密使用的最多由N个字节组成的bytes对象
#进程管理函数
'''
#os.abort()#生成SIGABRT信号给当前进程,WIN系统立即返回退出代码3,我运行的话是会崩掉
#os.execl("python.exe路径"," ",'py文件路径','i')#执行执行文件,还有execle,execlp
#os.forkpty()#module 'os' has no attribute 'forkpty',!!??fork一个子进程
#os.kill(pid,sig)#将sig信号发到pid对应进程,用于结束该进程
#os.killpg(pgid,sig)#将sig信号发送到pgid对应进程组
#os.popen(cmd,mode='r',buffering=-1)#向cmd命令打开读写管道,r读w写,返回字符串
#上面的是介绍,不是实例,下面的是可以执行的
os.system('cmd')#打开控制台,注意python程序在这里会阻赛
os.system('notepad')#打开记事本,注意python程序在这里会阻赛
os.startfile('GJL.xlsx')#打开excel表,注意python程序在这里不会阻赛
os.spawnl(os.P_NOWAIT,'F:\配套资源《RMMV小彤传》\output\XiaoTongZhuanPC\小彤传1.0\Game.exe',' ')
'''

#random
import random
#伪随机数
random.seed(a=5,version=2)#初始化伪随机数生成器,version是生成算法的版本,不用管
print(random.random(),random.random())#生成伪随机数,0.6229016948897019 0.7417869892607294
#a为None时用系统时间,a非空时只要设置种子时a的值相同,生成的伪随机数序列就相同
#例如,我再设random.seed(5)再跑print(random.random(),random.random())也一样输出
#乱序
k=['cj','love','gjl']
random.shuffle(k)#打乱排序
print(k)#['gjl', 'love', 'cj']
#抽数
print(random.randrange(3,20,4))#11,从整数序列中抽一个数
print(random.randint(5,8))#6,同randrange(5,9),从整数序列中抽一个数
print(random.choice(['cj','love','gjl']))#gjl,从列表中抽一个元素
print(random.sample(['cj','love','gjl'],k=2))#['gjl', 'cj'],从列表中不放回抽2个元素 
print(random.choices(['a','b','c'],[5,5,1],k=4))#['a', 'a', 'b', 'a'],有放回抽4个
print(random.uniform(5,8))#7.50922153993281,生成[a,b]范围的随机数
#分布
print(random.expovariate(lambd=1))#0.39945531631158493,指数分布下生成随机数
print(random.gauss(mu=0,sigma=1))#0.00681644002733326,正态分布下生成随机数
print(random.triangular(low=2,high=4,mode=3))#2.4516069135297096,对称分布下生成随机数
#补充
import collections
deck=collections.Counter(tens=16,low_cards=36)#生成16张tens,36张low_cards
seen=random.sample(list(deck.elements()),k=20)#随机抽20个
print(seen.count('tens')/20)#计算20张抽到的牌中tens的比例

#time
import time
print(time.asctime((2018,2,4,11,8,23,0,0,0)))#Mon Feb  4 11:08:23 2018
print(time.asctime())#Thu Jul  2 09:10:47 2020,以时间元组为单位转时间字符串,默认当前时间
print(time.ctime(30))#Thu Jan  1 08:00:30 1970,以秒数为单位转时间字符串,自动修正时区,默认当前时间
print(time.mktime((2018,2,4,11,8,23,0,0,0)))#1517713703.0,元组格式时间转秒数代表时间
print(time.gmtime(30))#以秒数为单位的时间转时间元组,默认当前时间
print(time.localtime(30))#以秒数为单位的时间转代表当前时间的时间元组,默认当前时间
'''
time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, 
tm_hour=0, tm_min=0, tm_sec=30, tm_wday=3, tm_yday=1, tm_isdst=0)
'''
print(time.perf_counter())#695.421531935718,性能计数器的值
print(time.process_time())#23.421875,当前进程使用CPU时间
#time.sleep(1)#暂停一秒,什么都不干
print(time.time())#1593652248.492522,从1970年1月1日0点整到现在过了多少秒
print(time.timezone)#-28800,返回本地时区的时间偏移,以秒为单位,东八区-28800
print(time.tzname)#('Öйú±ê׼ʱ¼ä', 'ÖйúÏÄÁîʱ'),本地时间名字
print(time.strptime('2018年3月20日','%Y年%m月%d日'))#time.struct_time(...)把字符串恢复成时间元组对象
print(time.strftime('%Y-%m-%d %H:%M:%S'))#2020-07-02 09:24:52,当前时间按格式转字符串
#补充说明
print(time.strftime('%a %A %b %B %c %d'))#星期Thu Thursday 月份Jul July 本地时间Thu Jul  2 09:30:47 2020,本月第几天02 
print(time.strftime('%H %I %j %m %M %p %S %U %w %W'))#09 09 184 07 28 AM 43 26 4 26 
#24小时,12小时,一年第几天,月份数值,分钟数值,上午或下午,分钟数值,一年第几周(首个周日起),星期几,一年第几周(首个周一起)
print(time.strftime('%x %X %y %Y %z %Z %%'))#07/02/20 09:28:43 20 2020 +0800 ?D1¨²¡À¨º¡Á?¨º¡À?? %
#本地日期,本地时间,年份缩写,完整年份,时间偏移,时区名,%号

#json:javascript object notation
import json
print(json.__all__)#['dump', 'dumps', 'load', 'loads', 'JSONDecoder', 'JSONDecodeError', 'JSONEncoder']
#'dump'与'dumps'(dumps把PYTHON对象转成JSON字符串并返回,dump则不返回直接输出到文件)
s=json.JSONEncoder().encode({"names":('cj','gjl')})#与dumps一样效果,不过dumps更高级
print(s)#{"names": ["cj", "gjl"]}
f=open('GJL.json','w')
json.dump(['cj',{'love':'gjl'}],f)
f.close()
s=json.dumps({'c':1,'b':2,'a':3},sort_keys=True)#元素同类型时可以排序
print(s)#{"a": 3, "b": 2, "c": 1}
s=json.dumps([2,1,3,{'x':5,'y':7}],separators=(',',':'),indent=4)
print(s)#,区分元素,:分隔Key与val,indent是缩进空格
'''
[
    2,
    1,
    3,
    {
        "x":5,
        "y":7
    }
]
'''
#'load', 'loads'(loads把JSON字符串转成PYTHON对象并返回,load则从文件获取JSON字符串再转换返回)
f=open('GJL.json')
s=json.load(f)
print(s)#['cj', {'love': 'gjl'}]
s=json.loads('["cj","love","gjl"]')#无非就是List,dict,元素是int,float,str,就这么些组合起来
print(s)#['cj', 'love', 'gjl']


# 定义JSONEncoder的子类实现扩展
import json
class myEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, complex):#complex改成int,str都不允许修改!
            return {'real': obj.real, 'imag': obj.imag}
        return json.JSONEncoder.default(self, obj)
s1 = json.dumps(2 + 1j, cls=myEncoder)
print(s1) # '{"__complex__": "true", "real": 2.0, "imag": 1.0}'
s2 = myEncoder().encode(2 + 1j)
print(s2) # '{"__complex__": "true", "real": 2.0, "imag": 1.0}'
#下面我自己写一个stu36类
class stu36:age=10
class myEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, stu36):
            return {'my age is ': obj.age}
        return json.JSONEncoder.default(self, obj)
p=stu36()
print(json.dumps(p,cls=myEncoder)) #{"my age is ": 10}
print(myEncoder().encode(p)) #{"my age is ": 10}

#re(超级烦的模块)
import re
print(re.__all__)
'''
['match', 'fullmatch', 'search', 'sub', 'subn', 'split', 'findall', 'finditer', 
'compile', 'purge', 'template', 'escape', 'error', 'A', 'I', 'L', 'M', 'S', 'X', 'U',
 'ASCII', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL', 'VERBOSE', 'UNICODE']
'''
#基本参数都是三个(pattern正则表达式,string被匹配的母串,flags旗标)

#compile,search从任意位置检测匹配在第一处匹配就返回,match从开始处匹配
p=re.compile('abc')#得到_src.SRE_Pattern对象,输出p的话是re.compile('abc')
print(p.search("www.abc.com"))#<_sre.SRE_Match object; span=(4, 7), match='abc'>,匹配失败返回None
print(re.search('abc','www.abc.com'))#与上面两行基本等价,串1是否串2子串,返回_sre.SRE_Match类对象
print(re.match('gjl','cj loves gjl'))#None,match只能从开始处匹配,这是与search的区别

#_sre.SRE_Match类对象方法
m = re.search(r'(fkit).(org)', r"www.fkit.org is a good domain")
print(m[0])#fkit.org,调用简化写法,底层是调用m.__getitem__(0)
print(m.group(0))#fkit.org
print(m.span(0))#(4, 12)
print(m[1])#fkit,用简化写法,底层是调用m.__getitem__(1)
print(m.group(1))#fkit
print(m.span(1))#(4, 8)
print(m[2])#org,#调用简化写法,底层是调用m.__getitem__(2)
print(m.group(2))#org
print(m.span(2))#(9, 12)
print(m.groups())#('fkit', 'org')返回所有组所匹配的字符串组成的元组
m2 = re.search(r'(?P<prefix>fkit).(?P<suffix>org)',r"www.fkit.org is a good domain")
print(m2.groupdict()) # {'prefix': 'fkit', 'suffix': 'org'},返回所有组匹配的字符串组成的字典
print(m2.pos)#0,传给正则表达式对象的search()与match()等方法的pos参数
print(m2.endpos)#29,传给正则表达式对象的search()与match()等方法的endpos参数
print(m2.lastindex)#2,最后一个匹配捕获组的索引
print(m2.lastgroup)#suffix,最后组名
print(m2.re)#re.compile('(?P<prefix>fkit).(?P<suffix>org)'),正则表达式
print(m2.string)#www.fkit.org is a good domain,被匹配的母串

#findall返回正则表达式匹配到的子串组成的列表,finditer返回迭代器
print(re.findall('cj','cj loves gjl, cj loves gjl',re.I))#['cj', 'cj']返回一个列表
it=re.finditer('cj','cj loves gjl, cj loves gjl',re.I)
for e in it:#返回迭代器,迭代器元素是_sre.SRE_Match,所以还能有span与group
    print(str(e.span())+'-->'+e.group())#(0, 2)-->cj (14, 16)-->cj
    
#fullmatch要求整个字符串能匹配正则表达式,参数一样是三个,与上面一样
print(re.fullmatch('abc','abc'))#<_sre.SRE_Match object; span=(0, 3), match='abc'>

#sub(pattern正则表达式,repl替换串,string母串,count=0最多替换几次,flags=0旗标)
print(re.sub(r'-','/','I-love-GJL-forever',2))#I/love/GJL-forever,r''表示原始字符串,无视转义字符
def fun(s):#用组名获取匹配内容
    if s.group('lang')=='cj':return '陈俊'
    if s.group('lang')=='gjl':return '龚嘉露'
print(re.sub(r'(?P<lang>\w+)',fun,'cj喜欢gjl',flags=re.A))#陈俊喜欢龚嘉露
#?P<>表示创建一个组,组名在<>里,\w任意字符,+是一到多交次,re.A是ASCII字符
print(re.split(' ','cj loves gjl',maxsplit=1,flags=0))#['cj', 'loves gjl']
re.purge()#清除正则表达式缓存
print(re.escape(r'I love GJL, very much! '))#I\ love\ GJL\,\ very\ much\!\,对ASCII数值_之外的字符进行转义

#旗标
'''
rs.A,rs.ASCII:只匹配ASCII字符而不是所有的Unicode字符
re.DEBUG:显示编译正则表达式的Debug信息
re.I,re.IGNORECASE:不匹分大小写
re.L,re.LOCALE:只对bytes模式下当前区域不区分大小写
re.M,re.MULTILINE:多行模式,^匹配串首与行首,$匹配串尾行尾,原本默认情况不含行首行尾
re.S,s.DOTALL:.匹配所有字符含换行符,原本默认情况不包括换行符
re.U,re.Unicode:能匹配Unicode字符,是多余旗标,默认就是匹配所有Unicode字符
re.X,re.VERBOSE:允许分行书写,为旗标加注释
'''
#正则表达式合法字符
#'''
#x 任意合法字符
#\uhhhh 十六进制值字符
#\t 制表符
#\n 换行符
#\r 回车符
#\f 换页符
#\a 报警符
#\e Escape符
#\cx Ctrl+x,x可换成对应控制符,如M
#'''
#正则表达式特殊字符
'''
$行尾
^行首
()标记子表达式,即组的始末位置
[]确定表达式始末位置
{}标记前面子表达式的出现频度
*指定前面子表达式可以出现零次或一次或多次
+指定前面子表达式可以出现一次或多次
?指定前面子表达式可以出现零次或一次
.匹配除换行符\n外任意单个字符
\转义下一字符,就是本组特殊字符要取消其特殊义时在前面加\
|两项间选一项
'''
#正则表达式预定义字符
'''
.匹配除换行符\n外任意单个字符,re.S,s.DOTALL做旗标时可匹配换行符
\d匹配0~9所有数字
\D匹配非数字
\s匹配所有空白字符,即空格,制表符,回车符,换行符,换页符
\S匹配所有非空白字符
\w匹配所有单词字符,即0~9,a~z,A~Z,_
\W匹配所有非单词字符
'''
print(re.fullmatch(r'\u0041\\','A\\'))#<_sre.SRE_Match object; span=(0, 2), match='A\\'>
print(re.fullmatch(r'\?\[','?['))#<_sre.SRE_Match object; span=(0, 2), match='?['>
print(re.fullmatch(r'\w','c'))#<_sre.SRE_Match object; span=(0, 1), match='c'>
print(re.fullmatch(r'\d\d\d-\d\d\d-\d\d\d\d','123-456-8888'))#<_sre.SRE_Match object; span=(0, 12), match='123-456-8888'>
#正则表达式方括号
#[atxz]枚举,即a,t,x,z中的任一字符
#[a-f]范围,即abcdef中的任一字符
#[^abc]求否,即除abc外的任一字符,[^a-f]即除abcdef外的任一字符
#正则表达式边界匹配符
'''
^ 行首
$ 行尾
\b 单词的边界,只能匹配单词前后的空白
\B 非单词边界,只能匹配不在单词前后的空白
\A 只匹配字符串开头
\Z 只匹配字符串结尾,仅用于最后结束符
'''

#子表达式
print(re.search(r'Windows (95|98|2000)[\w ]+\1','Windows 2000 published in 2000'))
#<_sre.SRE_Match object; span=(0, 26), match='Windows 2000 published in 2000'>
#()中的数字任意匹配一个,\1第一个捕获组所匹配的串,[\w ]+任意单词加一空格组合若干次
print(re.search(r'<(\w+)>\w+</\1>','<h3>xx</h3>'))
print(re.search(r'<(?P<tag>\w+)>\w+</(?P=tag)>','<h3>xx</h3>'))
#<_sre.SRE_Match object; span=(0, 11), match='<h3>xx</h3>'>
#对比易知,?P<tag>表示给当前组命名,后面(?P=tag)就是引用当前组捕获的字符串
#(?:95|98|2000)表示匹配exp表达式但是不捕获,与(95|98|2000)区别就是不捕获后面不能用\1
print(re.search(r'(?<=<h1>).+?(?=</h1>)','cj<h1>loves.com</h1>gjl'))
#<_sre.SRE_Match object; span=(6, 15), match='loves.com'>
#(?<=<h1>)子模式<h1>必须在匹配内容左侧,且<h1>不作为匹配部分。(?<!<h1>)把前面叙述改为必须不在
#(?=</h1>)子模式</h1>必须在匹配内容右侧,且</h1>不作为匹配部分。(?!</h1>)把前面叙述改为必须不在
print(re.search(r'(?i)[a-z0-9_]{3,}(?#CJ)@loves\.gjl','Sum@loves.gjl'))
print(re.search(r'(?i:[a-z0-9_]){3,}(?#CJ)@loves\.gjl','Sum@loves.gjl'))
print(re.search(r'(?-i:[a-z0-9_]){3,}(?#CJ)@loves\.gjl','sum@loves.gjl',re.I))
#<_sre.SRE_Match object; span=(0, 13), match='Sum@loves.gjl'>
#<_sre.SRE_Match object; span=(0, 13), match='Sum@loves.gjl'>
#<_sre.SRE_Match object; span=(0, 13), match='sum@loves.gjl'>
#(?#CJ)是注释,直接无视,{3,}表示前面的表达式出现三次,(?i)行内旗标整行不区分大小写相当于最后加re.I
#(?i[a-z0-9_])只是当前组不区分大小写,(?-i:[a-z0-9_])表示当前组区分大小写即取消旗标re.I效果
#频度限定:{n,m}表示限定前面的式子出现次数为最少n次最多m次(*+?见前面)
                
#贪婪/勉强模式:表达式中的模式会尽可能多/少地匹配字符
print(re.search(r'@.+\.','sun@fkit.com.cn'))#<_sre.SRE_Match object; span=(3, 13), match='@fkit.com.'>
#@.+\.就是以@与.为左右界,.+表示任意非换行字符串且尽可能长,即遇最后一个.才结束
print(re.search(r'@.+?\.','sun@fkit.com.cn'))#<_sre.SRE_Match object; span=(3, 9), match='@fkit.'>
#@.+?\.就是以@与.为左右界,.+?表示任意非换行字符串且尽可能短,即遇第一个.就结束

#set不记录元素添加顺序,元素不允许重复,frozenset元素不可变
c={'cj'}#创建
print(type(c))#<class 'set'>
j=set()#创建
j.add('cj')#加
j.add('gjl')#加
print(len(c),'cj' in c)#1 True
print(c,j,c.issubset(j),c<=j)#{'cj'} {'gjl', 'cj'} True True,子集
print(c,j,j.issuperset(c),j>=c)#{'cj'} {'gjl', 'cj'} True True,母集
c.add('loves')
print(c,j,j-c,j.difference(c))#{'cj', 'loves'} {'gjl', 'cj'} {'gjl'} {'gjl'},差
print(c,j,c&j,c.intersection(j))#{'cj', 'loves'} {'gjl', 'cj'} {'cj'} {'cj'},交
print(c,j,c^j)#{'cj', 'loves'} {'gjl', 'cj'} {'gjl', 'loves'},异或
print(c,j,c.union(j))#{'cj', 'loves'} {'gjl', 'cj'} {'gjl', 'cj', 'loves'},并
#j.difference_update(c)#j变成j-c的集合
#j.intersection_update(c)#j变成j与c的交集
#j.update(c)#j变成j与c的并集
c.add(6)#加
c.remove(6)#删,不存在时报错
c.discard(6)#删,不存在不操作
c.clear()#清空
j.clear()#清空
print(set(range(5)))#{0, 1, 2, 3, 4}
c.add(frozenset('cj loves gjl'))#c.add(j)报错,不能加set
print(c)#{frozenset({' ', 'v', 'l', 's', 'g', 'o', 'j', 'e', 'c'})}

#deque
from collections import deque
dq=deque(('cj','loves'))
dq.append('g')
dq.appendleft('j')
print(dq)#deque(['j', 'cj', 'loves', 'g'])
dq.pop()
dq.popleft()
print(dq)#deque(['cj', 'loves'])
dq.extend(('g','j','l'))
dq.extendleft((5,2,0))
print(dq)#deque([0, 2, 5, 'cj', 'loves', 'g', 'j', 'l'])
dq.insert(3,'1314')
print(dq)#deque([0, 2, 5, '1314', 'cj', 'loves', 'g', 'j', 'l'])
dq.rotate()
print(dq)#deque(['l', 0, 2, 5, '1314', 'cj', 'loves', 'g', 'j'])
dq.clear()
print(dq)#deque([])

#heapq
import heapq
my_data=list(range(10,3,-1))
print(my_data)#[10, 9, 8, 7, 6, 5, 4]
heapq.heapify(my_data)#列表变堆
print(my_data)#[4, 6, 5, 7, 9, 10, 8]
heapq.heappush(my_data,1)#1入堆
print(my_data)#[1, 4, 5, 6, 9, 10, 8, 7]
heapq.heappop(my_data)
print(my_data)#[4, 6, 5, 7, 9, 10, 8],最小值出堆
print(heapq.nlargest(3,my_data))#[10, 9, 8]
print(heapq.nsmallest(3,my_data))#[4, 5, 6]
heapq.heapreplace(my_data,5.5)#最小元素出堆,5.5入堆
print(my_data)#[5, 6, 5.5, 7, 9, 10, 8]
heapq.heappushpop(my_data,7.6)#7.6入堆,最小元素出堆
print(my_data)#[5.5, 6, 7.6, 7, 9, 10, 8]

#collections
from collections import ChainMap#多个map连成chain
a={'cj':1,'gjl':2}
b={'gjl':3,'lovse':4}
c={'loves':5,'cj':6}
d=ChainMap(a,b,c)
print(d)#ChainMap({'cj': 1, 'gjl': 2}, {'gjl': 3, 'lovse': 4}, {'loves': 5, 'cj': 6})
print(d['cj'],d['gjl'],d['loves'])#1 2 5

#Counter
from collections import Counter#本质是dict,val是每个key的频数
c3=Counter(['cj','loves','gjl'])
print(list(c3.elements()))#['cj', 'loves', 'gjl']
print(c3)#Counter({'cj': 1, 'loves': 1, 'gjl': 1})
print(c3['gjl'])#1
c3['gjl']+=3
print(c3.most_common(1))#[('gjl', 4)]
del c3['gjl']
print(c3['gjl'])#0
c2=Counter(cj=7,loves=8)
print(c2,c3)#Counter({'loves': 8, 'cj': 7}) Counter({'cj': 1, 'loves': 1})
c2.subtract(c3)#Counter({'loves': 7, 'cj': 6})#就是对应key都减1
print(c2)
print(Counter('abracadabra'))#Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1})
print(Counter())#Counter()
print(Counter('cj'))#Counter({'c': 1, 'j': 1})
print(Counter({'cj':1,'gjl':2}))#Counter({'gjl': 2, 'cj': 1})
print(Counter(cj=1,gjl=2))#Counter({'gjl': 2, 'cj': 1})
#加减交并正负
c = Counter(Python=4, Swift=2, Kotlin=3, Go=-2)# 创建Counter对象
print(sum(c.values())) # 7统计Counter中所有出现次数的总和
print(list(c)) # ['Python', 'Swift', 'Kotlin', 'Go'],将Counter转换为list,只保留各key
print(set(c)) # {'Go', 'Python', 'Swift', 'Kotlin'},将Counter转换为set,只保留各key
print(dict(c)) # {'Python': 4, 'Swift': 2, 'Kotlin': 3, 'Go': -2},将Counter转换为dict
list_of_pairs = c.items()# 将Counter转换为list,列表元素都是(元素, 出现次数)组
print(list_of_pairs) # dict_items([('Python', 4), ('Swift', 2), ('Kotlin', 3), ('Go', -2)])
c2 = Counter(dict(list_of_pairs))# 将列表元素为(元素, 出现次数)组的list转换成Counter
print(c2) # Counter({'Python': 4, 'Kotlin': 3, 'Swift': 2, 'Go': -2})
print(c.most_common()[:-4:-1])#[('Go',-2),('Swift',2),('Kotlin',3)],获取Counter中最少出现的3个元素
c.clear()# 清空所有key-value对
print(c) # Counter()
c = Counter(a=3, b=1, c=-1)
d = Counter(a=1, b=-2, d=3)
print(c + d)  # Counter({'a': 4, 'd': 3}) 对Counter执行加法
print(c - d)  # Counter({'b': 3, 'a': 2}) 对Counter执行减法
# 对Counter执行交运算
print(c & d) # Counter({'a': 1})
print(c | d) # Counter({'a': 3, 'd': 3, 'b': 1}) 
print(+c) # Counter({'a': 3, 'b': 1})
print(-d) # Counter({'b': 2})

#defaultdict:与dict不同的地方是访问不存在的key时不会报错而是新增key并设val为默认值
#例1比较
from collections import defaultdict
my_dict={}#先开个dict
my_defaultdict=defaultdict(int)#再开个defaultdict,使用int作为defaultdict的default_factory
print(my_defaultdict['a'])#0,将key不存在时,将会返回int()函数的返回值
#print(my_dict['a'])#KeyError
#例2比较
s = [('Python', 1), ('Swift', 2), ('Python', 3), ('Swift', 4), ('Python', 9)]
d = {}#创建dict,目标是把s转成dict,同key的val生成list
for k, vv in s:# setdefault()方法用于获取指定key对应的value.
    d.setdefault(k, []).append(vv)# 如果该key不存在,则先将该key对应的value设置为默认值:[]
print(list(d.items()))#[('Python', [1, 3, 9]), ('Swift', [2, 4])]
s = [('Python', 1), ('Swift', 2), ('Python', 3), ('Swift', 4), ('Python', 9)]
d = defaultdict(list)# 创建defaultdict,设置由list()函数来生成默认值,目标同上
for k, vv in s:# 直接访问defaultdict中指定key对应的value即可。
    d[k].append(vv) # 如果该key不存在,defaultdict会自动为该key生成默认值[]
print(list(d.items()))#[('Python', [1, 3, 9]), ('Swift', [2, 4])]

#namedtuple
from collections import namedtuple
pt=namedtuple('Point',['x','y'])
p=pt(11,y=22)
print(p.x+p.y,p[0]+p[1])#33 33
print(type(pt))#<class 'type'>,其实就是相当于class了一个新类,pt是这个类的别名
print(type(p))#<class '__main__.Point'>,p就是这个Point类的实例,但type(Point)会说未定义
my_data=['east','north']
p2=pt._make(my_data)#由列表创建pt类对象(继承tuple)
print(p2)#Point(x='east', y='north')#创建命名元组对象
print(p2._asdict())#OrderedDict([('x', 'east'), ('y', 'north')]),转成OrderedDict
p2._replace(y='south')#改变y字段的值
print(p2)#Point(x='east', y='north'),改变失败!?书里也是这样的,不是我的问题
print(p2._fields)#('x', 'y'),看所有字段

#OrderedDict:继承dict,先添加的key-val在前,后添加的在后
#例1
from collections import OrderedDict
d=OrderedDict(b=5,c=2,a=7)
d['cj']=3
d['gjl']=1
d['love']=4
d[520]=1
print(d)#OrderedDict([('b', 5), ('c', 2), ('a', 7), ('cj', 3), ('gjl', 1), ('love', 4), (520, 1)])
#例2
my_data = {'Python': 20, 'Swift':32, 'Kotlin': 43, 'Go': 25}
d1=OrderedDict(sorted(my_data.items(),key=lambda t:t[0]))#创建基于key排序的OrderedDict
d2=OrderedDict(sorted(my_data.items(),key=lambda t:t[1]))#创建基于value排序的OrderedDict
print(d1)#OrderedDict([('Go',25),('Kotlin',43),('Python',20),('Swift',32)])
print(d2)#OrderedDict([('Python',20),('Go',25),('Swift',32),('Kotlin',43)])
print(d1==d2)#False
#例3
d = OrderedDict.fromkeys('abcde')
d.move_to_end('b')# 将b对应的key-value对移动到最右边(最后加入)
print(d.keys()) # odict_keys(['a', 'c', 'd', 'e', 'b'])
d.move_to_end('b', last=False)# 将b对应的key-value对移动到最左边(最先加入)
print(d.keys()) # odict_keys(['b', 'a', 'c', 'd', 'e'])
print(d.popitem()[0]) # e  弹出并返回最右边(最后加入)的key-value对
print(d.popitem(last=False)[0]) # b  弹出并返回最左边(最先加入)的key-value对

#itertools
import itertools as it
#例1:三个无限迭代器
for e in it.count(10,3):
    print(e,end='  ')#10  13  16  19  22
    if e>20:break
cj_counter=0
for e in it.cycle(['cj','loves','gjl']):
    print(e,end='  ')#cj  loves  gjl  cj  loves  gjl  
    cj_counter+=1
    if cj_counter>5:break
for e in it.repeat('Python',3):
    print(e,end=' ')#Python Python Python 
print('\n')
#例2:常用
for e in it.accumulate(range(6)):# 默认使用累加的方式计算下一个元素的值
    print(e, end=', ') # 0, 1, 3, 6, 10, 15
print()
for e in it.accumulate(range(1,6),lambda x,y:x*y):#使用x*y的方式来计算迭代器下一个元素的值
    print(e, end=', ') # 1, 2, 6, 24, 120
print()
for e in it.chain(['a', 'b'], ['Kotlin', 'Swift']):# 将两个序列“链”在一起,生成新的迭代器
    print(e, end=', ') # 'a', 'b', 'Kotlin', 'Swift'
print()
for e in it.compress(['a', 'b', 'Kotlin', 'Swift'], [0, 1, 1, 0]):#用第二序列挑选1真保留0假抛弃
    print(e, end=', ') # 只有: 'b', 'Kotlin'
print()
for e in it.dropwhile(lambda x:len(x)<4,['a','b','Kotlin','x','y']):#获取第一个条件为假的元素到最后
    print(e, end=', ') # 只有: 'Kotlin', 'x', 'y'
print()
for e in it.takewhile(lambda x:len(x)<4, ['a','b','Kotlin','x','y']):#从第一个元素开始获取至条件不符合
    print(e, end=', ')  # 只有: 'a', 'b'
print()
for e in it.filterfalse(lambda x:len(x)<4,['a','b','Kotlin','x','y']):#只保留序列中从长度不小于4的元素
    print(e, end=', ') # 只有: 'Kotlin'
print()
for e in it.starmap(pow,[(2,5),(3,2),(10,3)]):#用函数(传入参数对应)计算原序列元素返回结果
    print(e, end=', ') # 32, 9, 1000
print()
for e in it.zip_longest('ABCD','xy',fillvalue='-'):#将'ABCD'、'xy'的元素按索引合并成元组,长度不够用-代替
    print(e, end=', ') # ('A', 'x'), ('B', 'y'), ('C', '-'), ('D', '-')
print('\n')
#例3:排列组合
for e in it.product('AB', 'CD'):# 使用两个序列进行排列组合
    print(''.join(e), end=', ') # AC, AD, BC, BD,
print()
for e in it.product('AB', repeat=2):# 使用一个序列、重复2次进行全排列
    print(''.join(e), end=', ') # AA, AB, BA, BB,
print()
for e in it.permutations('ABCD', 2):# 从序列中取2个元素进行排列
    print(''.join(e), end=', ') # AB, AC, AD, BA, BC, BD, CA, CB, CD, DA, DB, DC,
print()
for e in it.combinations('ABCD', 2):# 从序列中取2个元素进行组合、元素不允许重复
    print(''.join(e), end=', ') # AB, AC, AD, BC, BD, CD,
print()
for e in it.combinations_with_replacement('ABCD', 2):# 从序列中取2个元素进行组合、元素允许重复
    print(''.join(e), end=', ') # AA, AB, AC, AD, BB, BC, BD, CC, CD, DD,
print('\n')

#functools
import functools

#functools.reduce用法
print(functools.reduce(lambda x,y:x+y,range(5)))#10,((1+2)+3)+4
print(functools.reduce(lambda x,y:x+y,range(6)))#15,初始值为默认0
print(functools.reduce(lambda x,y:x+y,range(6),10))#25,设初始值为10

#functools.cmp_to_key用法
class User:
    def __init__(self, name):
        self.name = name
    def __repr__(self):
        return 'Username=%s' % self.name
def old_cmp(u1 , u2):# 定义一个老式的大小比较函数,User的name越长,该User越大
    return len(u1.name) - len(u2.name)
my_data = [User('Kotlin'), User('Swift'), User('Go'), User('Java')]
my_data.sort(key=functools.cmp_to_key(old_cmp))#排序需要关键字参数,调用cmp_to_key将old_cmp转换为关键字参数
print(my_data)

#@functools.lru_cache用法
@functools.lru_cache(maxsize=32)#下面函数使用装饰器,占用缓存32B,使用LRU算法保存最近的(key传入:val传出)
def factorial(n):
    print('~~计算%d的阶乘~~' % n)
    if n==1:return 1
    else:return n * factorial(n - 1)
print(factorial(5))#120 只有这行会计算,然后会缓存5、4、3、2、1的解乘
print(factorial(3))#6
print(factorial(5))#120

#functools.partial用法:为函数的部分参数绑定值
print(int('111'))#111 int函数默认将10进制的字符串转换为整数
print(int('111', 3))#13 int函数根据传入的进制参数把字符串转换为整数
basetwo = functools.partial(int, base=2)# 复制int函数并改变base默认值
print(basetwo('111'))#7 执行复制出来的函数,相当于执行base为2的int()函数
basetwo.__doc__ = '将二进制的字符串转换成整数'#顺手改一下注释

#functools.partialmethod用法:为类中方法的部分参数绑定值
class Cell:
    def __init__(self):
        self._alive = False
    @property# @property装饰器指定该方法可使用属性语法访问
    def alive(self):
        return self._alive
    def set_state(self, state):
        self._alive = bool(state)
    set_alive=functools.partialmethod(set_state,True)#指定set_alive()方法就是将set_state()方法的state参数指定为True
    set_dead=functools.partialmethod(set_state,False)#指定set_dead()方法就是将set_state()方法的state参数指定为False
c=Cell()
print(c.alive)#False
c.set_alive()#相当于调用c.set_state(True)
print(c.alive)#True
c.set_dead()#相当于调用c.set_state(False)
print(c.alive)#False

#total_ordering类装饰器用法:提供lt,le,gt,ge,eq之一函数即可生成其他四个函数
@functools.total_ordering
class User:
    def __init__(self, name):
        self.name = name
    def __repr__(self):
        return 'User[name=%s' % self.name
    def _is_valid_operand(self, other):# 根据是否有name属性来决定是否可比较
        return hasattr(other, "name")
    def __eq__(self, other):
        if not self._is_valid_operand(other):
            return NotImplemented
        return self.name.lower()==other.lastname.lower()#根据name判断是否相等(转成小写比较忽略大小写)
    def __lt__(self, other):
        if not self._is_valid_operand(other):
            return NotImplemented
        return self.lastname.lower()<other.lastname.lower()#根据name判断是否相等(转成小写比较忽略大小写)
print(User.__gt__)# 打印被装饰之后的User类中的__gt__方法

#functools.singledispatch用法:函数重载,同名函数,传入参数类型不同执行不同函数
@functools.singledispatch
def test(arg, verbose):
    if verbose:print("默认参数为:", end=" ")
    print(arg)
test('Python', True) #默认参数为: Python
@test.register(int)#test函数第一个参数为int时,执行下面的函数
def _1(argu, verbose):
    if verbose:print("整型参数为:", end=" ")
    print(argu)
test(20, True)#整型参数为: 20
@test.register(list)#test函数第一个参数为list时,执行下面的函数
def _2(argb, verbose=False):
    if verbose:print("列表中所有元素为:", end=" ")
    for i, elem in enumerate(argb):print(i, elem, end=" ")
test([20, 10, 16, 30, 14], True) #列表中所有元素为: 0 20 1 10 2 16 3 30 4 14 
print() 
def nothing(arg, verbose=False):print("~~None参数~~")#先定义一个函数,不使用函数装饰器
test.register(type(None), nothing)#test函数第一个参数为None时,转向为调用nothing函数
test(None, True) #~~None参数~~
from decimal import Decimal
@test.register(float)#test函数第一个参数为float或Decimal时,执行下面的函数
@test.register(Decimal)
def test_num(arg, verbose=False):
    if verbose:print("参数的一半为:", end=" ")
    print(arg / 2)
print(test_num is test.dispatch(float))#True,test.dispatch(类型)可获取它转向的函数
print(test_num is test.dispatch(Decimal))#True,test()函数第一个参数为float或Decimal时将转向调用test_num
print(test_num is test)#False,直接调用test并不等于test_num
print(test.registry[int])# 获取test函数为int类型绑定的函数,#<function _1 at 0x000001F599CB31E0>
print(test.registry.keys())# 获取test函数所绑定的全部类型
#dict_keys([<class 'object'>, <class 'int'>, <class 'list'>, <class 'NoneType'>, <class 'decimal.Decimal'>, <class 'float'>])

#wraps_test用法:
def fk_decorator(f):
    @functools.wraps(f)#让下面的函数看上去就像f函数,也就是test函数看上去像test函数本身
    def wrapper(*args, **kwds):
        print('调用被装饰函数')
        return f(*args, **kwds)
    return wrapper
@fk_decorator
def test():
    """test函数的说明信息"""
    print('执行test函数')
test()#调用被装饰函数 执行test函数
print(test.__name__)#test,test被装饰后就会变成wrapper函数,然后又被包装回来
print(test.__doc__)#test函数的说明信息

#update_wrapper用法:
def fk_decorator(f):
    def wrapper(*args, **kwds):
        print('调用被装饰函数')
        return f(*args, **kwds)
    #functools.update_wrapper(wrapper, f)#让wrapper函数看上去像f函数
    return wrapper
@fk_decorator
def test():
    """test函数的说明信息"""
    print('执行test函数')
test()#调用被装饰函数 执行test函数
print(test.__name__)#wrapper,一般来说test被装饰后就会变成wrapper函数
print(test.__doc__)#None,wrapper函数没有写说明

关于__init__.py的使用下面补充:

 

 

 

 

 

 

 

 

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值