isinstance和issubclass
isinstance(obj,cls) # 检查是否obj是否是类 cls 的对象
class Foo(object):
pass
obj = Foo()
isinstance(obj, Foo) # ture
issubclass(sub, super) # 检查sub类是否是 super 类的派生类
class Foo(object):
pass
class Bar(Foo):
pass
issubclass(Bar, Foo) # ture
反射
1 什么是反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。
2 python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
四个可以实现自省的函数 hasattr getattr setattr delattr
下列方法适用于类和对象(一切皆对象,类本身也是一个对象),还可以反射类中的模块,查看模块是否存在,总而言之,只要能用a.b 的都可以用
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)
# hasattr(*args, **kwargs) 检测是否含有某属性
print(hasattr(obj,'name'))
print(hasattr(obj,'say_hi'))
# getattr(object, name, default=None) 获取属性
n = getattr(obj,'name')
print(n) # egon
func = getattr(obj,'say_hi')
func() # hi,egon
print(getattr(obj,'aaaaaaaa','不存在啊')) # 不存在啊
# setattr(x, y, v) 设置属性
setattr(obj,'sb',True)
setattr(obj,'show_name',lambda self:self.name+'sb')
print(obj.__dict__) # {'name': 'egon', 'age': 73, 'sb': True, 'show_name': <function <lambda> at 0x00000207DFFE6598>}
print(obj.show_name(obj)) # egonsb
# delattr(x, y) 删除属性
delattr(obj,'age')
delattr(obj,'show_name')
delattr(obj,'show_name111') # 不存在,则报错
__str__、__repr__和__fromat__
改变对象的字符串显示__str__,__repr__,自定制格式化字符串__format__
str函数 或者 print函数 ---> obj.__str__()
repr 或者 交互式解释器 ---> obj.__repr__()
如果__str__没有被定义,那么就会使用__repr__来代替输出(备胎)
注意:这俩方法的返回值必须是字符串,否则抛出异常
#_*_coding:utf-8_*_
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)) # from repr: School(oldboy1,北京)
print('from str: ',str(s1)) # from str: (oldboy1,北京)
print(s1) # (oldboy1,北京)
print(format(s1,'nat')) # oldboy1-北京-私立
print(format(s1,'tna')) # 私立:oldboy1:北京
print(format(s1,'tan')) # 私立/北京/oldboy1
print(format(s1,'asfdasdffd')) # oldboy1-北京-私立
__del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
class Foo:
def __del__(self):
print('执行我啦')
f1=Foo()
del f1
print('------->')
# 输出结果
执行我啦
------->
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.setitem('age',18)
f1['age1']=19
del f1.age1
del f1['age']
f1['name']='alex'
print(f1.__dict__) # {'name': 'alex'}
__new__
构造方法,__new__ 实在执行__init__ 之前执行的,object 已实现该方法,所以一般不用写,作用是创建一个self
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'): # 判断类的命名空间中是否存在变量_instance
cls._instance = object.__new__(cls, *args, **kw) # 在类的命名空间中加了一个私有的静态变量_instance
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 ,实际调用__eq__ 方法
print(one is two) # True
__call__
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print('__call__')
obj = Foo() # 执行 __init__
obj() # 执行 __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))
__hash__
object中未实现,如果有需求,需要自己实现
class A:
def __init__(self):
self.a = 1
self.b = 2
def __hash__(self):
return hash(str(self.a)+str(self.b))
a = A()
print(hash(a))
__eq__
object已实现
class A:
def __init__(self):
self.a = 1
self.b = 2
def __eq__(self,obj):
if self.a == obj.a and self.b == obj.b:
return True
a = A()
b = A()
print(a == b)
集合set判断的依据是 先判断__eq__ ,如果相同,在判断__hash__, 如果两者都相同,则认为相同
String类型的equals方法 只比较内容 不比较是否来引用同一个对象
== 实际调用__eq__ 方法,判断值是否相等
is 判断的是内存地址,= 赋值时赋值的内存地址 , 如果赋值时使用字符串,列表等,存在小地址池的原因,也会存在内存地址相同的情况 ,is 运算符比 == 效率高,在变量和None进行比较时,应该使用 is