python面向对象进阶
类相关的内置函数
isinstance
内置函数
isinstance(obj,cls) 检查obj是否是cls的对象
class C:pass
a = C()
print(isinstance(a,C)) 返回布尔类型
issubclass
issubclass(sub,super)检查sub是否是super的派生类
class B(C):
pass
print(issubclass(B,C)) 返回布尔类型
反射
1 什么是反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。
2 python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
四个可以实现自省的函数
下列方法适用于类和对象(一切皆对象,类本身也是一个对象)
四个方法:hasattr getattr setatte delattr
hasattr 和 getattr 组合使用
import mymodul # 是自定义模块
if hasattr(mymodul,'Modul_cls'): #判断是否存在这个类名再执行后面的
print(getattr(mymodul,'Modul_cls')) # 获取到一个类的对象
#<class 'mymodul.Modul_cls'>
class A:
def func(self):
print('in func')
a = A()
a.name = 'alex'
a.age = 63
A.func(a)
# 反射对象的属性
ret = getattr(a,'age') # 通过变量名的字符串形式取到的值
print(ret)
# 反射对象的方法
print(getattr(a,'func'))
# 反射类的方法
print(getattr(A,'func'))
反射模块的属性
import mymodul
print(getattr(mymodul,'year'))
# 反射模块的方法
getattr(mymodul,'fangfa')() # 获取到的是一个函数名加()就是调用
# 内置模块也能用
# 反射自己模块中的变量和模块
def func():
print('自己模块名')
import sys
print(sys.modules['__main__']) # 这里要使用__name__如被其他脚本导入后使用用__name才能生效此方法
im = input('>>>')
getattr(sys.modules[__name__],im)()
要反射的函数有参数
import time
time.strftime('%Y-%m-%d %H:%M:%S')
getattr(time,'strftime')('%Y-%m-%d %H:%M:%S')
def qqx():pass
import sys
print(sys.modules['__main__']) #__name__
setattr # 设置修改变量
class D:pass
a = D()
setattr(a,'name','classtor') # 往对象a中添加一个静态属性
print(a.name)
setattr(D,'name',123)
print(D.name) # 往类D 中添加静态属性
delattr 删除属性
delattr(a,'name') # 删除了对象a属性中的name 打印类中的属性 123
print(a.name) # 123
delattr(D,'name')
print(a.name) # 删除了类的name属性再打印找不到会报错
class Foo: f = '类的静态变量' def __init__(self,name,age): self.name=name self.age=age def say_hi(self): print('hi,%s'%self.name) obj=Foo('egon',73) #检测是否含有某属性 print(hasattr(obj,'name')) print(hasattr(obj,'say_hi')) #获取属性 n=getattr(obj,'name') print(n) func=getattr(obj,'say_hi') func() print(getattr(obj,'aaaaaaaa','不存在啊')) #报错 #设置属性 setattr(obj,'sb',True) setattr(obj,'show_name',lambda self:self.name+'sb') print(obj.__dict__) print(obj.show_name(obj)) #删除属性 delattr(obj,'age') delattr(obj,'show_name') delattr(obj,'show_name111')#不存在,则报错 print(obj.__dict__)
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')
#!/usr/bin/env python # -*- coding:utf-8 -*- import sys def s1(): print 's1' def s2(): print 's2' this_module = sys.modules[__name__] hasattr(this_module, 's1') getattr(this_module, 's2')
#!/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')()
__str__ 和 __reper__
改变对象的字符串显示__str__
__repr__ 原型毕露
自定制格式化字符串__format__
class A:
# def __str__(self):
# return '执行我啦'
def __init__(self,name,age):
self.name = name
self.age = age
def __repr__(self):
return '执行我啦reper'
def fund(self):
print('执行我啦')
a = A('alex',98)
print(a) # 打印一个对象时,实际是执行对象中__str__方法,没有返回内存地址
# <__main__.A object at 0x01E01DF0>
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(s1)
print('from repr: ',repr(s1))
print('from str: ',str(s1))
print(s1)
lst = [1,2,3,4,5] # 实例化列表类方法
print(lst) # 实际调用lst下的__str__方法 即obj对象
%s 和 %r
class B:
def __str__(self):
return 'str : class B'
def __repr__(self):
return 'repr : class B'
b=B()
print('%s'%b)
print('%r'%b)
小结:
双下方法
内置的类方法和内置的函数之间有着千丝万缕的联系
__str__
__repr__ 原型毕露
object 里有一个__str__,一旦被调用,就返回调用这个方法的对象的内存地址
repr 是 str的备胎
str 不能做 repr 的备胎
print(obj)、%s 、str(obj) 的时候,实际上是内部调用了obj.__str__方法,如果str方法有,那么返回的必定是一个字符串,其他会报错
如果没有__str__方法,会先找本类中的__repr__方法,再没有再找父类中的__str__,如没有就会调用object中的__srt__方法会打印一个内存地址
repr() 只会找__repr__,如果没有找父类的
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
print(f1.__dict__)
del f1.age #执行对象中__delitem__方法
print(f1.__dict__)
del f1['age1'] #对象中有__delattr__方法,可以使用此方式进行删除
print(f1.__dict__)
f1['name']='alex'
print(f1.__dict__) #对象中有__getitem__方法,可以使用此方式进行删除
__del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
class A:
def __del__(self): # 析构函数
print('执行我啦')
a = A()
del a # 执行了__del__此方法,有把a这个对象给删除了
print(a.__dict__) # 所以这里打印是会报错哦
__new__ 构造方法:创建一个对象
一个类始终只有一个实例
当你第一个次实例化这个类的时候,就创建一个实例化的对象
当你之后再来实例化的时候,就用之前创建的对象
单列模式
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__(A) # cls 也可以写这个
return cls.__instance
egnon nezha 完全相同可以使用 id() == is 检测
egon = A('egon',38)
egon.cloth = '小花衣'
nezha = A('nezha',25)
print(nezha)
print(egon)
print(nezha.name)
print(egon.name)
print(egon == nezha) # True
print(egon is nezha) # True 对比内存地址
__call__
对象后面加括号,触发执行。注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print('__call__')
obj = Foo() # 执行 __init__
obj() # 执行 __call__
with和__enter__,__exit__
with 语句
class A:
def __enter__(self):
print('before')
def __exit__(self, exc_type, exc_val, exc_tb):
print('after')
with A() as a:
print('123')
# before
# 123
# after
with 和文件操作
# with 和文件操作
class Myfile:
def __init__(self,path,mode='r',encoding = 'utf-8'):
self.path = path
self.mode = mode
self.encoding = encoding
def __enter__(self):
self.f = open(self.path, mode=self.mode, encoding=self.encoding)
return self.f
def __exit__(self, exc_type, exc_val, exc_tb):
self.f.close()
with Myfile('file',mode='w') as f:
f.write('wahaha') # 在本目录创建了file文件并写入了wahaha
with 和 pickle
import pickle
class MyPickledump:
def __init__(self,path):
self.path = path
def __enter__(self):
self.f = open(self.path, mode='ab')
return self
def dump(self,content):
pickle.dump(content,self.f)
def __exit__(self, exc_type, exc_val, exc_tb):
self.f.close()
class Mypickleload:
def __init__(self,path):
self.path = path
def __enter__(self):
self.f = open(self.path, mode='rb')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.f.close()
def load(self):
return pickle.load(self.f)
def loaditer(self):
while True:
try:
yield self.load()
except EOFError:
break
# with MyPickledump('file') as f:
# f.dump({1,2,3,4}) #以ab模式把1/2/3/4写入了file文件内
with Mypickleload('file') as f:
for item in f.loaditer():
print(item)
with 和 pickle 和iter
import pickle
class MyPickledump:
def __init__(self,path):
self.path = path
def __enter__(self):
self.f = open(self.path, mode='ab')
return self
def dump(self,content):
pickle.dump(content,self.f)
def __exit__(self, exc_type, exc_val, exc_tb):
self.f.close()
class Mypickleload:
def __init__(self,path):
self.path = path
def __enter__(self):
self.f = open(self.path, mode='rb')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.f.close()
def __iter__(self):
while True:
try:
yield pickle.load(self.f)
except EOFError:
break
# with MyPickledump('file') as f:
# f.dump({1,2,3,4})
with Mypickleload('file') as f:
for item in f:
print(item)
__len__
class A:
def __init__(self):
self.a = 1
self.b = 2
def __len__(self):
return len(self.__dict__)
a = A()
print(len(a)) #求对象的长度是,依赖对象内部的len发放
__hash__ 方法
class H:
def __init__(self,name,sex):
self.name = name
self.sex = sex
def __hash__(self):
return hash(self.name+self.sex)
a = H('egon','男')
b = H('egon','男')
print(hash(a)) # 608824368
print(hash(b)) # 608824368 两个对象的HASH一致
#
100名字 和 性别相同,就认为是一个对象去重 你年龄不同
set 去重对象
class A:
def __init__(self,name,sex,age):
self.name = name
self.sex = sex
self.age = age
def __hash__(self):
sec = hash(self.name+ self.sex)
return sec
def __eq__(self, other):
if self.name == other.name and self.sex == self.sex:
return True
return False
a = A('egg','男',38)
b = A('egg','男',37)
print(a,b)
print(set((a,b))) # set 方法去重对象时,依赖对象的__hash__ 和 __eq__ 方法
__eq__
class C:
def __init__(self,name):
self.name = name
def __eq__(self, other):
if self.name == other.name:
return True
else:
return False
# print(self,other)
ob1 = C('egg')
ob2 = C('egg')
print(ob1 == ob2) # False
# 纸牌游戏 import _json from collections import namedtuple Card = namedtuple('Card',['rank','suit']) # rank牌面的大小 suit 牌面的花色 ranks = [str(n) for n in range(2,11)] + list('JQKA') suits = ['红心','方板','梅花','黑桃'] print(ranks) lei = [Card(rank,suit) for rank in ranks for suit in suits] print(lei) class FranchDeck: ranks = [str(n) for n in range(2,11)] + list('JQKA') # 生成2到10 和J到A 字符串类型的类表 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]) # 对象中有__getitem__方法可以使用索引方式查看属性 # Card(rank='2', suit='红心') from random import choice print(choice(deck)) # choice取随机数牌、 # Card(rank='9', suit='方板') print(choice(deck)) # Card(rank='2', suit='方板') from random import shuffle shuffle(deck) shuffle(deck) print(deck[:5]) # 洗牌用到的,依赖对象的__len__方法
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))
浙公网安备 33010602011771号