python基础总结二

类和对象

# 定义
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"]) #检测的文件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值