面向对象进阶
isinstance和issubclass
isinstance(object, classinfo)检查是否obj是否是类 cls 的对象
class Foo(object):
pass
obj = Foo()
print(isinstance(obj,Foo))
issubclass(sub, super)检查sub类是否是 super 类的派生类
class Foo(object): pass class Bar(Foo): pass issubclass(Bar, Foo)
反射:是用字符串类型的名字去操作变量
反射 就没有安全问题
1 什么是反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。
2 python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
四个可以实现自省的函数
下列方法适用于类和对象(一切皆对象,类本身也是一个对象)
反射对象中的属性和方法 hasattr getattr setattr delattr
class A: def func(self): print('in func') a = A() a.name = 'alex' a.age = 63
反射对象的属性
ret = getattr(a,'name') #getattr(a,'name')=a.name # 通过变量名的字符串形式取到的值
print(ret)
print(a.__dict__) #把属性和值按键值对的形式存放在字典内
'''
{'name': 'alex', 'age': 63}
'''
变量名 = input('>>>') # func #输入属性来取值 print(getattr(a,变量名)) print(a.__dict__[变量名]) #a.__dict__实际上是一个字典,按照键来取值
反射对象的方法 就是让函数执行
a.func() ret = getattr(a,'func') #getattr(a,'func')=a.func
ret()
反射类的属性
class A: price = 20 A.price print(getattr(A,'price')) #getattr(A,'price')=A.price
class Foo: f = '类的静态变量' def __init__(self,name,age): self.name=name self.age=age def say_hi(self): print('hi,%s'%self.name) obj=Foo('egon',73) #检测是否含有某属性 print(hasattr(obj,'name')) print(hasattr(obj,'say_hi')) #获取属性 n=getattr(obj,'name') print(n) func=getattr(obj,'say_hi') func() print(getattr(obj,'aaaaaaaa','不存在啊')) #报错 #设置属性 setattr(obj,'sb',True) setattr(obj,'show_name',lambda self:self.name+'sb') print(obj.__dict__) print(obj.show_name(obj)) #删除属性 delattr(obj,'age') delattr(obj,'show_name') delattr(obj,'show_name111')#不存在,则报错 print(obj.__dict__)
反射类的方法 :classmethod staticmethod
class A: price = 20 @classmethod def func(cls): print('in func') A.func() if hasattr(A,'func'): #查找A。func存在不,不存在就报错 getattr(A,'func')() #getattr(A,'func')=A.func
模块
反射模块的属性
import my_module print(my_module.day)#模块名.属性名 print(getattr(my_module,'day'))
反射模块的方法
getattr(my_module,'read1')()
内置模块也能用
import time print(getattr(time,'time')()) print(getattr(time,'asctime')())
反射自己模块中的变量
import sys year = 2018 print(sys.modules['__main__'].year) print(getattr(sys.modules['__main__'],'year'))
反射自己模块中的函数
import sys def qqxing(): print('qqxinng') sys.modules['__main__'].qqxing() getattr(sys.modules['__main__'],'qqxing')()
变量名 = input('>>>')
getattr(sys.modules['__main__'],变量名)()
要反射的函数有参数怎么办?
import time print(time.strftime('%Y-%m-%d %H:%M:%S')) print(getattr(time,'strftime')('%Y-%m-%d %H:%M:%S'))
一个模块中的类能不能反射到?
#in my_module.py class A: print('nihao') #in my.py import my_module print(getattr(my_module,'A')())
setattr 修改设置属性
class A: name = '222' def __init__(self,name): self.name = name a = A('111')
print(A.name) print(a.name) setattr(a,'name','nezha') setattr(A,'name','alex') print(A.name) print(a.name) print(A.__dict__) print(a.__dict__)
delattr #删除一个变量
class A: name = '222' def __init__(self,name): self.name = name a = A('111') print(A.name) print(a.name) setattr(a,'name','nezha') setattr(A,'name','alex') print(A.name) print(a.name) delattr #删除一个变量 delattr(a,'name') print(a.name) delattr(A,'name') print(a.name)
内置的类方法
内置的类方法和内置的函数有着千丝万缕出的联系
双下方法
__str__和__repr__
改变对象的字符串显示__str__,__repr__
自定制格式化字符串__format__
object 里有一个__str__,一旦被调用,就返回调用这个方法的对象的内存地址 l = [1,2,3,4,5] # 实例化 实例化了一个列表类的对象 print(l) %s str() 直接打印 实际上都是走的__str__ %r repr() 实际上都是走的__repr__ repr 是str的备胎,但str不能做repr的备胎 print(obj)/'%s'%obj/str(obj)的时候,实际上是内部调用了obj.__str__方法,如果str方法有,那么他返回的必定是一个字符串 如果没有__str__方法,会先找本类中的__repr__方法,再没有再找父类中的__str__。 repr(),只会找__repr__,如果没有找父类的
#_*_coding:utf-8_*_ format_dict={ 'nat':'{obj.name}-{obj.addr}-{obj.type}',#学校名-学校地址-学校类型 'tna':'{obj.type}:{obj.name}:{obj.addr}',#学校类型:学校名:学校地址 'tan':'{obj.type}/{obj.addr}/{obj.name}',#学校类型/学校地址/学校名 } class School: def __init__(self,name,addr,type): self.name=name self.addr=addr self.type=type def __repr__(self): return 'School(%s,%s)' %(self.name,self.addr) def __str__(self): return '(%s,%s)' %(self.name,self.addr) def __format__(self, format_spec): # if format_spec if not format_spec or format_spec not in format_dict: format_spec='nat' fmt=format_dict[format_spec] return fmt.format(obj=self) s1=School('oldboy1','北京','私立') print('from repr: ',repr(s1)) print('from str: ',str(s1)) print(s1) ''' str函数或者print函数--->obj.__str__() repr或者交互式解释器--->obj.__repr__() 如果__str__没有被定义,那么就会使用__repr__来代替输出 注意:这俩方法的返回值必须是字符串,否则抛出异常 ''' print(format(s1,'nat')) print(format(s1,'tna')) print(format(s1,'tan')) print(format(s1,'asfdasdffd'))
class B: def __str__(self): return 'str : class B' def __repr__(self): return 'repr : class B' b=B() print('%s'%b) print('%r'%b)
__del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
__del__ class A: def __del__(self): # 析构函数: 在删除一个对象之前进行一些收尾工作 self.f.close() a = A() a.f = open() # 打开文件 第一 在操作系统中打开了一个文件 拿到了文件操作符存在了内存中 del a # a.f 拿到了文件操作符消失在了内存中 del a # del 既执行了这个方法,又删除了变量 引用计数
class Foo: def __del__(self): print('执行我了!') f1 = Foo() del f1 print('----->')
__call__
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
class A: def __init__(self,name): self.name = name def __call__(self): ''' 打印这个对象中的所有属性 :return: ''' for k in self.__dict__: print(k,self.__dict__[k]) a = A('alex')()
class Foo: def __init__(self): pass def __call__(self, *args, **kwargs): print('__call__') obj = Foo() # 执行 __init__ obj() # 执行 __call__
item系列
__getitem__\__setitem__\__delitem__
class Foo: def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def __getitem__(self, item): #通过双下划方法可以不用通过print(f.name)来取值,用print(f['name'])类似字典的方式取值 if hasattr(self,item): return self.__dict__[item] def __setitem__(self, key, value): #设置修改属性,有就覆盖,没有就添加 self.__dict__[key] = value def __delitem__(self, key): #删除属性 del self.__dict__[key] f = Foo('egon',38,'男') print(f['name']) f['hobby'] = '男' print(f.hobby,f['hobby']) del f.hobby # object 原生支持 __delattr__ del f['hobby'] # 通过自己实现的 print(f.__dict__)
class Foo: def __init__(self,name): self.name=name def __getitem__(self, item): print(self.__dict__[item]) def __setitem__(self, key, value): self.__dict__[key]=value def __delitem__(self, key): print('del obj[key]时,我执行') self.__dict__.pop(key) def __delattr__(self, item): print('del obj.key时,我执行') self.__dict__.pop(item) f1=Foo('sb') f1['age']=18 f1['age1']=19 del f1.age1 del f1['age'] f1['name']='alex' print(f1.__dict__)
__new__
__init__ 初始化方法 __new__ 构造方法 : 创建一个对象 class A: def __init__(self): self.x = 1 print('in init function') def __new__(cls, *args, **kwargs): print('in new function') return object.__new__(A, *args, **kwargs) a1 = A() a2 = A() a3 = A() print(a1) print(a2) print(a3) print(a.x)