封装:

✳第一个层面的封装:类就是麻袋,本身就是一种封装。

✳第二个层面的封装:类定义私有的,只在类的内部使用外部无法访问

✳第三个层面的封装:明确区分内外,内部的实现逻辑,外部无法知晓,并且为封装到内部的逻辑提供一个访问的接口给外部使用

反射/自省:

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