面向对象的进阶
一、isinstance
isinstance(o,t)检查o是不是t的对象,返回值为bool.
class A: pass a=A() print(isinstance(a,A)) #True #a是A的对象
二、issubclass
issubclass(cls,classinfo) 检查B是不是继承了A,A是B的父类。
class A:pass class B(A):pass print(issubclass(B,A)) #True A是B的父类 print(issubclass(A,B)) #False B不是A的父类
三、反射
反射 :是用字符串类型的名字去操作变量。(python中的一切事物都是对象(都可以使用反射))
反射对象中的属性和方法 hasattr getattr setattr delattr
1、getattr
1 class A: 2 def func(self): 3 print("in func") 4 a=A() #实例化 5 a.name="yaya" 6 a.age=22 7 8 #反射对象的属性 9 ret=print(getattr(a,"name")) #通过变量名的字符串形式取到的值 10 print(ret) 11 print(a.__dict__) #{'name': 'yaya', 'age': 22} 12 变量名=input(">>>") 13 print(a) #<__main__.A object at 0x000000CE0F5F6048> 14 print(getattr(a,变量名)) 15 print(a.__dict__[变量名]) 16 17 #反射对象的方法 18 a.func() #in func 19 ret=getattr(a,"func") 20 ret() #in func 调用ret方法 21 print(ret) #<bound method A.func of <__main__.A object at 0x000000CF18D71D68>>
2、hasattr
1 #hasattr 与getattr配套使用,夫妻档 2 class A: 3 price=20 4 @classmethod 5 def func(cls): 6 print("in func") 7 #反射类的属性 8 # print(getattr(A,"price")) 9 10 #反射类的方法 11 if hasattr(A,"func"): 12 getattr(A,"func")() #in func 直接加括号调用
3、setattr 设置修改变量
1 class A: 2 pass 3 a=A() 4 setattr(a,"name","yaya") 5 setattr(A,"name","alex") 6 print(a.name) #yaya 7 print(A.name) #alex
4、delattr 删除一个变量
class A: pass a=A() setattr(a,"name","yaya") setattr(A,"name","alex") delattr(a,"name") print(a.name) delattr(A,"name")
5、其他模块
import my #反射模块的属性 print(my.day) #Monday print(getattr(my,"day")) #Monday #反射模块的方法 print(getattr(my,"func")) #<function func at 0x00000050F9D80488> getattr(my,"func")() #in func 加括号直接调用 ##************************************************************************************ #内置模块也能用 import time print(getattr(time,"time")) #<built-in function time> print(getattr(time,"time")()) #1516609758.551611 print(getattr(time,"asctime")) #<built-in function asctime> print(getattr(time,"asctime")()) #Mon Jan 22 16:29:18 2018 #************************************************************************************ def func(): print("in func") year=2018 import sys print(sys.modules['__main__'].year) #2018 # 反射自己模块中的变量 print(getattr(sys.modules["__main__"],"year")) #2018 #反射自己模块中的函数 getattr(sys.modules["__main__"],"func")() #in func 变量名=input(">>>") print(getattr(sys.modules[__name__],变量名)) #要反射的函数有参数怎么办? import time print(time.strftime("%Y-%m-%d %H:%M:%S")) #2018-01-22 18:58:07 print(getattr(time,"strftime")("%Y-%m-%d %H:%M:%S")) #2018-01-22 18:58:07 #一个模块中的类能不能反射得到 import my print(getattr(my,"C")()) #<my.C object at 0x000000088EFFB978> if hasattr(my,"name"): getattr(my,"name")
四、__str__ __repr__
obj.__str__ str(obj)
obj.__repr__ repr(obj)
1 class Teacher: 2 def __init__(self,name,salary): 3 self.name = name 4 self.salary = salary 5 def __str__(self): 6 return "Teacher's object :%s"%self.name 7 def __repr__(self): 8 return str(self.__dict__) 9 def func(self): 10 return 'wahaha' 11 nezha = Teacher('哪吒',250) 12 print(nezha) # 打印一个对象的时候,就是调用a.__str__ 13 #Teacher's object :哪吒 14 print(repr(nezha)) #字典形式存在 15 #{'salary': 250, 'name': '哪吒'} 16 print('>>> %r'%nezha) 17 #>>> {'salary': 250, 'name': '哪吒'}
补充:
1、object 里有一个__str__,一旦被调用,就返回调用这个方法的对象的内存地址。
2、%s str() 直接打印 实际上都是走的__str__
%r repr() 实际上都是走的__repr__
3、repr 是str的备胎,但str不能做repr的备胎
4、print(obj)/'%s'%obj/str(obj)的时候,实际上是内部调用了obj.__str__方法,如果str方法有,那么他返回的必定是一个字符串。
5、obiect为基类时,如果没有__str__方法,会先找本类中的__repr__方法,再没有再找父类中的__str__,然后是父类的__repr__。
6、自定义父类时,先找自己的__str__,如果没有,就找父类的__str__,没有再找自己的__repr__,还没有就找父类的__repr__。
7、repr(),只会找__repr__,如果没有找父类的。
五、__len__
class Classes: def __init__(self,name): self.name = name self.student = [] def __len__(self): return len(self.student) def __str__(self): return 'classes' py_s9= Classes('python') py_s9.student.append('二哥') py_s9.student.append('大哥') print(len(py_s9)) #2 print(py_s9) #classes
六、__del__ 析构函数
class Foo: def __del__(self): print('执行我啦') f1=Foo() del f1 print('------->') #输出结果 执行我啦
七、__call__
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()().
class Foo: def __init__(self): pass def __call__(self, *args, **kwargs): print('__call__') obj = Foo() # 执行 __init__ obj() # 执行 __call__
八、item系列
__getitem__:实例传一个参数,传到它这里,返回值,返回什么值自己可以定义。
__setitem__:为类设置或者赋值,增长情况下应该是对__dict__增加属性值,(也可以设置成其他的乱七八糟的),主要是在对对象进行字典操作的时候会调用这个内置函数。
__delitem__:执行字典类似的删除的操作的时候,会默认执行的内置函数(如果不想让他有它应该有的作用的时候,也可以设置成别的)
class Foo: def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def __getitem__(self, item): 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('yaya',22,'女') print(f['name']) #yaya f['hobby'] = '帅哥' print(f.hobby,f['hobby']) #帅哥 帅哥 # del f.hobby # object 原生支持 __delattr__ # del f['hobby'] # 通过自己实现的 print(f.__dict__) #{'name': 'yaya', 'sex': '女', 'hobby': '帅哥', 'age': 22}
九、__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() #in new function #in init function a2 = A() a3 = A() print(a1) #<__main__.A object at 0x000000FDFE5A0C50> print(a2) print(a3)
单例模式
一个类 始终 只有 一个 实例
当你第一次实例化这个类的时候 就创建一个实例化的对象
当你之后再来实例化的时候 就用之前创建的对象
class A: __instance = False def __init__(self,name,age): self.name = name self.age = age def __new__(cls, *args, **kwargs): if cls.__instance: return cls.__instance cls.__instance = object.__new__(cls) return cls.__instance yaya = A('yaya',22) yaya.cloth = '小花袄' alex = A('alex',28) print(yaya) #<__main__.A object at 0x000000DFFFEF0E10> print(alex) #<__main__.A object at 0x000000DFFFEF0E10> print(yaya.name) #alex print(alex.name) #alex print(yaya.cloth) #小花袄
十、__eq__
class A: def __init__(self,name): self.name = name def __eq__(self, other): if self.__dict__ == other.__dict__: return True else: return False ob1 = A('egon') ob2 = A('egg') print(ob1 == ob2) #False
十一、__hash_
class A: def __init__(self,name,sex): self.name = name self.sex = sex def __hash__(self): return hash(self.name+self.sex) a = A('yaya','女') b = A('yaya','男') print(hash(a)) #5854354249374934794 print(hash(b)) #-8349671480864591817
class FranchDeck: ranks = [str(n) for n in range(2,11)] + list('JQKA') suits = ['红心','方板','梅花','黑桃'] def __init__(self): self._cards = [Card(rank,suit) for rank in FranchDeck.ranks for suit in FranchDeck.suits] def __len__(self): return len(self._cards) def __getitem__(self, item): return self._cards[item] deck = FranchDeck() print(deck[0]) from random import choice print(choice(deck)) print(choice(deck))
class FranchDeck: ranks = [str(n) for n in range(2,11)] + list('JQKA') suits = ['红心','方板','梅花','黑桃'] def __init__(self): self._cards = [Card(rank,suit) for rank in FranchDeck.ranks for suit in FranchDeck.suits] def __len__(self): return len(self._cards) def __getitem__(self, item): return self._cards[item] def __setitem__(self, key, value): self._cards[key] = value deck = FranchDeck() print(deck[0]) from random import choice print(choice(deck)) print(choice(deck)) from random import shuffle shuffle(deck) print(deck[:5])
#名字和性别相同,年龄不同,去重 class Person: def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def __hash__(self): return hash(self.name+self.sex) def __eq__(self, other): if self.name == other.name and self.sex == other.sex:return True p_lst = [] for i in range(84): p_lst.append(Person('egon',i,'male')) print(p_lst) print(set(p_lst))