文章目录
类和对象
# 定义
class students:
"""
self描述的是类自身的对象,由python主动去传入(self不是关键字)
"""
def pro1(self, var1, var2):
self.var1 = var1
self.var2 = var2
# 实例化对象
mem = students()
mem.pro1("abc", 123)
#属性:实例属性与类属性,实例属性是每个实例对象所独自拥有的,可以在外部动态扩充类中定义的实例属性
mem.var1 = "def"
# python中所有数据类型都是引用数据类型,类对象也是,即将同一块内存空间的修改交由不同的对象来完成
#在整个python的引用数据处理之中,都会有一个引用计数器,当它为0时则表示该对象已经成为了垃圾,等待进行回收
#虽然python提供有垃圾收集机制,但垃圾的回收与释放依然需要占用系统资源,可能会带来性能降低问题
a = students()
b = students()
a = b #引用传递、产生垃圾
#属性封装:在属性名称前加入"__"
class students:
"""
外部无法进行封装属性的访问
对于封装属性,使用setter、getter方法操作
"""
def pro1(self, var1, var2):
self.__var1 = var1
self.__var2 = var2
def set_var1(self, var1):
self.__var1 = var1
def get_var1():
return self.__var1
def inner_change(self, tmp)
self.__var1 = "asd" #封装属性可以通过内部访问
mem = students()
mem.inner_change(mem)# 传递本类引用
print(mem.__var1)
构造
# 构造:"__init__()"对类中属性初始化操作,是类对象的操作起点,不允许返回值,只允许定义0或1个构造方法
class stu:
def __init__(self, v1, v2):
"""
python内置的特殊方法,实例化对象时调用
没有明确的定义时,自动生成无参的、不做处理的构造方法
"""
self.__var1 = v1
self.__var2 = v2
dir_list = dir(stu) #列出stu类的结构
print(dir_list)
mem = stu("as", 15)
# python中没有重载的概念,但可以使用(**)关键字参数模拟实现
class stu2
def __init__(self, **keys):
self.__var1 = keys.get("v1")
self.__var2 = keys.get("v2")
def getdata():
return "var1=%s, var2=%s" % (self.__var1, self.__var2)
a = stu2(v1 = "a", v2 = 56)
b = stu2(v1 = "a")# var1 = "a", var2 = None
c = stu2(v2 = 56)
析构
#析构:"__del__()": 对象不再使用时,用del删除对象时,进行某些收尾处理的操作方法
class st3:
"""
析构调用时机:
对象长时间不使用,引用数据为0
del 对象
程序结束时
"""
def __del__():
pass
def getdata():
pass
mem = st3()
del mem
匿名对象
print(st3().getdata())
#匿名对象使用完成后,没有其他对象进行引用,成为垃圾,有可能被垃圾回收进行处理
#匿名对象表示被引用的数量为0,意味着使用完后可能会被立刻回收
类属性
#所有实例化对象所共有的
class example:
info1 = "example test"
print(example.info1) #类属性可以直接通过类名称调用(也可通过对象访问,但通过对象修改时,实际是增加了实例属性)
#当对象没有实例属性时,会自动使用同名的类属性,一但为对象设置了实例属性,就不会再去使用类属性
# python中所有属性都是可以动态增加的,包括类属性
example.info2="test2"
__slots__系统变量
# 可以对定义的属性进行名称限制,定义属性可选范围
def example:
__slots__=("name","age") #类中只允许有name,age两个属性,只能管理实例属性,不限制类属性
example.id = 11 # 正常运行
ep = example()
ep.id = 11 # 报错
内部类
class example:
def func(self):
data = example.inner_class() #内部类的名称:外部类.内部类
data.inner_func()
class inner_class:
"""
虽然定义在外部类的内部,但本质上两个类还是属于彼此独立的关系
内部类可以在任意结构中定义,方法中也可以
"""
def inner_func(self):
pass
#没有封装时,内部类是可以被外部的结构使用的
#内部类封装:"class __inner_class"封装后的内部类只允许被外部类所使用
#如果想在内部类进行外部类的功能调用,就必须明确的向内部类传递一个外部类的实例化对象(不建议使用)
class outer:
def __init__(self):
pass
def getdata(self):
pass
class __inner:
def __init__(self, out): #传递外部类实例
self.__out = out
def getinfo(self):
print(self.__out.getdata())
def func(self):
inobj = outer.__inner(self) #实例化内部类对象
inobj.getinfo()
out = outer()
out.func()
类关联结构
#通过引用实现了现实关联关系的面向对象的抽象转换
# 一对一关联
class Pro1:
# ...
def set_pro2(self, pro2):
self.__pro2 = pro2
def get_pro2(self):
return self.__pro2
def get_info1():
pass
class Pro2:
# ...
def set_pro1(self, pro1):
self.__pro1 = pro1
def get_pro1(self):
return self.__pro1
def get_info2():
pass
#各自实例化对象
a = Pro1()
b = Pro2()
#根据对象引用关系设置关联
a.set_pro2(b)
b.set_pro1(a)
#根据关联关系获取相应的内容
print(a.get_pro2().getinfo2())
print(a.get_pro1().getinfo1())
#自身关联
class A:
def __init__(self):
self.__As = []
def get_As(self):
return self.__As
def get_info(self):
pass
a = A()
a_b = A()
a_c = A()
a.get_As().append(a_b)
a.get_As().append(a_c)
# 通过列表可以实现多方数据的存储,以及动态的扩充
#一对多关联
#依靠列表可以实现不同类型的连接
class A:
def __init__(self):
self.__B = []
def get_B(self):
return self.__B
def get_infoA(self):
pass
class B:
def set_data(self, data):
self.__data = data
def set_A(self, a):
self.__a = a
def get_A(self):
return self.__a
def get_data(self):
if "_B__data" in dir(self): #如果给定的对象有__data属性则返回
return self.__data
else:
return None
def get_infoB(self):
pass
a = A()
b1 = B()
b2 = B()
b3 = B()
#设置B类与A类之间的关系
b1.set_A(a)
b2.set_A(a)
b3.set_A(a)
#设置B实例化对象间的关系
b2.set_data(b1)
b3.set_data(b2)
#设置A类与B类之间的关系
a.get_B().append(b1)
a.get_B().append(b2)
a.get_B().append(b3)
for i in a.get_B():
print(i.getinfoB())
if i.get_data() != None
print(i.get_data().getinfoB())
#合成设计模式:通过不同的类实现子结构定义,最后在一个父结构中进行整合
#可以理解为将完整的整体进行拆分再整合
class A:
pass
class B:
pass
class C:
pass
class chars:
def __init__(self):
self.__a = A()
self.__b = B()
self.__c = []
#...
继承
在已有类的基础上进行扩充
class 父类:
pass
class 子类(父类, 父类,...):
"""
允许同时继承多个父类
可以调用由父类继承而来的操作结构
"""
pass
#子类会继承父类中全部定义的结构
#子类没有定义构造方法时,实例化子类会自动调用父类中提供的无参构造
#当子类定义构造方法时,将不再默认调用父类中的任何构造方法(可手动调用)
#手动调用:
super().__init__() # 由子类调用父类构造,可在子类中任意位置调用,super是系统内部内建模块builtins.py的操作类
#多继承
# 如果子类多继承时出现二义性问题(多个父类定义了相同的方法),会有自己的MRO算法(方法解析顺序,最高的优先调用权)
# 即根据子类继承顺序从左到右
example.mro() #mro()内置函数,通过类名调用,观察类中默认的mro定义
#获取继承信息
class Base:
pass
class pro(Base):
pass
# "__class__" 系统变量,获取对象对应类的相关信息
a = Base()
print(a.__class__)
print(a.__class__.mro())#通过实例化对象调用mro
#动态获取子类与父类的信息
#父类可通过"__subclass__()"函数获取一个子类的列表
#子类也可通过"__bases__"获取继承的父类元组
print(Base.__subclass__())
print(str(pro.__bases__))
#判断某类是否为指定父类的子类,issubclass()
b = pro()
print(issubclass(b.__class__.Base))#判断该实例化对象所属类是否为Base子类,True
print(issubclass(pro.Base))
多态
python中多态的实现有两种:方法覆写、对象多态
所有操作在不同的环境下都可能发生改变
#方法覆写:同名方法
#方法覆写后,若子类仍想调用父类中的方法,只能通过super().方法()进行调用
#python没有强制定义要覆写方法的需求
class son(parient):
def func(self):
super().func()#调用父类中被覆写的方法
#对象多态:本质在于操作类型的不确定性,但这些不确定性有着统一的操作形式
#对象多态性很多时候都需要方法覆写支持
#isinstance(对象, 类) 判断一个实例是否是指定类的对象(包括父类),True、False
class Base:
pass
class pro1(Base):
pass
#...
class example:
def callclass(self, msg):
if isinstance(msg, Base) #操作限定
print(msg.getdata()) #统一操作方法
print(isinstance(pro1(), Base)) #True
#object父类:唯一没有继承父类的类
#python设计时,为所有类(不论是否明确的编写了继承关系)都定义了一个父类:object
#object类中只定义了一些基本的公共操作行为,但其中的方法大多数都属于python的特殊方法
#(python2中:经典类(不继承object,解决mro问题使用深度优先算法)、新式类(继承object,解决mro问题使用广度优先算法)
#(python3中,所有类都会被默认继承object父类)
代理设计模式
# 通过代理业务子类操作核心业务子类
class Food:
def eat(self):
pass
class FoodReal(Food):
def eat(self):
print("核心业务子类")
class FoodProxy():
def __init__(self, food):
self.__food = food
def prepare(self):
pass
def clear(self):
pass
def eat(self):
self.prepare()
self.__food.eat()
self.clear()
print("代理业务子类")
def get_food_instance():
return FoodProcy(FoodReal())
data = get_food_instance()
if data != None
data.eat()
对象操作支持
# __new__()构造器,__init__()构造方法是在__new__()特殊方法之后调用的
def example:
def __new__(cls, *args, **kwargs):
#...
return object.__new__(cls) #继续执行本类的构造"__init__()",object父类
#__new__()优先并可以控制__init__()方法的执行,可以返回其他类型的对象实例,利用"__new__()"的调用才产生了"__init__()"中的当前对象信息
#获取对象信息,直接输出对象,默认获取的只是对象的地址编码信息
class A:
pass
a = A()
print(a)#a.__str__(),a.__repr__(),输出结果都相同
#object类中已经提供了__str__(),__repr__()的方法,由于需要考虑所有的类对象,所以只能获得对象所在类的名称以及对应的内存地址信息
#若一个类对象有自己的直接输出要求,可通过覆写此特殊方法来实现
class B:
def __init(self, data):
self.__data = data
def __str__(self):
"""
为了进行对象内容的直接输出
"""
return "__str__():%s" % self.__data
def __repr__():
"""
是为了留给开发者使用的
通过交互式环境观察,在交互式环境直接输出b,会调用__repr__()
"""
return "__repr__():%s" % self.__data
b = B("aaa")
print(b) #__str__():aaa
print(str(b)) # __str__():aaa
print(repr(b)) # __repr__():aaa
# 方法引用定义对象输出,若__str__(),__repr__()输出内容相同,则使用方法引用
class B:
def __init(self, data):
self.__data = data
def __str__(self):
return "__str__():%s" % self.__data
__repr__ = __str__
b = B("aaa")
print(str(b)) # __str__():aaa
print(repr(b)) # __str__():aaa
#对象比较
#__eq__(self, other) 比较对象:==
#__ne__(self, other) 比较对象:!=
#__lt__(self, other) 比较对象:<
#__le__(self, other) 比较对象:<=
#__gt__(self, other) 比较对象:>
#__ge__(self, other) 比较对象:>=
#__bool__(self) 获取布尔环境内容
class example:
def __init__(self, idnum):
self.__idnum = idnum
def __ge__(self,other):
if not isinstance(other, example) or other == None:
return False
return self.__idnum >= other.__idnum
def __bool__(self):
return self.idnum > 12
a = example(15)
b = example(14)
print(a.__ge__(b)) #True
print(a >= b) #True
if a: #直接布尔型操作
print("ok")
#对象格式化,通过"__format__()"自定义格式化对象
class example:
def __init__(self, num, name):
self.__num = num
self.__name = name
def __format__(self, format_spec):
if format_spec == "": #没有设置格式化标记
return str(self)
format_data = format_spec.replace("%num", self.__num).replace("%name", self.__name)
return format_data
def __str__(self):
return "data:%s and %s" % (self.__num,self.__name)
a = example("014","aaa")
print("{}".format(a)) #没有定义格式化标记,采用空格式,#data:014 and aaa
print("info:%num:%name".format(info = a)) #014:aaa
#可将列表中保存的多个类对象内容格式化
class examplelist:
def __init__(self,msgs):
self.__msgs = msgs
def __format__(self, format_spec):
if format_spec == "":
return str(self)
format_data = "\n".join("{:{fs}}".format(m,fs = format_spec) for m in self.__msgs)
return format_data
msg_list = examplelist([example("001","a"), example("002", "b")])
print("info:%num:%name".format(info = msg_list))
#可调用对象:__call__()
class example:
def __call__(self, *args, **kwargs):
return "__call__"
a = example()
print(callable(a)) #系统函数,判断对象是否可调用
print(a()) #"__call__",可传参
#动态导入: __import__() 动态实现模块的导入控制,类似import
m1 = __import__("模块名") #定义要导入的模块(得存在)
getdata_obj = getattr(m1, "getdata") #获取函数对象
print(getdata_obj())
msg_class = getattr(m1, "msg") #获取类
print(msg_class().getinfo())
属性操作支持
# 调用拦截:调用属性或方法时会自动在目的操作执行前执行一些其他的处理
#"__getattribute__()"
class example:
def __getattribute__(self, item):
"""
item 描述的是拦截的内容,但无法区分是属性还是方法
所有拦截处理操作都是自动完成的
若是方法可返回其他方法的引用实现方法替换
"""
print("__getattribute__:item = %s" % item)
return object.__getattribute__(self, item) #放行
def get_data(self,data):
print("%s" % data)
msg = example()
msg.m = "aaa"
print(mag.m)
print(msg.get_data("bbb"))
#__getattribute__:item = m
#aaa
#__getattribute__:item = get_data
#bbb
#实例属性字典:object类中定义的一个变量:"__dict__ = {}"保存着所有的实例属性(可动态配置)
class example:
def __init__(self, data):
self.__data = data
exa = example("aaa")
exa.info = "bbb"
print(exa.__dict__) # {'_example__data':'aaa', 'info':'bbb'},_example__data封装属性名
#进行属性操作时,还会有一组属性的拦截方法,属性监听:
#设置属性拦截:"__setattr__()"
#获取属性拦截:"__getattr__()"
#删除属性拦截:"__delattr__()"
class example:
def __init__(self, data):
self.__data = data
def get_data(self):
return self.__data
def del_data(self):
del self.__data
def __setattr__(self, key, value):
print("__setattr__: key = %s, value = %s" % (key, value))
self.__dict__[key] = value
def __getattr__(self, item):
"""
属性不存在时才会拦截
"""
print("__getattr__: item = %s" % item)
return "属性不存在:%s" % item
def __delattr__(self, item):
print("__delattr__: item = %s" % item)
self.__dict__.pop(item)
exa = example("aaa")
print("%s" % exa.get_data())
print("%s" % exa.nodata)#获取不存在的属性
print("%s" % exa.del_data())
"""
__setattr__: key = _example__data, value = aaa
aaa
__getattr__: item = nodata
属性不存在:nodata
__delattr__: item = _example__data
"""
#属性字典中的操作本身是自动完成的,若使用属性监听,必须自行进行字典内容的控制
#获取子类实例化信息:当子类实例化时,父类也可以获取一些信息的:"__init_subclass__()"
class parent:
def __init_subclass__(cls, **kwargs):
"""
kwargs:表示可以配置一些参数
子类继承父类时还可以定义一些元数据参数信息
"""
print("cls = %s, kwargs = %s" % (cls, kwargs))
class sub(parent, num = "123"):
def __init__(self):
print("sub_init")
s = sub()
"""
cls = <class '__main__.sub'>, kwargs = {'num':'123'}
sub_init
"""
序列操作支持
通过一些特殊方法可以让对象按序列的形式进行处理
#自定义迭代操作
# "__iter__(), __next__()"
def example:
def __init__(self, maxnum):
self.__max = maxnum #允许迭代的最大值
self.__foot = 0 #迭代当前的下标
def __iter__(self): #获取iterable对象
"""
表示有迭代能力
"""
return self
def __next__(self):
"""
表示可以进行迭代处理
"""
if self.__foot >= self.__max:
return -1
#可以抛出异常,停止迭代,调用不用break:raise StopIteration()
else:
val = self.__max - self.__foot
self.__foot += 1
return val
msg = example(5)
for i in msg: #对象可以直接for循环
if i == -1:
break
#没有break,死循环:5、4、3、2、1、0、-1、-1、-1、-1...
print(i, end = "、")
#对象反转
#"__reversed__()"
class example:
def __init__(self):
self.__list = ["a", "b", "c"]
def get_list(self):
return self.__list
def __reversed__(self):
self.__list = reversed(self.__list) #反转后保存
exa = example()
reversed(exa) # c b a
#对象字典操作支持
#"__setitem__(),__getitem__(),__len__(),__delitem__()"
class example:
def __init__(self):
self.__map = {}
def __setitem__(self,key,value):
"""
设置数据
"""
self.__map[key] = value
def __getitem__(self):
return self.__map[item]
def __len__(self):
return len(self.__map)
def __delitem__(self,key):
self.__map.pop(key)
exa = example()
exa["num"] = "123"# 调用__setitem__
print(exa["num"])# 调用__getitem__
print(len(exa))# 调用__len__
del exa["num"]# 调用__delitem__
装饰器
实现一些特殊程序结构定义
#"inspect.stack()"返回详细的调用信息
class example:
def get_data(self):
logwriting()
def logwriting():
import inspect
method_name = inspect.stack()[1][3] #可动态获取调用其的方法的名称
print(method_name)
#logwriting本身不属于方法所需功能,但不定义又无法调用,但通过装饰器就可以将其操作形式拿到另外与方法不冲突,却又可以为方法服务的地方
#装饰器,本质是python的函数,采用切面的形式保证核心代码不做修改的情况下进行切面控制
#在不影响程序开发的情况下,为核心功能附加一些其他的内容
#使用:@装饰器函数名称,在需要的地方进行包装的处理操作
def logwriting(func): #定义装饰器,接收操作函数,由python传递
"""
需要嵌套,对真实调用的操作方法进行包装
"""
def wrapper(*args,**kwargs):
print("%s" % func.__name__) #动态获取包装函数的名称
return func(*args,**kwargs) #继续调用被包装函数操作
return wrapper #返回装饰内部函数
class example:
@logwriting #不破坏原始的方法结构
def get_data(self):
print("aaa")
@logwriting
def get_info(self):
print("bbb")
exa = example()
exa.get_data()
"""
get_data
aaa
"""
#装饰器接收参数,需要再加一层包装
def logwriting(level = "INFO"): #接收参数
def wrapper(func):
def inner_wrapper(*args,**kwargs):
print("%s:%s" % (func.__name__, level))
return func(*args,**kwargs)
return inner_wrapper
return wrapper
class example:
@logwriting() #使用参数默认值
def get_data(self):
print("aaa")
@logwriting(level = "DEBUG") #传参
def get_info(self):
print("bbb")
基于类定义装饰器
#要求类变成可调用的对象结构,即需要提供"__call__()"
class log:
def __init__(self, level):
self.__level = level
def __call__(self, func):
def inner_wrapper(*args,**kwargs):
print("%s:%s" % (func.__name__, self.__level))
return func(*args,**kwargs)
return inner_wrapper
class example:
@log()
def get_data(self):
print("aaa")
@log(level = "DEBUG")
def get_info(self):
print("bbb")
wrapt模块
#减少装饰器的一层嵌套
import wrapt #第三方模块
@wrapt.decorator #使用wrapt模块自动包装
def logwriting(wrapped, instance, args, kwargs): #接收:包装对象,实例对象,操作的参数
print("%s" % wrapped.__name__)
#接收参数
import wrapt
def logwriting(level = "INFO"):
@wrapt.decorator
def logwriting_wrapper(wrapped, instance, args, kwargs):
print("%s" % wrapped.__name__)
return wrapped(*args, **kwargs)
return logwriting_wrapper
内置装饰器
#静态方法
#可由类名称直接进行调用
#python没有直接提供静态方法的支持,但能通过装饰器来实现
class example:
@staticmethod #使用内部的装饰器
def get_data(): #静态方法
"""
提高内存的使用率,不开辟无用的内存空间
"""
return "aaa"
print("%s" % example.get_data())
#静态方法不能直接调用普通方法,使用必须实例化对象
#类方法
#可以直接被类名称调用的方法
#@classmethod 内部的装饰器,类方法中必须接收一个当前类的参数
#主要作用:为弥补构造方法(只允许一个)缺陷问题,先处理再实例化(return 实例化对象)
class example:
def __init__(self, num1, num2):
pass
@classmethod
def get_data(clazz): #clazz,当前类型的参数,可以实例化本类对象,后面可继续传参数
clazz().get_info()
print(clazz)
def get_info(self):
print("data")
@classmethod
def get_instance(clazz, data):
return clazz(data[0], data[1])
example.get_data()
a = example.get_instance([12,25])
"""
data
<class '__main__.example'>
"""
#属性访问:针对于封装属性访问的优化设计
#使用属性装饰器简化操作
class example:
def __init__(self,info):
self.__info = info
@property #整个操作方法作为一个实例属性出现
def info(self):
return self.__info
@info.setter #名称需要统一,有关联性的
def info(self,info)
self.__info = info
@info.deleter
def info(self):
del self.__info
exa = example("aaa")
exa.info = "bbb" #直接访问属性
print(exa.info) #直接访问属性,实际访问的是info()方法
del exa.info
# bbb
异常
导致程序中断执行的一种指令流
# 异常处理
# try,except.finally,else
try:
"""
可能产生异常的语句
若发生异常,try后续语句不执行
"""
[except 异常类型 [as 对象(别名)]:
异常处理
except 异常类型 [as 对象]:
异常处理
...]#异常若未处理,程序仍会发生中断
[else:
异常未发生时的执行语句]
[finally:
异常的统一出口]#始终会执行
#程序产生异常时,python虚拟机会自动的帮助开发者实例化一个异常类对象
#若没有提供异常处理操作机制,会交由虚拟机采用默认形式处理(打印异常信息,中断程序执行)
#若有提供异常处理操作机制,则自动实例化的异常类对象将由try自动进行捕获,随后交由except语句进行异常类型匹配(按定义顺序依次匹配处理)
#若执行完毕后发现异常无法处理,则交由虚拟机进行默认处理,已经处理则继续执行后续代码
#所有子类的对象实例都可以通过父类的对象实例进行匹配,那么所有的异常都可以通过Exception(所有用户能处理的异常基本都由其继承而来)进行接收
"""
...
except Exception as err:
print("发生异常")
...
"""
#获取异常的完整信息,traceback模块
import traceback
try:
#...
except Exception as err:
print("%s" % traceback.format_exc())
#抛出异常:raise
try:
raise NameError("程序发生错误")
except Exception as err:
print("%s" % err) #程序发生错误
class example:
def get_data(self): #希望子类覆写此方法
raise NotImplementedError("get_data未覆写")
#raise还可以基于已有的异常继续进行异常抛出
def func():
try:
raraise NameError("程序发生错误")
except Exception as err:
print("%s" % err)
raise TypeError("类型错误") from err #通过已有的异常抛出
try:
func()
except Exception as err:
print("%s, cause = %s" % (err, err.__cause__))#类型错误, cause = 程序发生错误
#__cause__ 系统属性:异常引发的原因
#不想异常追加到__cause__系统变量中,raraise NameError("程序发生错误") from None
#上下文管理:with
#上下文管理
#一种管理上下文的管理机制,在某个上下文内可以重复使用资源的结构,结合__enter__()与__exit__()使用
class example:
class __connect:
def build(self):
#...
return True
def close(self):
pass
#上下文开启
def __enter__(self):
print("__enter__=============begin")
self.__con = example.__connect()
if not self.__con.build():
print("error")
return self
#上下文关闭
def __exit__(self, exc_type, exc_val, exc_tb):
"""
exc_type:如果抛出异常,此处返回异常类型
exc_val:如果抛出异常,此处返回异常内容
exc_tb:如果抛出异常,此处返回异常出现的位置
"""
print("__exit__=============end")
self.__con.close()
def send(self, data):
print("%s" % data)
with example() as ea #所有操作都受到当前上下文的管理
ea.send("a")
ea.send("b")
ea.send("c")
#由with进行上下文的状态管理
"""
__enter__=============begin
a
b
c
__exit__=============end
"""
#自定义异常类
class CustomError(Exception):
def __init__(self, msg = "CustomError"):
self.__msg = msg
def __str__(self):
return self.__msg
序列结构扩展
#set集合:python中提供的一个集合定义类
#原生的列表允许进行重复保存,set集合不允许保存重复的内容,同时可进行集合运算(set集合主要目的),无序的(不保存数据的存储索引)
"""
add(self, element),追加数据
clear(self),清空数据
copy(self),浅拷贝
discard(self, element),若元素存在则删除
update(self, seq),更新集合数据
remove(self, element),删除元素
pop(self),弹出一个元素
difference(self, t),计算两集合差集, 等价于s - t
intersection(self, t),计算两集合交集, 等价于s & t
symmetric_difference(self, t),计算两集合对称差集, 等价于s ^ t
union(self, t),计算两集合并集, 等价于s | t
集合运算:调用方法或符号计算都可
"""
info_set = set(["a", "b", "c", "b"]) #set()接受序列
print(info_set) # {'c','b','a'}
info_set.add("hhh")
data1 = set("abcd")
data2 = set("bdfg")
print("%s" % (data1 ^ data2)) # {'a', 'c', 'f', 'g'}
#deque双端队列
#使用必须依赖于collections模块
"""
append(self, element),队尾追加数据
appendleft(self, element),队头追加数据
clear(self),清空数据
count(self, element),获取指定元素在队中出现次数
pop(self),从队头弹出数据
popleft(self),从队尾弹出数据
remove(self, element),删除指定数据
reverse(self),反转
"""
from collections import deque
info_deque = deque(("aaa","bbb"))
info_deque .append("ccc")
info_deque .appendleft("ddd")
print("%s" % info_deque) # deque(['ddd', 'aaa', 'bbb', 'ccc'])
print(info_deque.pop()) # ddd
#heapq堆
#基于数据的完全二叉树实现,有序,会按照中序遍历的形式进行数据获取,可以从中获取到一个有序的序列数据操作
"""
heapify(iterable),向堆中追加一个可迭代对象,如列表
heappush(heap, element),向堆中保存数据
heappop(heap),从堆中移除并弹出一个最小值
heappushpop(heap, ele),先push,再pop
heapreplace(heap, ele),先pop,再替换
nlargest(n, heap, key = fun),获取前n个最大值
nsmallest(n, heap, key = fun),获取前n个最小值
"""
import heapq #操作模块
data = [5,9,8,6,2]
heapq.heapify(data) #基于迭代对象创建一个堆
heapq.heappush(data, 0) #会自动进行原始列表的更新
print("%s" % heapq.nlargest(2,data)) #[9,8]
#enum枚举
#定义好了数据的可用范围,python没有直接进行枚举的原生支持,需导入enum模块
import enum
@enum.unique #使用装饰器防止value内容重复
class sex(enum.Enum): #必须强制继承父类
WOMAN = 0
MAN = 1
sex_a = sex.MAN #直接通过枚举类获取所需要的一个对象
print("%s : %s" % (sex_a.name, sex_a.value)) #MAN 1
生成器
对要进行操作的数据进行一种编号
需要一个编号就生成一个编号,而不是一次全部生成(未全部使用前需要占用大量内存空间)
#yield关键字
#作用与return相似,进行数据的返回,但其除了进行数据的返回也可以进行数据的发送
def generator():
print("begin")
yield "001"
print("end")
ret = generator() #获取生成器对象(内部有yield,返回的为生成器对象)
#获取返回内容 "next(生成器对象)"
print("%s" % next(ret))
"""
begin
001
"""
#向生成器中发送数据 "生成器对象.send(数据)"
def generator():
print("begin")
res = yield "001"
print("end: %s" % res)
yield "002"
ret = generator()
print("%s" % next(ret))
print("%s" % ret.send(10))
"""
begin
001
end: 10
002
"""
#整个生成器函数不是一次执行完毕的,而是可以持续和调用处沟通
#利用该模式实现的生成器可避免过大的内存占用
def generator(maxnum):
for item in range(1, maxnum):
print("a")
yield "id-{num:0>20}".format(num = item)
print("b")
for item in generator(5):
print(item)
"""
a
id-00000000000000000001
b
a
id-00000000000000000002
b
a
id-00000000000000000003
b
a
id-00000000000000000004
b
"""
#"yield from iterable" 可迭代对象的处理(如生成器,列表,元组),根据已有的迭代对象返回另外一个生成器,类似于迭代的操作形式
"""
相当于:
for item in iterable:
yield item
"""
def fin(max):
a, b = 0, 1
while b < max:
yield b
a, b = b, a+b
def fin_wrapper(fun_iterable):
yield from fun_iterable
wrap = fin_wrapper(fin(66))
for item in wrap:
print(item,end="、")
# 1、1、2、3、5、8、13、21、34、55、
#contextlib模块
#使用contextlib模块直接在函数中进行上下文管理
from contextlib import contextmanager
class message:
def send(self, info):
print("%s" % info)
@contextmanager #装饰器可简化with操作
def message_wrap(): #上下文管理
class __connect:
def build(self):
pass
def close(self):
pass
try:
con = __connect()
if con.build():
yield message()
else:
yield None
except:
print("异常")
finally:
con.close()
with message_wrap() as msg:
msg.send("aaa")
#资源管理时,若只是通过上下文进行关闭的处理操作,也可以自动调用close()方法
#自动关闭的支持
from contextlib import closing
class connect:
def __init__(self):
print("aaa")
def close(self):
print("ccc")
with closing(connect()) as con:
print("bbb")
"""
aaa
bbb
ccc
"""
#异常压制
#在明确可能不会返回数据的情况时,可以进行错误的压制,suppress
from contextlib import contextmanager,suppress
class message:
def send(self, info):
print("%s" % info)
@contextmanager
def message_wrap():
class __connect:
def build(self):
print("mmm")
return False
def close(self):
print("nnn")
try:
con = __connect()
if con.build():
yield message()
finally:
con.close()
with suppress(RuntimeError,TypeError): #根据需求加入要压制的异常,压制异常
with message_wrap() as msg:
msg.send("aaa")
"""
mmm
nnn
"""
日期时间
time模块
#内置的实现日期时间的操作模块
"""
时间戳:自1970.1.1 00:00:00起以秒为单位的时间的偏移量
时间元组:保存日期时间数据的元组结构对象
tm_year=年
tm_mon=月 1-12
tm_mday=日 1-31
tm_hour=时 0-23
tm_min=分 0-59
tm_sec=秒 0-61(60或61是闰秒)
tm_wday=一周第几天 0-6 0是周一
tm_yday=一年第几天 1-366 儒略历
tm_isdst=1(夏令时) 0(非夏令时) 默认-1
格式化日期时间:按指定标记进行格式化处理
"""
"""
time() 获取当前时间戳
process_time() #返回cpu耗时时间,第一次调用返回进程时间,第二次调用返回距离第一次调用所耗费时间
localtime([secs]) 时间戳转本地时间元组,若未设置时间戳,返回当前时间元组
mktime(struct_time_instance)时间元组转时间戳
asctime([t])将时间元组转为日期时间字符串,若未设置则取出当前日期时间,(内置格式)
ctime([secs])将时间戳转为日期时间字符串,若未设置则取出当前日期时间,(内置格式)
gmtime([secs])返回指定时间戳对应的UTC时区(0时区)时间元组
strptime(time_str, time_format_str)将日期时间字符串转为时间元组,同时设置转换格式
strftime(time_format_str, struct_time_instance)将时间元组转为日期时间字符串
"""
import time
start_time= time.process_time() #获取程序启动的cpu耗时
timestamp = time.time()
print(timestamp)
time_tuple = time.localtime(timestamp)
print("%s" % str(time_tuple ))
#time.struct_time(tm_year=2023, tm_mon=3, tm_mday=15, tm_hour=19, tm_min=23, tm_sec=50, tm_wday=2, tm_yday=74, tm_isdst=0)
tmptime_tuple = (2023,3,15,19,25,45,2,74,0)
print(time.mktime(tmptime_tuple))
print("%s" % time.strftime("%Y-%m-%d %H:%M:%S", tmptime_tuple))
print("%s" % time.strftime("%F", tmptime_tuple))#获取时间元组中的日期数据:2023-03-15
print("%s" % time.strftime("%T", tmptime_tuple))#获取时间元组中的时间数据:19:25:45
str_time = "2023-03-15 19:25:45"
print(time.strptime(str_time,"%Y-%m-%d %H:%M:%S"))
end_time = time.process_time() #获取程序执行完毕耗时
#日期时间格式化标记:还有很多,使用时自行查询
#使用内置格式化结构格式化时间元组
print(time.asctime())
print(time.asctime(time_tuple))
calendar模块
主要进行年历或日历的显示,实现整体的日历计算处理,同时可以实现闰年的判断
import calendar
#显示月历
calendar.setfirstweekday(calendar.MONDAY) #控制从周几开始,默认周一
mon = calendar.month(2023,3)
print(mon)
"""
March 2023
Mo Tu We Th Fr Sa Su
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
"""
# 显示年历:
#calendar.calendar(year, w = 2, l = 1, c = 6, m = 3) year指定年份,w每个单元格宽度,l每列换行数,c月份之间间隔宽度,m12个月显示的列数
ye = calendar.calendar(2023)
print(ye)
"""
2023
January February March
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 1 2 3 4 5 1 2 3 4 5
2 3 4 5 6 7 8 6 7 8 9 10 11 12 6 7 8 9 10 11 12
9 10 11 12 13 14 15 13 14 15 16 17 18 19 13 14 15 16 17 18 19
16 17 18 19 20 21 22 20 21 22 23 24 25 26 20 21 22 23 24 25 26
23 24 25 26 27 28 29 27 28 27 28 29 30 31
30 31
April May June
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 1 2 3 4 5 6 7 1 2 3 4
3 4 5 6 7 8 9 8 9 10 11 12 13 14 5 6 7 8 9 10 11
10 11 12 13 14 15 16 15 16 17 18 19 20 21 12 13 14 15 16 17 18
17 18 19 20 21 22 23 22 23 24 25 26 27 28 19 20 21 22 23 24 25
24 25 26 27 28 29 30 29 30 31 26 27 28 29 30
July August September
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 1 2 3 4 5 6 1 2 3
3 4 5 6 7 8 9 7 8 9 10 11 12 13 4 5 6 7 8 9 10
10 11 12 13 14 15 16 14 15 16 17 18 19 20 11 12 13 14 15 16 17
17 18 19 20 21 22 23 21 22 23 24 25 26 27 18 19 20 21 22 23 24
24 25 26 27 28 29 30 28 29 30 31 25 26 27 28 29 30
31
October November December
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 1 2 3 4 5 1 2 3
2 3 4 5 6 7 8 6 7 8 9 10 11 12 4 5 6 7 8 9 10
9 10 11 12 13 14 15 13 14 15 16 17 18 19 11 12 13 14 15 16 17
16 17 18 19 20 21 22 20 21 22 23 24 25 26 18 19 20 21 22 23 24
23 24 25 26 27 28 29 27 28 29 30 25 26 27 28 29 30 31
30 31
"""
#判断闰年
print(calendar.isleap(2023)) #False
print(calendar.leapdays(2023,2123))#2023-2123之间的闰年个数 24
datetime模块
针对于time模块的包装(time模块中原始的日期时间数据格式操作有些麻烦),针对性的作出一些改进
#核心类:date,time,datetime,timedelta,tzinfo
#datetime.date,专门进行日期操作的类,直接进行日期构造或将时间戳中的日期数据取出
from datetime import date
import time
print("可以描述的最小日期:%s,最大日期:%s,可以表示日期的最小单位:%s" % (date.min,date.max,date.resolution))
print("今天日期:%s" % date.today())
tmptime_tuple = (2023,3,15,19,25,45,2,74,0)
print("通过时间元组抽取日期:%s" % date.fromtimestamp(time.mktime(tmptime_tuple)))
#其实是通过时间戳
"""
可以描述的最小日期:0001-01-01,最大日期:9999-12-31,可以表示日期的最小单位:1 day, 0:00:00
今天日期:2023-03-16
通过时间元组抽取日期:2023-03-15
"""
da = date(2023,3,16) #构造对象
print("星期数:%s, ISO星期数:%s" % (da.weekday(), da.isoweekday()))#0-6 1-7
print("格式化日期显示:%s" % da.isoformat())
print("日期元组:%s" % str(da.isocalendar()))
print("日期替换:%s" % da.replace(2001,1,1))
"""
星期数:3, ISO星期数:4
格式化日期显示:2023-03-16
日期元组:(2023, 11, 4)
日期替换:2001-01-01
"""
#time类:时间的操作,时、分、秒、微秒
from datetime import time
ti = time(1,12,55,5446) #构造对象,参数可选,还有tzinfo参数
print("时间数据:%s,%s,%s,%s" % (ti.hour,ti.minute,ti.second,ti.microsecond))
#时间数据:1,12,55,5446
#还包含方法:isoformat()获取格式化时间字符串HH:MM:SS.ssssss,strftime(fmt)通过格式化字符串获取时间,replace([hour[,minute[,second[,microsecond[,tzinfo]]]]])参数与构造相同
#属性:max,min,resolution(微秒)
#datetime类:日期时间的集合
from datetime import datetime
da = datetime(2023,3,16,1,12,55,5446) #构造日期时间对象
#datetime(year,month,day[,hour[,minute[,second[,microsecond[,tzinfo]]]]])
print("日期时间:%s" % da) #日期时间:2023-03-16 01:12:55.005446
"""
还包含方法:
today()获取本地当前日期时间类对象
now([tzinfo])获取本地当前日期时间或指定时区日期时间类对象
utcnow()获取当前utc日期时间类对象(格林威治时间)
fromtimestamp(timestamp[,tz])根据时间戳创建日期时间类对象
utcfromtimestamp(timestamp)根据时间戳创建日期时间类对象
combine(date,time)根据date和time类实例创建datetime对象
strptime(date_string, format)将格式化字符串转为datetime对象
"""
#timedelta类:实现日期时间间隔操作
from datetime import datetime,timedelta
da = datetime(2023,3,16,1,12,55,5446)
da2 = da + timedelta(hours = 45) #45小时后的日期时间
da3 = da + timedelta(days = -10) #10天前的日期时间
print(da2)
print(da3)
"""
2023-03-17 22:12:55.005446
2023-03-06 01:12:55.005446
"""
#tzinfo类:设置时区描述,需要子类,且覆写方法:"tzname()时区的名字,utcoffset()偏移量,dst()夏令时"
from datetime import timedelta,tzinfo,datetime
class UTC(tzinfo):
def __init__(self, offset = 0):
self.__offset = offset
def tzname(self, dt):
return "UTC+%s" % self.__offset
def utcoffset(self, dt):
return timedelta(hours=self.__offset)
def dst(self,dt):
return timedelta(hours=self.__offset)
ca = datetime(2023,3,16,1,37,54,tzinfo = UTC(8))
g = datetime(2023,3,16,1,37,54,tzinfo = UTC(1))
print("本地日期时间:%s" % ca)
print("德国:%s" % g)
print("本地日期时间转德国:%s" % (ca.astimezone(UTC(1))))
print("时差:%s" % (ca-g))
"""
本地日期时间:2023-03-16 01:37:54+08:00
德国:2023-03-16 01:37:54+01:00
本地日期时间转德国:2023-03-15 18:37:54+01:00
本地日期时间:2023-03-16 01:37:54+08:00
德国:2023-03-16 01:37:54+01:00
本地日期时间转德国:2023-03-15 18:37:54+01:00
时差:-1 day, 17:00:00
"""
正则表达式
利用一些特殊符号实现的字符串处理操作,主要作字符串的拆分、替换、匹配的操作实现支持
#并非python的原生定义范畴之内,需要导入re模块
import re
#match只能从首部开始匹配, match(pattern, string, flags=0)
print("从头开始匹配:%s" % re.match("abcd", "abcdsfg")) #匹配成功返回match类对象
print(re.match("abcd", "abcdsfg").span()) #span()可以获取match类的匹配的索引位置(元组)
print("匹配失败:%s" % re.match("adscd", "abcdsfg"))
print("忽略大小写匹配:%s" % re.match("aBcd", "abcdsfg", re.IGNORECASE))
print("忽略大小写匹配:%s" % re.match("ABCD", "abcdsfg", re.I))
"""
从头开始匹配:<re.Match object; span=(0, 4), match='abcd'>
(0, 4)
匹配失败:None
忽略大小写匹配:<re.Match object; span=(0, 4), match='abcd'>
忽略大小写匹配:<re.Match object; span=(0, 4), match='abcd'>
"""
#任意位置匹配,search(pattern, string, flags=0)
print(re.search("abcd","asdaabcdlk"))
print(re.search("abCd","asdaabcdlk",re.I)) #忽略大小写
"""
<re.Match object; span=(4, 8), match='abcd'>
<re.Match object; span=(4, 8), match='abcd'>
"""
"""
compile(pattern, flags=0) 进行正则表达式编译
escape(pattern) 正则符号转义处理
findall(pattern, string, flags=0)匹配正则符号,并将匹配的内容以列表的形式返回
finditer(pattern, string, flags=0)匹配正则符号,将匹配内容以迭代对象的形式返回
purge()清除缓存中的正则表达式
split(pattern, string, maxsplit=0, flags=0)按照给定匹配符号进行字符串拆分
sub(pattern, repl, string, count=0, flags=0)正则匹配替换,count表示替换次数
subn(pattern, repl, string, count=0, flags=0)正则匹配替换,并返回替换结果
"""
正则匹配符号
"""
x:表示匹配任意的一位字符
匹配对应的转义字符:\\ \t \n \r
[abc]:匹配a、b、c中的任意一位
[^abc]:取反,匹配不是a、b、c中的任意一位
[a-zA-Z]:匹配范围中的一位,表示全部字母,包括大小写
[0-9]:匹配数字中的一位
^设置正则匹配开始,忽略多行模式
$设置正则匹配结尾,忽略多行模式
单独出现只匹配单边,开头或结尾,要考虑边界问题,否则匹配所有内容
?:匹配字符出现0或1次
*:匹配字符出现0或1次或多次
+:匹配字符出现1次或多次
{n}:匹配字符出现n次
{n,}:匹配字符出现n次以上
{n,m}::匹配字符出现n-m次
简化正则表达式
\A:等价^
\Z:等价$
\b:匹配开始或结束位置的空字符串
\B:匹配不在开始或结束位置的空字符串
\d:匹配数字,等价[0-9]
\D:匹配非数字,等价[^0-9]
\s:匹配任意的一位空格,等价[\t\n\r\f\v]
\S:匹配任意的一位非空格,等价[^\t\n\r\f\v]
\w:匹配任意的一位字母(大小写)、数字、_,等价[a-zA-Z0-9_]
\W:匹配任意的一位非字母(大小写)、数字、_,等价[^a-zA-Z0-9_]
.:表示任意一位字符
"""
import re
s = "id-11"
d = "id-[0-9]"
print(re.match(d,s,re.I))
dd = "^id-[0-9]$" #整个字符串必须完整的符合于当前的正则格式
print(re.match(dd,s,re.I))
s2 = "asdid-2daid-7"
print(re.findall(d,s2,re.I))
"""
<re.Match object; span=(0, 4), match='id-1'>
None
['id-2', 'id-7']
"""
st = "a4sa4d56454as4"
p = r"\d+"
print(re.split(p,st)) #['a', 'sa', 'd', 'as', ''] 按照给定的符号进行拆分
#字符串能接收的都是转义字符,'\d'是正则字符,应写"\\d",python帮助简化可以直接使用'\d',最早是需要在字符串前加上r,表示里面按照正则规则编写,现在可加可不加
p = r"^[+-]?\d+(\.\d+)?$"
#正则表达式编写时,可将一组的正则使用"()"进行定义,则可单独为其设置一些量词定义,打印()时需加上\转义,有特殊含义
"""
逻辑表达:正则表达式A、B
AB:表达A后继续表达式B
A|B:表达A或B,二选一
"""
#正则匹配模式
p = """
[0-9] #匹配数字
[a-zA-Z] #匹配字母
"""
"""
I、IGNORECASE 忽略大小写
L、LOCALE 字符集本地化表示,可匹配不同语言环境下的符号
M、MULTILINE 多行匹配模式(默认会有)
S、DOTALL 修改"."匹配任意模式,可匹配任意字符包括换行符(默认不包括换行符)
X、VERBOSE 忽略正则表达式中的空白和注释(#),正则表达式可使用多行模式在其中添加注释
U、UNICODE "\w、\W、\b、\B、\d、\D、\s、\S"匹配符号将按照UNICODE定义
可以同时定义,使用"|"相连
"""
#分组:方便从匹配的内容之中获取所需要的内容
data = "name:abc, num:123456, bir:1900-01-01"
p = r"(\d{4})-(\d{2})-(\d{2})"
ma = re.search(p,data)
print(ma.group())
print(ma.group(1))
print(ma.group(2))
print(ma.group(3))
p2 = r"(?P<year>\d{4})-(?P<mon>\d{2})-(?P<day>\d{2})"
ma = re.search(p2,data)
print(ma.group())
print(ma.group(1))
print(ma.group("mon"))
print(ma.group("day"))
"""
1900-01-01
1900
01
01
1900-01-01
1900
01
01
"""
"""
(...)默认分组捕获模式,可单独取出分组内容,索引自1开始
(?iLmsux)设置分组模式"i、L、m、s、u、x"
(?...)分组不捕获模式计算索引会跳过该分组
(?P<name>...)分组命名模式,可通过索引编号或name名获取内容
(?P=name)分组引用模式:可在正则表达式中引用前面命名过的正则表达式
"""
#环视:依据其他内容的位置进行匹配处理
import re
data = "na:aaa,num:101;na:bbb,num:202"
p = r"(?<=na:)(?P<name>\w+)"
print(re.findall(p,data))
# ['aaa', 'bbb']
"""
(?=...)顺序肯定环视,表示所在位置右侧能匹配括号内正则表达式
(?!...)顺序否定环视,表示所在位置右侧不能匹配括号内正则表达式
(?<=...)逆序肯定环视,表示所在位置左侧能匹配括号内正则表达式
(?<!...)逆序否定环视,表示所在位置左侧不能匹配括号内正则表达式
"""
测试
代码测试
python提供有第三方测试工具:doctest、unittest
doctest
#基于文档模式实现的测试操作,文档mymain.py
import doctest
#在程序中对于执行部分使用>>>进行描述,结果部分直接编写
def add(x,y):
"""
>>>add(10,15)
25
>>>add(156,254)
410
"""
return x+y
def main():
doctest.testmod(verbose=True) #生成详细的输出
if __name__ == "__main__":
main()
#测试成功,代码正常执行,失败则将错误信息输出,自动标注
#也可以将测试代码单独定义在一个文件内 test_mymain.txt
>>> from mymain import add
>>> add(4,6)
10
#命令行运行,python -m doctest -v test_mymain.txt
#-m要引入的模块,-v要进行详细的测试结果的输出
unittest
实现的是单元测试组件(单独定义专属测试类)
#test_mymain.py:直接运行
from mymain import mathadd
import unittest
class Test(unittest.TestCase): #继承父类
#实现测试的前置及后置处理
#总体前置,类方法
@classmethod
def setUpClass(cls):
print("unittest begin")
#总体后置
@classmethod
def tearDownClass(cls):
print("unittest end")
#每个测试前置
def setUp(self):
print("begin test:%s" % self.id())
#每个测试后置
def tearDown(self):
print("end test:%s" % self.id())
#测试用例
def test_add(self):
self.assertEqual(mathadd().add(5,6), 11) #测试
@unittest.skip("(mathadd().getdata()功能不再测试") #跳过测试
def getdata(self):
self.assertEqual(mathadd().getdata(20), 20)
"""
#mymain.py
class mathadd:
def add(x,y):
return x+y
def getdata(data):
return data
"""
#编写一个获取测试目录的形式进行整体测试运行,即集中测试
import unittest
import os #系统模块,获取相应目录
class RunAlltest(unittest.TestCase):
def test(self):
casePath = os.getcwd() #获取程序当前目录
#匹配所有以"test_*"命名的测试文件
discover = unittest.defaultTestLoader.discover(casePath, pattern="test_*.py")
#操作输出级别定义:简单(0)、普通(1)、详细(2)
runner = unittest.TextTestRunner(verbosity = 2)
runner.run(discover) #运行所有的测试文件
if __name__ == "__main__":
unittest.main() #启动测试
性能测试
分析功能的执行速度,cpu的占用率
#cProfile性能分析(python提供有profile性能分析模块,和cProfile模块(c编写))
import cProfile
def adds(max):
sum = 0
for i in range(max):
sum += i
return sum
cProfile.run("adds(1000000)")
"""
4 function calls in 0.091 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.091 0.091 <string>:1(<module>)
1 0.091 0.091 0.091 0.091 main.py:3(adds)
1 0.000 0.000 0.091 0.091 {built-in method builtins.exec}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
"""
"""
ncalls:函数调用次数
tottime:函数总运行时间
percall:函数运行一次的平均时间
cumtime:函数总计运行时间
percall:函数运行一次的平均时间
filename:lineno(function):函数所在文件名、代码行数、函数名称
"""
# pstats模块
cProfile.run("adds(100000000)", "d:\\test.result") #将测试结果保存在二进制文件中
#通过pstats模块加载该报告的内容
import pstats
stats = pstats.Stats("d:\\test.result") #加载测试报告
stats.sort_stats("time") #测试时间排序
stats.print_stats() #打印操作结果
代码规范性
#代码编写遵守PEP规范标准,代码规范化检测工具:pylint、flake8
#pylint,不是python环境的默认组件,需要额外安装(pip)
pylint mymain.py #执行代码规范性检测
#提示级别:Error(错误)、Warning(警告)、Refactor(重构)、Convention(规范)
#文件中忽略错误信息,在相应位置加上:pylint:disable=提示信息或错误编码
# PyCharm中使用需要额外单独配置扩展执行项
#flake8:python官方发布的代码规范性的检测工具,可以通过编程式的方式进行代码规范性的检测
#需要额外的下载
flake8 mymain.py
# PyCharm中使用需要额外单独配置扩展执行项
from flake8.api import legacy
if __name__ == "__main__":
check_style = legacy.get_style_guide(ignore = "E301")#得到测试的规则,ignore 可设置忽略的错误信息
check_style.excluded("t001.py") #设置需要排除的文件(本文件),不做规范性的检测
check_style.check_files(["mymain.py"]) #检测的文件