isinstance和issubclass
反射setattr、delattr、getattr、hasattr
__str__和__repr__
item系列__getitem__、__setitem__、__delitem__
__del__、__new__、__call__
with和__enter__、__exit__
__len__
isinstance(obj,cls)检查是否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
print(issubclass(Bar, Foo))
反射
python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
class People:
f = '类的静态变量'
def __init__(self,name,age):
self.name = name
self.age = age
def say_hi(self):
print('hi,%s'%(self.name))
obj = People('wy',22)
# 检测是否含有某属性 hasattr
print(hasattr(obj,'name'))
print(hasattr(obj,'say_hi'))
# 获取属性 getattr
n = getattr(obj,'name')
print(n)
s = getattr(obj,'say_hi')
s()
print(getattr(obj,'aaa','不存在'))
# 设置属性 setattr
print(obj.__dict__)
setattr(obj,'sex','male')
print(obj.__dict__)
# 删除属性 delattr
delattr(obj,'name')
print(obj.__dict__)
# delattr(obj,'nn') 不存在则报错
__str__和__repr__方法
__str__是在str()函数被使用,或是在print函数打印一个对象的时候才被调用的,并且它返回的字符串对终端用户更友好。
如果只想实现这两个特殊方法中的一个,__repr__是更好的选择,因为如果一个对象没有__str__函数,而Python又需要调用它的时候,解释器会用__repr__作为替代。
__repr__和__str__这两个方法都是用于显示的,__str__是面向用户的,而__repr__面向程序员。
打印操作会首先尝试__str__和str内置函数(print运行的内部等价形式),它通常应该返回一个友好的显示。
__repr__用于所有其他的环境中:用于交互模式下提示回应以及repr函数,如果没有使用__str__,会使用print和str。它通常应该返回一个编码字符串,可以用来重新创建对象,或者给开发者详细的显示。
当我们想所有环境下都统一显示的话,可以重构__repr__方法;当我们想在不同环境下支持不同的显示,例如终端用户显示使用__str__,而程序员在开发期间则使用底层的__repr__来显示,实际上__str__只是覆盖了__repr__以得到更友好的用户显示。
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('qinghua','北京','私立')
print(s1)
# 这里直接打印s1,如果有__str__,则打印__str__方法,没有则会打印__repr__方法
'''
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)
item系列__getitem__/__setitem__/__delitem__
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 obj.key时,我执行
del f1['age'] # del obj[key]时,我执行
f1['name']='alex'
print(f1.__dict__)
__getitem__
#如果类把某个属性定义为序列,可以使用__getitem__()输出序列属性中的某个元素.
class FruitShop():
def __getitem__(self,i):
return self.fruits[i]#可迭代对象
if __name__ == "__main__":
shop = FruitShop()
print(shop) #__main__.FruitShop instance
shop.fruits = ["apple", "banana"]
print(shop[1]) #banana
for item in shop:
print(item)
__del__ : 析构方法,当对象在内存中被释放时,自动触发执行。
__new__ :
1.创建类时先执行type的__init__方法,
2.当一个类实例化时(创建一个对象)执行type的__call__方法,__call__方法的返回值就是实例化的对象
__call__内部调用
-类.__new__方法,创建一个对象
-类.__init__方法,初始化对象
实例化对象是谁取决于__new__方法,__new__返回什么就是什么
__new__() 方法的特性:
- __new__() 方法是在类准备将自身实例化时调用。
- __new__() 方法始终都是类的静态方法,即使没有被加上静态方法装饰器
class Foo(object):
pass
obj=Foo() #默认是调用该类的直接父类的__new__()方法来构造该类的实例
print(obj) #打印结果:<__main__.Foo object at 0x000002636FEAA208>
事实上如果(新式)类中没有重写__new__()方法,即在定义新式类时没有重新定义__new__()时,Python默认是调用该类的直接父类的__new__()方法来构造该类的实例,
如果该类的父类也没有重写__new__(),那么将一直按此规矩追溯至object的__new__()方法,因为object是所有新式类的基类。
class F1(object):
#重写__new__方法,返回这个重写的__new__方法
def __new__(cls, *args, **kwargs):
return 123
obj=F1() #实例化对象是谁取决于__new__方法,__new__返回什么就是什么
print(obj,type(obj)) #打印结果:123 <class 'int'>
class F2(object):
pass
class F3(object):
def __new__(cls, *args, **kwargs):
return F2()
obj=F3() #实例化对象是谁取决于__new__方法,__new__返回什么就是什么
print(obj) #<__main__.F2 object at 0x00000210119BA4A8>
如果要得到当前类的实例,应当在当前类中的 __new__() 方法语句中调用当前类的父类的 __new__() 方法。
例如,如果当前类是直接继承自 object,那当前类的 __new__() 方法返回的对象应该为:
def __new__(cls, *args, **kwargs):
...
return object.__new__(cls)
__new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供
__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例
__init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值
__new__实现单例模式
class Singleton:
def __new__(cls, *args, **kw):
if not hasattr(cls, '_instance'):
cls._instance = object.__new__(cls)
return cls._instance
__call__
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print('__call__')
obj = Foo() # 执行 __init__
obj() # 执行 __call__
with和__enter__,__exit__
class A:
def __enter__(self):
print('before')
def __exit__(self, exc_type, exc_val, exc_tb):
print('after')
with A() as a:
print('123')
class A:
def __init__(self):
print('init')
def __enter__(self):
print('before')
def __exit__(self, exc_type, exc_val, exc_tb):
print('after')
with A() as a:
print('123')
pickle模块
用于序列化的两个模块
json:用于字符串和Python数据类型间进行转换
pickle: 用于python特有的类型和python的数据类型间进行转换
json提供四个功能:dumps,dump,loads,load
pickle提供四个功能:dumps,dump,loads,load
pickle可以存储什么类型的数据呢?
- 所有python支持的原生类型:布尔值,整数,浮点数,复数,字符串,字节,None。
- 由任何原生类型组成的列表,元组,字典和集合。
- 函数,类,类的实例
pickle模块可能出现三种异常:
1. PickleError:封装和拆封时出现的异常类,继承自Exception
2. PicklingError: 遇到不可封装的对象时出现的异常,继承自PickleError
3. UnPicklingError: 拆封对象过程中出现的异常,继承自PickleError
import pickle
class A:
def __init__(self,name):
self.name = name
def test(self):
print('%s是帅逼!'%(self.name))
obj = A('wy')
print(obj.name)
with open('test','wb') as f:
obj_d = pickle.dumps(obj)
print(obj_d)
f.write(obj_d)
with open('test','rb') as f:
obj_a = f.read()
print(obj_a)
obj_l = pickle.loads(obj_a)
print(obj_l.name)
print(obj_l.test())
__len__
class A:
def __init__(self):
self.a = 1
self.b = 2
def __len__(self):
return len(self.__dict__)
a = A()
print(len(a))
# 输出: 2