检查实例化对象与派生类
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) 复制代码
反射
1 什么是反射
反射:是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)
2 python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
四个可以实现自省的函数
下列方法适用于类和对象(一切皆对象,类本身也是一个对象)
对象
def hasattr(*args, **kwargs): # real signature unknown """ Return whether the object has an attribute with the given name. This is done by calling getattr(obj, name) and catching AttributeError. """ pass
def getattr(object, name, default=None): # known special case of getattr """ getattr(object, name[, default]) -> value Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y. When a default argument is given, it is returned when the attribute doesn't exist; without it, an exception is raised in that case. """ pass
def setattr(x, y, v): # real signature unknown; restored from __doc__ """ Sets the named attribute on the given object to the specified value. setattr(x, 'y', v) is equivalent to ``x.y = v'' """ pass
def delattr(x, y): # real signature unknown; restored from __doc__ """ Deletes the named attribute from the given object. delattr(x, 'y') is equivalent to ``del x.y'' """ pass
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')()
反射的增删改查
# getattr一定要和hasattr配合使用 # 反射 4个内置函数 # getattr ****** # hasattr ****** # setattr # 修改和新建 ** # delattr # 删除一个属性 * # 增删改 对象属性 # class A: # def __init__(self,name): # self.name = name # # def wahaha(self): # print('wahahahahaha') # # a = A('alex') # a.name # a.wahaha() # getattr(a,'name') # # a 'age' = 18 # # a.age = 18 # print(a.__dict__) # setattr(a,'age',18) # 给a对象新增一个属性 # print(a.__dict__) # setattr(a,'name','egon') # print(a.__dict__) # # # del a.age # delattr(a,'age') # print(a.__dict__) # 增删改 方法 class A: def __init__(self,name): self.name = name def wahaha(self): print('wahahahahaha') def qqxing(self): print('qqqqqxing') a = A('alex') setattr(A,'qqxing',qqxing) setattr(a,'qqxing',qqxing) print(a.__dict__) a.qqxing(a)
双下方法
一。 内置函数
1.__len__ 与 len()
# class A:
# def __init__(self,name,age,sex,cls):
# self.name = name
# self.age = age
# self.sex = sex
# self.cls = cls
# def __len__(self):
# return len(self.__dict__)
#
# # 有一个内置函数 和内置方法len()是唯一对应的关系
# a1 = A('alex',81,'不详',2)
# a1.hobby = '烫头'
# a2 = A('egon',20,'不详',3)
# a3 = A('yuan',21,'不详',4)
# print(len(a1))
# print(len(a2))
# print(len(a3))
2.字典的存储
# hash
class A:
def __init__(self,name,age,sex,cls):
self.name = name
self.age = age
self.sex = sex
self.cls = cls
def __hash__(self):
return 0
a1 = A('alex',81,'不详',2)
print(hash(a1))
每一次的哈希值都不同,为什么可以直接哈希,因为object类里有__hash__方法
二。__str__ 与 __repr__ 与 print()
ps: 总结:
1.print() 想文件中写,print() 替你将数据类型转化成字符串打印出来
2.__str__ : object 类中的__str__ 就是返回一个数据类型的内存地址
l = [1,2,3,4] print(l) # 向文件中写 print替你将数据类型转化成字符串打印出来 class List: def __init__(self,*args): 5 self.l = list(args) def __str__(self): return '[%s]'%(','.join([str(i) for i in self.l])) l = List(1,2,3,4,5) print(l) #--> l.__str__() # object类中的__str__就是返回一个数据的内存地址 print(l) print(str(l)) print('%s'%l) print(obj) 的结果 是 obj.__str__()的结果 str(obj) 的结果 也是 obj.__str__()的结果 '%s'%obj 的结果 也是 obj.__str__()的结果
class Teacher: def __init__(self,name,age): self.name = name self.age = age # def __str__(self): # return "Teacher's object is %s" %self.name def __repr__(self): return "repr %s" %self.name a = Teacher('alex',18) b = Teacher('wusir',18) print(a) print(repr(b))
# repr(obj)的结果和obj.__repr__()是一样的
# '%r'%(obj)的结果和obj.__repr__()是一样的
总结:
1.实际上上述三种结果都是__str__的返回值
2.当然:如果我们不手动改写object中 的上下划线str或者repr,就会默认调用object类中的方法,默认返回的是 内存地址
思考:why? repr(1) 与 repr('1'):的打印结果不同?
因为:在整形中 定义的repr方法,与在str中定义的repr方法定义的函数方法的返回值不同。 即在class int 与 class str 中的 __repr__ 方法的返回值不同
class Teacher: def __init__(self,name,age): self.name = name self.age = age def __str__(self): return "Teacher's object %s"%self.name def __repr__(self): return 'repr function %s'%self.name a = Teacher('alex',80) b = Teacher('egon',80) print(a) print(b)
PS:总结:
1.到需要使用__str__的方法时,找不到__str__方法时,就会找__repr__方法。
2.当需要使用__repr__的方法时,找不到__repr__的方法时,就会找父类的或object的__repr__方法,这是默认返回的时内存地址
3.repr()方法是 str()方法的备胎。嘿嘿嘿(偷笑)
3.实际上:len()和 repr() 方法的返回值都是依赖__len__和__repr__方法来返回值的
三。__len__方法 与 __hash__方法
# class A:
# def __init__(self):pass
# def __len__(self):pass
# def len(obj):
# obj.__len__()
# a = A()
# a.__len__()
# len() # 为什么要归一化设计呢?
# 更接近面向函数编程,简单且节省代码
# len() obj.__len__() 返回值是一致的
# len() 的结果是依赖 obj.__len__()
# hash() 的结果是依赖 obj.__hash__()
# str() 的结果是依赖 obj.__str__()
# print(obj) 的结果是依赖 obj.__str__()
# %s 的结果是依赖 obj.__str__() # 语法糖
#
# repr() 的结果是依赖 obj.__repr__()
# %r 的结果是依赖 obj.__repr__()
# repr是str的备胎
思考:如果str与repr 我只能实现一个,那选哪个?# __str__
# __repr__ 一定是选择repr
什么是语法糖?语法糖的定义?
答:语法糖就是可以让数据结构变得更加简单,就像吃了糖一样甜。这就是语法糖。
四。__format__方法?
class Format: def __init__(self,name,age,hobby): self.name = name self.age = age self.hobby = hobby def __format__(self,format_spec): return format_spec.format(obj = self) person = Format('alex',18,'女') format_spec = '{obj.name}-{obj.age}-{obj.hobby}' print(format(person,format_spec))
五:__call__?
class Teacher: def __init__(self,name,age): self.name = name self.age = age def __call__(self): print(123) t = Teacher('wusir',18) t()
靠?方法加(),什么鬼?
对象名() 相当于调用了类内置的__call__方法
print(callable(类名)):是否可调用的
如果一个对象是否可调用,取决于这个对象对应的类是否有__call__方法
2.__eq__?
class A:pass
a = A()
b = A()
print(a == b)
返回False
因为连个对象的内存地址是不一样的,
# class A: # def __eq__(self, other): # # if self.__dict__ == other.__dict__: # return True # # __eq__() # a = A() # a.name = 'alex' # b = A() # b.name = 'egon' # print(a) # print(b) # print(a == b) # == 是由__eq__的返回值来决定的
# == 是由__eq__的返回值来决定的
3.__del__ 析构方法?
在删除一个对象的时候做一些收尾工作。
class A: def __init__(self): self.f = open('文件','w') a = A() print('aaa')
把a对象删除不用了
这是文件并没有关闭,文件没有关闭会占内存。
应该在删除对象是进行一个析构方法,用操作系统将文件关闭在删除文件
class A: def __init__(self): pass self.f = open('文件','w') def __del__(self): self.f.close() print('执行我了') a = A() del a print(a) print('aaa')
4.__new__?
__new__ 构造方法
实例化对象的时候
创建对象的过程
init 初始化
设计模式 —— 单例模式
单例模式 就是 一个类 只能有一个实例 # class A:pass # a = A() # b = A() # print(a) # print(b) # class B: # __instance = None # def __new__(cls, *args, **kwargs): # if cls.__instance is None: # obj = object.__new__(cls) # cls.__instance = obj # return cls.__instance # def __init__(self,name,age): # self.name = name # self.age = age # def func(self): # print(self.name) # a = B('alex',80) # b = B('egon',20) # print(a) # print(b) # print(a.name) # print(b.name)
5.__item__系列
# item # dic = {'k':'v'} # print(dic['k']) # class Foo: # def __init__(self,name): # self.name=name # # def __getitem__(self,item): # return self.__dict__[item] # # def __setitem__(self, key, value): # self.__dict__[key]=value # # def __delitem__(self, key): # print('del obj[key]时,我执行') # self.__dict__.pop(key) # f = Foo('alex') # # f.name = ... # print(f['name']) # f.__getitem__('name') # f['age'] = 18 # 赋值 # print(f.age) # 自带的语法 # print(f['age']) # 修改 # f['age'] = 80 # print(f['age']) # 通过实现__getitem__得到的 # del f['age'] # print(f.age) # 删除 # class Foo: # def __init__(self,name): # self.name=name # def __delattr__(self, item): # print('del obj.key时,我执行') # self.__dict__.pop(item) # f = Foo('alex') # del f.name #相当于执行了__delattr__ # # delattr(f,'name')
面试题:
# 写一个类 定义100个对象
# 拥有三个属性 name age sex
# 如果两个对象的name 和 sex完全相同
# 我们就认为这是一个对象
# 忽略age属性
# 做这100个对象的去重工作
class Person:
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def __hash__(self):
# hash算法本身就存在了 且直接在python中就能调用
# 姓名相同 性别相同的对象的hash值应该相等才行
# 姓名性别都是字符串
return hash(self.name+self.sex)
def __eq__(self, other):
if self.name == other.name and self.sex == other.sex:
return True
# python2.7
# 去重 set
# hash方法
# set([obj,obj]) unhashable
# hash算法 一个值 进行一系列的计算得出一个数字在一次程序执行中总是不变
#来让每一个不同的值计算出的数字都不相等
obj_lst = []
obj_lst.append(Person('alex',80,'male'))
obj_lst.append(Person('alex',70,'male'))
obj_lst.append(Person('alex',60,'male'))
obj_lst.append(Person('boss_jin',50,'male'))
obj_lst.append(Person('boss_jin',40,'male'))
obj_lst.append(Person('boss_jin',30,'male'))
obj_lst.append(Person('nezha',20,'male'))
obj_lst.append(Person('nezha',10,'male'))
obj_lst = set(obj_lst)
for obj in obj_lst:print(obj.name)
# set对一个对象序列的去重 依赖于这个对象的两个方法 hash eq
# 可hash顺带着写的
# eq来做判断
# key hash 数字 --》 内存地址 --》 value
# set hash 数字 --》 内存地址 --》 set中的元素
# 'aaa' hash
# java
# set去重 一个容器中 有相同值的内容 __eq__
# 当你这个容器中有10000个元素的时候 我判断第10000个元素
# hash算法
# 'abc'
# 'bca'
# set对一个对象序列的去重 如何判断这两个值是否相等
# 值a进行hash --> 存值
# 值b进行hash --> 判断值是否相等 -相等-> 说明是一样的
#-不相等-> 在开辟一个空间 来存放b