前言
上节大话python面向对象对面向对象有了一些了解,这次就不用大话风格了 (ps:真心不好扯啊)
isinstance与issubclass
isinstance(obj,cls)检查是否obj是否是类 cls 的对象
class Foo(object): pass obj = Foo() isinstance(obj, Foo)
issubclass(sub, super)检查sub类是否是 super 类的派生类
class Foo(object): pass class Bar(Foo): pass issubclass(Bar, Foo)
python 反射
1 什么是反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。
2 python面向对象中的反射:
通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
反射即想到4个内置函数分别为:getattr、hasattr、setattr、delattr 获取成员、检查成员、设置成员、删除成员
下面逐一介绍
1 class Foo: 2 def __init__(self): 3 4 self.name='python反射' 5 6 def func(self): 7 8 print("这是一个func方法") 9 10 # getattr获取成员 11 obj=Foo() 12 13 ret=getattr(obj,'name') 14 15 print(ret)#输出 python反射 16 17 # hasattr检查成员 18 19 ret=hasattr(obj,'name') 20 print(ret) #输出 True 21 22 # setattr设置成员 23 24 setattr(obj,'name','new python反射') 25 26 print(obj.name)#输出 new python反射 27 28 # delattr删除成员 29 30 delattr(obj,'name') 31 32 print(obj.name)#报错 AttributeError: 'Foo' object has no attribute 'name'
__str__与__repr__
改变对象的字符串显示__str__,__repr__
__repr__和__str__这两个方法都是用于显示的,__str__是面向用户的,而__repr__面向程序员。
-
打印操作会首先尝试__str__和str内置函数(print运行的内部等价形式),它通常应该返回一个友好的显示。
-
__repr__用于所有其他的环境中:用于交互模式下提示回应以及repr函数,如果没有使用__str__,会使用print和str。它通常应该返回一个编码字符串,可以用来重新创建对象,或者给开发者详细的显示。
区别:
class Foo: def __init__(self): self.name='python反射' def __repr__(self): return "这是一个repr方法" def __str__(self): return "这是一个str方法" print(Foo())
class Foo: def __init__(self): self.name='python反射' def __repr__(self): return "这是一个repr方法" # def __str__(self): # return "这是一个str方法" print(Foo())
也就是说,在__str__不存在的情况下,print会直接使用__repr__返回的值。当我们想所有环境下都统一显示的话,可以重构__repr__方法;当我们想在不同环境下支持不同的显示,例如终端用户显示使用__str__,而程序员在开发期间则使用底层的__repr__来显示,实际上__str__只是覆盖了__repr__以得到更友好的用户显示。
以下几种情况会触发__repr__与__str__的调用 ,%s格式化字符串,print输出,str()
__del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
class Foo: def __init__(self): self.name='python反射' def __del__(self): print("我是析构函数") Foo()
__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']=2 del f1.age1 del f1['age'] f1['name']='item系列' print(f1.__dict__)
__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) a = A() print(a.x)
单例模式
class Singleton: def __new__(cls, *args, **kw): if not hasattr(cls, '_instance'): cls._instance = object.__new__(cls) return cls._instance one = Singleton() two = Singleton() two.a = 3 print(one.a) # 3 # one和two完全相同,可以用id(), ==, is检测 print(id(one)) # 29097904 print(id(two)) # 29097904 print(one == two) # True print(one is two) 单例模式
__call__
对象后面加括号,触发执行。
class Foo: def __init__(self): self.name='__call__方法' def __call__(self, *args, **kwargs): print("调用call方法") Foo()()#输出 调用call方法
__len__
class A: def __init__(self): self.a = 1 self.b = 2 def __len__(self): return len(self.__dict__) a = A() print(len(a))
__eq__ 与 __hash__
遇到了一次关于这哥俩的面试题,就把他放一块吧
题目是这样的:一百个对象去重,如果name与gender相同就代表两对象相同(类似于java的重写equal)
class Person: def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender def __hash__(self): return hash(self.name+self.gender) def __eq__(self, other): if self.name == other.name and self.gender == other.gender:return True def __str__(self): return self.name p_lst=[Person('python',20,'男'),Person('python',18,'男'),Person('linux',20,'女')] ret=set(p_lst)# 多方便,重写这仨哥们就完事了 for i in ret: print(i)