python(十)——反射与异常

反射

	就是利用字符串来操作相同值的属性或者方法,比如导入模块、调用函数,属性等等,
	反射是一种编程方法体现,凝聚了高内聚、松耦合的编程思想,
	不能简单的用执行字符串exec和eval来代替。
'''
4个相关的内置函数
hasattr(obj,str):检查模块或者对象中是否有某个成员
getattr(obj,str):获取成员
setattr(obj,str,value):设置成员
delattr(obj,str):删除成员
'''
#反射类中相关属性
class Student:
    school = '小学'
    def __init__(self,name):
        self.__name = name
    
    @staticmethod
    def test():
        print('test')
    
ret = input('请输入一个属性')
if hasattr(Student, ret):
    r = getattr(Student, ret)   #以字符串形式调用类中的属性
    #getattr(Student, 'school')
    print(r)
else:
    print('The target class does not have this property')
        
if  hasattr(Student, 'test'): 
    foo = getattr(Student, 'test')
    foo() #以字符串形式调用对象的方法
    delattr(Student, 'test') #删除对象属性
    setattr(Student, 'age','25')	#设置属性
    setattr(Student,'show_name',lambda self:self.name+'sb')	#设置方法
    #del Student.test 等价于 delattr(Student, 'test')
#类名.__dict__获取类中所有属性,包括方法名
#对象.__dict__获取当前对象的所有动态属性

#反射模块中的属性,方法
#getattr(模块名,'属性名/方法名')

#面向函数编程中,当前模块中没有class只有def 函数,如何调用自身模块
import sys
print(sys.modules[__name__]) #当前模块
print(getattr(sys.modules[__name__],'函数名/属性名')) 
class Student:
    school = '小学'
    def __init__(self,age,sex):
        self.age = age
        self.__sex = sex

    @property
    def dictproperty(self):
        return self.__dict__


stu = Student(23,'男')
print(stu.__dict__) # {'age': 23, '_Student__sex': '男'}
# 对于非私有的动态属性可以通过对象.__dict__获取一个对象所有属性组成的字典
print(stu.dictproperty) # {'age': 23, '_Student__sex': '男'}

__方法

'''
__str__:将对象转为字符串
__repr__:将对象转为字符串
__len__:获取序列长度
__del__:析构方法,当对象在内存中被释放或del 对象时,自动触发执行
__call__方法:对象()或者类()()时会调用这个方法
__eq__:自定义比较方法,此对象做==比较时运行;不实现,默认比较对象的值
__hash__:根据不可变数据类型的对象地址返回一串数字
'''
class Test():
    def __str__(self):
        print('这是__str__方法')
        return 'abc'

t = Test()
print(t)
print(str(t))
print('%s'%(t))
'''
这是__str__方法
abc
这是__str__方法
abc
这是__str__方法
abc
'''
#%s 和 str() 和print() 时都是调用对象的__str__方法
#如果没有就去父类找,没有就去object中找
#object中的__str__方法就是返回调用这个方法的对象的内存地址
#__str__方法必须返回一个字符串

    def __repr__(self):
        print('这是__repr__方法')
        return '123'

t = Test()
print(repr(t))
#这是__repr__方法
#123
#repr() 和 %r 都是调用对象的__repr__方法
#object中__repr__方法默认打印内存地址

#注意__repr__方法是__str__方法的备选
#%s 和 str() 和print() 时,对象中没有__str__方法却有__repr__方法,就会去执行__repr__方法;都没有,去父类找

    def __len__(self):
        print('JQK')
        return 10
t = Test()
print(len(t))	
#JQK
#10
#len()本质是调用了对象的__len__方法,必须返回一个数值
#object中没有实现__len__方法,所以一般类调用len(obj)会报错
#如list,tuple,dict等存放数据的容器都实现了__len__方法获取存储数据的个数
  name = 'zs'
    def __init__(self,age):
        self.age = age
    def __del__(self):
        print('删除属性前的收尾工作')
t = Test(23)
print(t.name)
t.sex = '男' 
print(t.sex) 
#zs
#男
#删除属性前的收尾工作
#在执行del 属性 或者当前程序运行结束时会自动调用对象的__del__方法
   def __call__(self):
        print('这是call方法')
t = Test()
t()
#这是call方法
#一个对象后接()调用时,相当于调用自身的__call__方法,没有会报错
'''
__eq__: 
        对象中重写了__eq__,那么此对象在做对象比较时会按照自定义的__eq__来判断是比较值还是内存地址
        对于不可变数据类型(tuple,str等等),值相同的对象在内存中只存在一个,==和is都是一样的
        对于可变数据类型(list,set,dict等等),==默认比较对象的内容,is比较的是对象的内存地址                                              
'''
class Test:
    def __init__(self, name):
        self.name = name

    def __eq__(self, other):  # 此对象 == 判断时,运行此方法
        if self.__dict__ == other.__dict__:  # 比较值是否一致
            # __dict__返回属性名与属性值组成的字典,字典是可变数据类型,==比较的是字典的内容是否一致
            print("==")
            return True
        else:
            return False


t1 = Test('zs')
t2 = Test('zs')
print(t1 == t2)  # True
print(t1 is t2)  # False
'''
==
True
False
'''
'''
__hash__:根据对象的内存地址得到一串的数字,hash()会调用__hash__
         只有不可变数据类型才有hash值,如tuple,int,str等等
'''
class Test:
    def __init__(self,name,age):
        self.name = name
        self.age = age
     
    def __hash__(self): #自定义hash方法
        if self:
            return hash(self.name)  
        #只根据对象的name值得到hash值,而不是根据整个对象得到哈希值
t1 = Test('zs',23)
t2 = Test('zs',24)
print(hash(t1)) #-571755659779486090
print(hash(t2)) #-571755659779486090
'''
内置函数与__方法的依赖:
set(obj)【将对象转为去除重复元素的集合】:此方法依赖__eq__和__hash方法

 - random模块的choice(list)

【获取列表/元组/字符串等随机一个元素】:此方法依赖于__len__和__getitem__
from random import choice 
class Test:
    dict = ['k','f','h']
    def __init__(self,name,age):
        self.name = name
        self.age = age
     
    def __len__(self):
        print('4566')
        return len(self.dict)
    def __getitem__(self,item):
        return self.dict[item]
 
t = Test('zs',23)       
print(choice(t))
#4566
#f 随机一个元素
'''        

item系列的__方法

	以字典的方式去操作属性
	通常属性调用 	对象.属性
		属性设置		对象.new属性 = value
		属性删除 		del	对象.属性
	item系列 	
		属性调用		对象['属性名']
		设置属性		对象['new属性名'] = value
		属性删除		del	对象['属性名']
class Test():
    def __init__(self,name):
        self.name = name
        
    def __getitem__(self,item):
        if hasattr(self, item):
            print('获取属性')
            return self.__dict__[item]
        else:
            print('属性名错误')
        
    def __setitrm__(self,key,value):
        print('设置属性')
        self.__dict__[key] = value
        
    def __delitem__(self,key):
        if hasattr(self, key):
            print('删除属性')
            self.__dict__.pop(key)
        else:
            print('属性名错误')
        

d = Test('zs')
print(d['name'])#获取属性
d['sex'] = '男'	#设置属性
print(d['sex'])
del d['name']	#删除属性
      

关于删除的__方法

	__del__	删除对象相关
	__delattr__	删除对象属性相关
	__delitem__	以字典形式删除对象属性相关
class Test():
    def __init__(self,name):
        self.name = name
        
    def __del__(self):
        print(self)
        print('del 删除对象')
        
    def __delattr__(self, *args, **kwargs):  
        print (' delattr删除对象属性')  
        return object.__delattr__(self, *args, **kwargs)
        
    def __delitem__(self,key):
        if hasattr(self, key):
            print('delitem 以字典形式删除对象属性')
            self.__dict__.pop(key)
        else:
            print('属性名错误')
        
t = Test('zs')
print(t)
del t.name
#删除对象属性,调用__delattr__方法,此时程序未结束,不会销毁t,
#不会调用删除对象的__del__方法

t1 = Test('ls')
print(t1)
del t1['name']
#以字典形式删除对象属性,调用__delitem__方法,程序未结束,不会销毁t1对象

t1 = Test('ww') 
#此时Test('ww')将Test('ls')的内存地址覆盖,Test('ls')没有引用指向,
#会被销毁,调用__del__方法,销毁Test('ls')对象
print(t1)#输出Test('ww')的内存地址
delattr(t1,'name') #删除Test('ww') 的属性,调用__delattr__方法
#程序运行到此即将结束,销毁其余所有对象,先创建的先销毁,先销毁t对象再销毁t1对象
'''
 <__main__.Test object at 0x000000000265C348>
 delattr删除对象属性
<__main__.Test object at 0x000000000265C388>
delitem 以字典形式删除对象属性
<__main__.Test object at 0x000000000265C388>
del 删除对象
<__main__.Test object at 0x000000000265C3C8>
 delattr删除对象属性
<__main__.Test object at 0x000000000265C348>
del 删除对象
<__main__.Test object at 0x000000000265C3C8>
del 删除对象

总结 :
	del 对象.属性 或者 delattr(对象,'属性')时会调用__delattr__方法
	del 对象['属性'] 时会调用__delitem__方法
	以上是属性删除
	del 对象 或对象销毁(在内存中被释放)时会调用__del__方法
'''      

对象的创建,初始化与释放

class Test():
    def __init__(self,name):
        print('初始化')
        self.name = name
        
    def __new__(cls, *args, **kwargs):
        print('new function')
        return object.__new__(cls)
    def __del__(self):
        print('对象被释放了')
    
t = Test('zs')
#new function
#初始化
#对象被释放了
'''
类()实例化时,会先去自身的new方法,没有就去object的new方法来创建对象,再返回给self
此时self是不存在的,所以用cls表示这个类,用cls来实例化对象,再赋值给self
然后运行init方法给self初始化(给对象设置属性)
程序运行结束前会释放所有对象
'''

异常

	try:
				可能出现的异常
	except 具体异常类型:
				对异常的处理
	except 具体异常类型:
				对异常的处理
	finally:
			pass
		
	except 可以有多个,except Exception / except 捕捉所有异常,一般写在最后
	无论异常是否发生,finally中的代码都会执行
	即使调用了sys模块的exit函数退出Python环境,finally块仍会被执行
	exit函数实质上是引发了SystemExit异常

	except语句不是必须的,finally语句也不是必须的,但是二者必须要有一个,否则就没有try的意义了。
	使用dir()函数来查看Exceptions中的异常类型
#处理迭代器取值越界异常
l = [1,2,3,4]
it = l.__iter__()
try:
    while 1:
        print(it.__next__())
except StopIteration:
    print('发生了异常',StopIteration)	#发生了异常 <class 'StopIteration'>
else:
    print('没有异常发生时,执行此代码')
finally:
    print('即使发生异常,此代码一样执行')
#1
#2
#3
#4
#发生了异常 <class 'StopIteration'>
#即使发生异常,此代码一样执行
def fun():

    try:
        with open('测试文件.txt', 'r', encoding='utf-8') as f:
       		 print(f.read())
    except FileNotFoundError as g:
	    print(g)#错误信息
        print('文件找不到!')#错误提示
    except LookupError as l:
    	print(l)#错误信息
        print('未知的编码错误!')#错误提示
    except UnicodeDecodeError as u:
    	print(u)#错误信息
        print('文件解码错误!')#错误提示
    finally:
		print('finally')


if __name__ == '__main__':
    fun()

尽量使用内置的语法范式代替try/except

比如for语句就处理了的StopIteration异常
with语句在打开文件后会自动调用finally并关闭文件
不确定一个类中是否有这个属性时,使用反射获取即可
name = getattr(test, 'name', 'default')

raise抛出异常

如果不希望异常在当前位置被捕获,可以直接使用raise关键字将这个异常抛出给上一级去处理
raise关键字后面可以指定你要抛出的异常实例,一般来说抛出的异常越详细越好
捕捉到了异常,但是又想重新抛出它(传递异常),使用不带参数的raise语句即可
raise NameError("Not a number !")
 try:
    with open('file') as f :
    	print(f.read())
    except Exception as e:
    	e.args += ('more info',)#抛出异常前对异常的信息进行更新
        raise

自定义异常类型

需要直接或间接继承Exception类即可
class MyException(Exception):
    pass

Exception 和 BaseException

BaseException是最基础的异常类,Exception继承了它。
BaseException除了包含所有的Exception外还包含了SystemExit,KeyboardInterrupt和GeneratorExit三个异常
所有在捕获所有异常时更应该使用Exception而不是BaseException,因为被排除的三个异常属于更高级别的异常

单例模式

	单例模式:java设计模式之一,只允许实例化一个对象
	可以通过上面的__new__方法来实现
	
	Python 的模块就是天然的单例模式,因为模块在第一次导入时,
	会自动添加到sys.modules中;下次再次导入时,会先去sys.modules中查看,
	如果有这个模块直接调用就行,不会再次导入

最简单的单例

#singletons.py
class Singleton(object):
    def foo(self):
        pass
singleton = Singleton()

#其他类导入singletons模块并重命名 
#other.py
import singletons as s
print(s.singleton)#获取模块中的变量

__new__方法实现的单例

class Singleton:
    __instance = False

    def __init__(self,name,age):
        self.name = name
        self.age = age 
    
    def __new__(cls,*args,**kwargs):
        if not cls.__instance:
            cls.__instance = object.__new__(cls)
        return cls.__instance
    
s1 = Singleton('张三','23')
print(id(s1))   #32079112
s2 = Singleton('李四','24')
print(id(s2))   #32079112

#后续多线程阶段可以继续优化

使用装饰器的单例

def Singleton(cls):
    __instance = {}

    def _singleton(*args, **kargs):
        if cls not in __instance:
            __instance[cls] = cls(*args, **kargs)
        return __instance[cls]

    return _singleton


@Singleton
class Student(object):
    def __init__(self, name):
        self.name = name


a1 = Student('zs')
print(id(a1))	#40288520
a2 = Student('ls')
print(id(a1))	#40288520

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下 4载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下载 4使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下载 4使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值