封装:
✳第一个层面的封装:类就是麻袋,本身就是一种封装。
✳第二个层面的封装:类定义私有的,只在类的内部使用外部无法访问
✳第三个层面的封装:明确区分内外,内部的实现逻辑,外部无法知晓,并且为封装到内部的逻辑提供一个访问的接口给外部使用
反射/自省:
1、hasattr(object,'字符串形式的名称'):判断object中有没有一个name字符串对应的方法和属性,用于开发的不完整阶段,可插拔式设计
class Test:
name = 'Jax'
def add(self):
print('6')
def mul(self):
print('7')
a = hasattr(Test,'name')
print(a)
>>> True
可插拔式设计和基于模块的反射:
import test
if hasattr(test,'name'):
func = getattr(test,'name')
func()
else:
print('不存在')
>>> 不存在
2、delattr(object,y) 删除属性 ==== del object.y
class Test:
name = 'Jax'
def add(self):
print('6')
def mul(self):
print('7')
delattr(Test,'name')
print(Test.__dict__)
3、 getattr(object(实例对象), name[,'None']) 最后的是默认值 是在找不到属性的情况下的打印,没有设置会报错
class Test:
name = 'Jax'
def add(self):
print('6')
def mul(self):
print('7')
print(getattr(Test,'aaaa', 'none'))
>>> none
返回值加括号运行函数
class Test:
name = 'Jax'
def add(self):
print('6')
def mul(self):
print('7')
t = Test()
getattr(t,'add')()
>>> 6
4、setattr(object, key,value) 设置属性 value 既可以是是值
class Test:
name = 'Jax'
def add(self):
print('6')
def mul(self):
print('7')
t = Test()
setattr(t,'name', 10)
print(t.name)
>>> 10
也可以是匿名函数
class Test:
name = 'Jax'
def add(self):
print('6')
def mul(self):
print('7')
t = Test()
setattr(t,'name', lambda x: x+1)
a = t.name(5)
print(a)
>>> 6
Python的工厂函数(魔术方法):
有许多这样的例子:len(str) 在本质上调用----->str.__len__(),format(name)---->name.__format__(), t.setattr(key,value)---->__setattr__(self,key,value)
a = 15
print(str(a))
print(a.__str__())
>>> 15
>>> 15
__getattr__(self,item): 当调用了一个不存在的属性或方法的时候,执行此函数,不存在的属性名回传个item
class Test:
name = 15
def __getattr__(self, item):
print('error'+ item)
t = Test()
t.xxx
>>> errorxxx
__delattr__(self,item): 当删除了一个不存在的类或方法的时候,执行此函数,不存在的属性名回传个item。删除的本质:self.__dict__.pop(item)
class Test:
def __init__(self, age):
self.age = age
def __delattr__(self, item):
print('start delete')
self.__dict__.pop(item)
t = Test('JAX')
print(t.__dict__)
del t.age
print(t.__dict__)
>>> {'age': 'JAX'}
>>> start delete
>>> {}
__setattr__(self,key,value): 通过调用self的字典来实现增加功能,self.__dict__['key_name']=value,value是在初始化函数__init__里传入的值,每运行一次就会触发一次__setattr__函数。(只有对象.xxx时才会触发__setattr__方法,并不是所有的赋值都会触发该方法)
f.y = value 一样 当初始化函数和设置函数的参数不同时(参数数量不一样),就会取最后一个参数的运行设置函数,并且会产生递归,因为每一次初始化赋值时就会,触发设置函数,设置函数又会调用自身,从而形成递归 不能设置成self.key = value,当每一次运行初始化函数时,就会触发设置函数,系统自定义的会自动把值加入字典中,自己定义的,就什么也没有。 __init__ 的参数名传到了key,值传到value。如果在函数__setattr__内写入f.y = value此时,函数__setattr__又会被调用,形成递归。
class Test:
def __init__(self, age):
self.age = age
def __setattr__(self, key, value):
print('start setting')
self.__dict__[key] =value
print(key)
print(value)
t = Test('JAX')
print(t.__dict__)
>>> start setting
>>> age
>>> JAX
>>> {'age': 'JAX'}
对于__setattr__的另外一种解决方法:通过调用父类的__setattr__进行赋值
class Foo(object):
def __init__(self):
object.__setattr__(self,"storage",{}) # 这样赋值不会触发setattr __slots__ 外面之能调用这几个方法
def __setattr__(self, key, value):
return None
f = Foo()
Tips:类创建的过程调用的函数
1、__new__ 实例化类第一个调用的方法,用于修改继承类,一般不用
2、__init__ 实例化类第二个调用的方法,初始化一些数据,类似造物主
isinstance(obj,cls) 检查是否obj是否是类cls的对象,子类的实例对象也是父类的实例对象
class Test:
pass
class One(Test):
pass
p = One()
print(isinstance(p,One))
print(isinstance(p,Test)) # 子类的实例对象也是父类的实例对象
>>> True
>>> True
issubclass(sub,super) 检查sub类是否是super的派生类. 子类在前,父类在后
class Test:
pass
class One(Test):
pass
p = One()
print(issubclass(One,Test))
>>> True
自己反射自己:
import sys
obj = sys.modules[__name__]
print(hasattr(obj,'attr‘))
>>> False
在一个类找属性有或没有都会触发__getattribute__. __getattribute__是 __getattr__的上级,当上级抛出异常时,下级就会工作
先触发__getattribute__后触发__getattr__
class Test:
name = 'Jax'
def __getattr__(self,item):
print('I am getattr')
def __getattribute__(self, item):
print('I am getattribute')
raise AttributeError('错误')
t = Test()
t.n
>>> I am getattribute
>>> I am getattr