![09042d4359aecb0436c58142312f832a.png](https://i-blog.csdnimg.cn/blog_migrate/ab20b76aa598e5d42ac792b8711af4c4.jpeg)
- isinstance(obj,cls)和issubclass(sub,super)
- 反射 hasattr()、setattr()、getattr()、delattr()
- 反射模块 __import__和importlib模块
- __str__和__del__
- __setattr__、__delattr__、__getattr__
- 二次加工标准类型(包装、授权)
- __getattribute__
- __setitem__和__getitem和__delitem__([]拦截方法)
- __format__(自定义格式化对象的字符串)
- __str__和__repr__
- __del__(析构方法)
- __doc__(类的注释信息)
- 描述符(__get__,__set__,__delete__)
- 类的装饰器
- 通过描述符+装饰器限制参数类型
- 自制@property、@classmethod、@staticmethod
- __call__
- __init__和__new__(重点)
- __module__和__class__
- __slots__和__dict__
- __all__
- 实现迭代器(__next__和__iter__)
- 上下文管理器(__enter__和__exit__)
- __len__
- __hash__
- __eq__
isinstance和issubclass
isinstance(obj,cls)检查是否obj是否是类 cls 的对象
ll = [1, 2, 3]
print(isinstance(ll, list))
dic = {
'name': 'lqz'}
print(isinstance(dic, dict))
结果:
True
True
isinstance和type的区别:
# isinstance比type强大在,它可以判断带有继承关系的类的对象,type只能判断所属类的对象
class A:
pass
class B(A):
pass
isinstance(A(), A) # returns True
type(A()) == A # returns True
isinstance(B(), A) # returns True
type(B()) == A # returns False
isinstance和type的区别:
- type() 不认为子类对象属于父类的类型,不考虑继承关系
- isinstance() 认为子类对象属于父类的类型,会考虑继承关系
如果要判断对象和类的关系推荐使用 isinstance()
issubclass(sub, super)检查sub类是否是 super 类的派生类(子类)
#单层单继承:
class Mydic(dict):
pass
print(issubclass(Mydic, dict))
print(issubclass(Mydic, list))
print(issubclass(Mydic, object))
结果:
True
False
True
#单层多继承:是所有父类的派生类
class Foo:
pass
class Mydic(dict, Foo):
pass
print(issubclass(Mydic, dict))
print(issubclass(Mydic, Foo))
结果:
True
True
#多层单继承:是所有直接或间接父类的派生类
class Animal:
pass
class Dog(Animal):
pass
class TDog(Dog):
pass
print(issubclass(TDog, Dog))
print(issubclass(TDog, Animal))
结果:
True
True
反射
python是动态语言,而反射(reflection)机制被视为动态语言的关键。
python面向对象中的反射指在程序的运行状态中通过字符串的形式操作对象相关的属性。由于python中的一切事物都是对象,所以都可以使用反射。这种动态获取程序信息以及动态调用对象的功能称为反射机制。
首先通过内置函数dir来获取任意一个类或者对象的属性列表,列表中全为字符串格式
>>> class People:
... def __init__(self,name,age,gender):
... self.name=name
... self.age=age
... self.gender=gender
...
>>> obj=People('egon',18,'male')
>>> dir(obj) # 列表中查看到的属性全为字符串 相当于obj.__dir__()
[......,'age', 'gender', 'name']
>>> obj.__dict__ # 属性字典
{
'name': 'egon', 'age': 18, 'gender': 'male'}
接下来就是想办法通过字符串来操作对象的属性了,这就涉及到4个内置函数的使用
四个内置函数(类和对象都可以被这四个函数操作)
- hasattr() # 判断一个对象中是否有某个属性或方法(判断字符串是不是对象的属性或方法)
- getattr() # 通过字符串获取对象中的属性或方法
- setattr() # 通过字符串设置对象的属性或方法
- delattr() # 通过字符串删除对象的属性或方法
class Teacher:
def __init__(self,full_name):
self.full_name =full_name
t=Teacher('Egon Lin')
# hasattr(object,属性)
hasattr(t,'full_name') # 按字符串'full_name'判断有无属性t.full_name
# getattr(object, 属性, 默认值)
getattr(t,'full_name',None) # 等同于t.full_name,获取对象中的属性或方法,不存在该属性则返回默认值None
注意:获取方法是获取其内存地址,使用时注意加括号
# setattr(object, 属性, 属性值) # x.y=v
setattr(t,'age',18) # 等同于t.age=18,设置属性或方法
# delattr(object, 属性)
delattr(t,'age') # 等同于del t.age,删除了属性或方法
setattr设置方法使用解析:
class Person:
def __init__(self, name, age):
self.age = age
self.name = name
def print_name(self):
print(self.name)
p = Person('sakura', 18)
def xxx(self):
print('xxx')
print(self.age)
# 如果直接给对象绑定方法
# setattr(p, 'print_age', xxx) #会报错
# p.print_age()
# 给类绑定方法,绑定给对象的方法是写在类中,如果使用反射,要反射到类内部
setattr(Person,'print_age',xxx)
p.print_age()
结果:
xxx
18
反射给对象(不推荐使用)
def xxx(obj):
print(obj.age)
setattr(p,'print_age',xxx)
p.print_age(p)
反射模块 __import__('字符串')
# 反射模块:__import__('字符串')
i = input('请输入使用哪个模块:')
# __import__('字符串')
s1 = __import__(i)
s1.test()
print(s1.name)
# 如果是带路径的模块导入
i = input('请输入使用哪个模块:') #如 root.db.db_handler
s1 = __import__(i, fromlist=True) # 加上fromlist=True即可
s1.test()
print(s1.name)
反射模块--importlib模块
# 反射模块(py3中用的比较多,框架中)避免了带有路径的模块的导入问题,适用范围更广
import importlib
i=input('请输入您要使用的模块:')
a=importlib.import_module(i)
a.test()
反射的实际应用案例:
>>> class FtpServer:
... def serve_forever(self):
... while True:
... inp=input('input your cmd>>: ').strip()
... cmd,file=inp.split()
... if hasattr(self,cmd): # 根据用户输入的cmd,判断对象self有无对应的方法属性
... func=getattr(self,cmd) # 根据字符串cmd,获取对象self对应的方法属性
... func(file)
... def get(self,file):
... print('Downloading %s...' %file)
... def put(self,file):
... print('Uploading %s...' %file)
...
>>> server=FtpServer()
>>> server.serve_forever()
input your cmd>>: get a.txt
Downloading a.txt...
input your cmd>>: put a.txt
Uploading a.txt...
反射和隐藏属性的结合
# 通过反射,获取隐藏属性
class Person:
def __init__(self, name, age, sex):
self.age = age
self.sex = sex
self.__name = name
p=Person('lqz',18,'男')
# name=getattr(p,'__name') # 无法获取__name属性
name=getattr(p,'_Person__name')
print(name)
# 通过反射,设置成隐藏属性
class Person:
def __init__(self, name, age, sex):
self.age = age
self.sex = sex
self.__name = name
def print_wife(self):
print(self.__wife) # 相当于self._Person__wife
p=Person('qys',18,'男')
setattr(p,'__wife','刘亦菲')
print(p.__wife) # 能,直接找到__wife属性
setattr(p,'_Person__wife','刘亦菲') #对对象设置了p._Person__wife='刘亦菲'
# print(p.__wife) # 不能
p.print_wife() # 能
setattr(Person,'_Person__wife','刘亦菲') #对类设置了Person._Person__wife='刘亦菲'
print(Person.__dict__)
print(Person._Person__wife)
p.print_wife()
结果:
刘亦菲
刘亦菲
{
'__module__': '__main__'……, '__doc__': None, '_Person__wife': '刘亦菲'}
刘亦菲
刘亦菲
反射的好处
- 实现可插拔机制:可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能
- 动态导入模块(基于反射,反射当前模块成员)
类的内置方法(面向对象的魔法方法)
Class机制内置了很多特殊的方法,都是以双下划线开头和结尾的即魔法方法,会在满足某种条件时自动触发,常用的如下:
__str__和__del__
__str__方法会在对象被打印时自动触发,print功能打印的就是它的返回值,我们通常基于方法来定制对象的打印信息,该方法必须返回字符串类型
>>> class People:
... def __init__(self,name,age):
...