python类的学习笔记(二)
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
参考文献:
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步