Python 面向对象进阶篇
一、isinstance和issubclass
1、isinstance 判断一个对象是否属于该类
class Foo(object): pass a = Foo()
isinstance(a, Foo) #判断a是否是Foo的对象 答案:True
2、issubclass(sub, super)检查sub类是否是 super 类的派生类
class Foo(object): pass class Son(Foo): pass issubclass(Son, Foo) #判断Son是否是Foo的派生类 答案:True
二、反射
1 什么是反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。
2 python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
反射对象中的属性和方法 # hasattr getattr setattr delattr
getattr
class A: def func(self): print('in func') a = A() a.name = 'amy' a.age = 63 # 反射对象的属性 ret = getattr(a,'name') # 通过变量名的字符串形式取到的值 print(ret) #amy
hasattr
class A: price = 20 @classmethod def func(self): print('in func') ret = getattr(A,'price') # 通过变量名的字符串形式取到的值 print(ret) if hasattr(A,'func'): #如果A中有func,就使执行getattr方法 getattr(A,'func')()
setattr
class Foo: role = 'teacher' def __init__(self,name,age): self.name = name self.age = age def say_hi(self): print('hi,%s'%self.name) obj = Foo('alex',23) setattr(obj,'sb',True) print(obj.__dict__) #{'age': 23, 'sb': True, 'name': 'alex'} print(getattr(obj,'sb')) #True setattr(obj,'show',lambda self:self.name+'sb') print(obj.show(obj)) #alexsb
delatter
# setattr 设置修改变量 class A: pass a = A() 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)
class Foo(object): staticField = "old boy" def __init__(self): self.name = 'wupeiqi' def func(self): return 'func' @staticmethod def bar(): return 'bar' print getattr(Foo, 'staticField') print getattr(Foo, 'func') print getattr(Foo, 'bar')
def qqxing(): print('qqxing') year = 2018 import sys # print(sys.modules['__main__'].year) # 反射自己模块中的变量 # print(getattr(sys.modules['__main__'],'year')) # 反射自己模块中的函数 # getattr(sys.modules['__main__'],'qqxing')() 变量名 = input('>>>') print(getattr(sys.modules[__name__],变量名))
导入其他模块,利用反射查找该模块是否存在某个方法
#!/usr/bin/env python # -*- coding:utf-8 -*- def test(): print('from the test')
#!/usr/bin/env python # -*- coding:utf-8 -*- """ 程序目录: module_test.py index.py 当前文件: index.py """ import module_test as obj #obj.test() print(hasattr(obj,'test')) getattr(obj,'test')(
导入的模块有类
class A: day = 'Monday' # @classmethod @staticmethod def wahaha(): print('wahahahaha')
import my #调用类的方法 getattr(my.A,'wahaha')() from my import A getattr(A,'wahaha')() print(getattr(A,'day')) print(getattr(my.A,'wahaha')() #调用类中的属性 if hasattr(my.A,'day'): print(getattr(my.A,'day'))
__str__和__repr__
改变对象的字符串显示__str__,__repr__
自定制格式化字符串__format__
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 Teacher: def __init__(self,name,salary): self.name = name self.salary = salary self.student = [] def __str__(self): return "Teacher's object:%s" %self.name def __len__(self): return len(self.student) def __repr__(self): return str(self.__dict__) def func(self): return 'wahaha' nazha = Teacher('nazha',2300) print(nazha) print(repr(nazha)) print('%r'%nazha) print('%s'%nazha) print(str(nazha))
__del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
class Foo: def __del__(self): print('执行我啦') f1=Foo() del f1 print('------->') #输出结果 执行我啦 ------->
__len__
class A: def __init__(self): self.a = 1 self.b = 2 def __len__(self): return len(self.__dict__) a = A() print(len(a))
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): #使用字典的方式查看属性 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('zzm',38,'男') #实例化一个对象 print(f['name']) #zzm f['hobby'] = 'swim' print(f.hobby) #swim print(f['hobby']) #swim del f['name'] #删除name print(f.__dict__)
__new__
new()方法的特性:
new()方法是在类准备将自身实例化时调用。
new()方法始终都是类的静态方法,即使没有被加上静态方法装饰器。
#在实例化开始之后,在调用 init()方法之前,Python首先调用new()方法: class A: def __init__(self): self.x = 1 print('in init function') def __new__(cls, *args, **kwargs): print('in new') return object.__new__(A, *args, **kwargs) a = A() #in new #in init function print(a.x) #1
我们还可以利用__new__来做一些其他有趣的事情,比如实现 设计模式中的 单例模式(singleton) 。
因为类每一次实例化后产生的过程都是通过__new__来控制的,所以通过重载__new__方法,我们 可以很简单的实现单例模式。
class Singleton: def __new__(cls, *args, **kw): if not hasattr(cls, '_instance'): cls._instance = object.__new__(cls, *args, **kw) 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) 单例模式
new()和ini()的区别,在新式类中new()才是真正的实例化方法,为类提供外壳制造出实例框架,然后调用该框架内的构造方法init()使其丰满。
__call__
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
class Foo: def __init__(self): pass def __call__(self, *args, **kwargs): print('__call__') obj = Foo() # 执行 __init__ obj() # 执行 __call__
__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('egon','男') b = A('egon','男') print(hash(a)) print(hash(b)) #hash a,b之后,两个值相同,但对于字符串来说,每次得到的值都会发生变化。
__eq__
使用eq方法可以对比两个属性或者值的大小
class A: def __init__(self,name,age): self.name = name self.age = age # def __eq__(self,other): # if self.name == other.name: # return True # return False ob1 = A('egon',23) ob2 = A('egon',23) print(ob1.age == ob2.age) #True print(ob1==ob2) #False print(hash(ob1)) #347809 print(hash(ob2)) #347811
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)) #{<__main__.Person object at 0x004BE9D0>}

浙公网安备 33010602011771号