文章目录
一、isinstance和issubclass
# 判断某个对象是不是某个类的实例
# isinstance()
class Person:
pass
class Student(Person):
pass
stu = Student()
print(isinstance(stu,Student)) #True
#判断是不是子类
#issubclass()
print(issubclass(Student,Person)) #True
二、反射
-
什么是反射:其实说的是反省,简单的说就是对象要具备一种修正错误的能力
hasattr 是否存在某个属性
getattr 获取某个属性的值
setattr 设置某个属性的值
delattr 删除某个属性
-
什么时候用反射:
如果在编写代码期间,就能明确知道我要访问的属性,没有必要使用反射
如果在编写代码期间,无法明确知道我要访问的属性,这时就应该使用反射
class Student:
def __init__(self,name,sex,age):
self.name = name
self.age = age
self.sex = sex
def study(self):
print("学生正在学习...")
stu = Student("矮根","woman",38)
print(stu.name) #矮根
#当你获取到一个对象,但是并不清楚对象的内部细节时,就需要使用反射了
def test(obj):
if hasattr(obj,"name"):
print(getattr(obj,"name","没有name属性"))
test(stu)
#设置属性的值
setattr(stu,"school","beijing")
print(getattr(stu,"school","没有学校属性")) #beijing
#删除属性的值
delattr(stu,"school")
print(getattr(stu,"school","没有学校属性")) #没有学校属性
#删除属性的值
delattr(stu,"age")
print(stu.age)
练习:
扫描二维码关注公众号,回复:
4940474 查看本文章
class Student:
def study(self):
print("学习中....")
stu = Student()
res = getattr(stu,"study",None)
print(res)
def eat(self):
print("正在吃饭...")
#可以通过反射的方式为对象增加一个方法,但是注意这样增加的方法就是一个普通函数,不会自动传值
setattr(stu,"eat",eat) #<function eat at 0x0000021994A82E18>
eat(stu) #正在吃饭...
===================================================
# 需要编写一个CMD工具,这个工具可以支持两个命令 dir,tasklist
class CMD:
def dir(self):
print("列出当前文件夹目录....")
def tasklist(self):
print("查看任务列表.....")
cmd = CMD()
res = input("请输入指令:").strip()
if hasattr(cmd,res):
func = getattr(cmd,res)
print(func)
func()
else:
print("输入的指令不正确....")
三、__
str__
- 前后带双下滑线的都是特殊的内置函数,会在某些时机自动执行,一般情况我们不应该直接调用他们。当我们需要自定义打印显示内容时,就需要实现
__
str__
方法,该方法必须返回一个字符串,返回的是什么,打印出来就是什么
class Test:
def __init__(self,name):
self.name = name
def __str__(self):
print("str run....")
return self.name
t = Test("张三")
#在将一个对象转换字符串时,本质就是在调用这个对象 __str__ 方法
print(str(t))
#str run....
#张三
四、__
del__
-
当对象从内存中删除时会自动执行,另外一种情况时,程序员手动删除了这个对象,也会自动执行
-
什么时候用:在python中有自动内存管理机制,所以 python自己创建的数据,会自动清理,不需要我们做任何操作。但是有一种情况,我们使用python打开了一个不属于python管理的数据,比如:打开了了一个文件,这个文件是操作系统在打开,会占有系统内存,而python解释器无法操作系统内存的,所以当你的python解释器运行结束后,文件依然处于打开状态,这时候就需要使用
__
del__
来关闭系统资源简单的说,当程序运行结束时,需要做一些清理操作,就使用
__
del__
__
del__
也称之为析构函数,分析构造,并拆除这个对象
class Student:
def __del__(self):
print("对象被删除了....")
stu = Student()
#手动删除,立即执行__del__
del stu
class TextFile:
def __init__(self,filepath,mode="rt",encoding="utf-8"):
self.file = open(filepath,mode=mode,encoding=encoding)
def read(self):
return self.file.read()
def write(self,text):
self.file.write(text)
# 该方法其实就是一个通知性质 仅仅是告诉程序员 对象即将被删除
def __del__(self):
# 在这里关闭系统的文件 妥妥的
self.file.close()
tf = TextFile("a.txt")
print(tf.read())
tf.file.close() #不需要手动关闭了,在对象删除时会自动关闭
tf.read() #等所有的程序执行完,在执行关闭,只执行一次
五、exec方法
- exec:execute的缩写,表示执行的意思
- exec作用:其作用是帮你解析执行python代码,并且将得到的名称存储到指定的名称空间,解释器内部也是调用它来执行代码的
- 参数一:需要一个字符串对象,表示需要被执行的python语句
- 参数二:是一个字典,表示全局名称空间
- 参数三:也是一个字典,表示局部空间
globalsdic = {}
localsdic = {}
exec("""
aaa = 1
bbbb = 2
def func1():
print("我是func1")
""",globalsdic,localsdic)
#如果同时制定了全局和局部,则会将字符串中包含名称解析后存到局部中
print(localsdic) #'aaa': 1, 'bbbb': 2, 'func1': <function func1 at 0x000001DF2FBD2E18>}
localsdic["func1"]() #我是func1
# 如果只传了一个传参数,则将字符串中包含名称解析后存到全局中
exec("""
aaaaaaaaaaaaaaaaaaaa = 1
bbbbbbbbbbbbbbbbbbbb = 2
""",localsdic)
六、元类
- 什么是元类:一切皆对象,元类是指,用于产生类的类,type就是元类,所有的自定义类都是通过type实例化得来
- 类是由type实例化产生的
- 我们可以使用type来产生一个类
- 一个类是由类名字,类的父类元祖, 类的名称空间三个部分组成
#class 也是一个对象
class Student(object):
school = "北京大学!"
def study(self):
print("学习中...")
#使用type可以发现,类其实是type类型的实例(对象)
print(type(Student)) #<class 'type'>
#我们可以自己调用type实例化产生一个类
code = """
name = "张三"
age = 18
def hello(self):
print("hello %s" % self.name)
"""
code = """
name = "张三"
age = 18
def hello(self):
print("hello %s" % self.name)
"""
#类的名字
class_name = "MyClass"
#类的的父类们
base_classes = (object,)
#类的名称空间
namespace = {}
exec(code,{},namespace)
res = type(class_name,base_classes,namespace)
print(res.name) #张三
print(res.age) #18
res.hello(res) #hello 张三
#一个类是由类名字,类的父类元祖, 类的名称空间三个部分组成
class Test(object): #Test = type("Test",(object,),{})
pass
元类补充:
class MyMeta(type):
def __new__(cls, *args, **kwargs):
print("new run")
res = type.__new__(cls,*args)
return res
def __init__(self,class_name,bases,namespace):
print("init run")
print(self)
class Student(metaclass=MyMeta):
pass
print(Student)
#new run
#init run
#<class '__main__.Student'>
#<class '__main__.Student'>
__new__与__init__的区别
__new__ 比 __init__ 先执行,其作用是创建一个空的类对象
作为一个类对象,必须具备是三个组成部分,所以调用type中的__new__来完成组
得到这个类对象后需要将其返回,以供__init__来使用
七、__
call__
方法控制对象的实例化
__
call__
:调用的意思,在对象被调用时执行- 自定义元类的目的:
- 可以通过
__
call__
来控制对象的创建过程 - 可用控制类的创建过程
- 可以通过
class MyMeta(type):
# self表示要创建对象的那个类(Person) *args是调用Person类时传入的参数
def __call__(self, *args, **kwargs):
print("MyMte中的 call run")
print(self,*args,**kwargs)
# 下面的三步是固定写法,是一个模板,只要你需要控制对象的创建过程,就应该先把模板写出来
# 1.创建空对象
obj = object.__new__(self)
# 2.调用初始化方法
self.__init__(obj,*args,**kwargs)
# 3.得到一个完整的对象
return obj
# 修改Person类的元类为MyMeta
class Person(metaclass=MyMeta):
def __init__(self,name,age):
self.name = name
self.age = age
def __call__(self, *args, **kwargs):
print("call run...")
#调用Person这个对象时,执行的是Person的类(type)中__call__ 方法
p = Person("张三疯",80)
print(p.name) #张三疯
print(p.age) #80
八、通过元类控制类的创建过程
- 要控制类的创建过程,只要找到类所属的类中的
__
init__
即可
class MyMeta(type):
# self 刚建出来的类
# 第二个 类的名字
# 第三个 类的父类们(元组)
# 第四个 这个类传进来的名称空间
def __init__(self,class_name,bases,namespace):
print("============================")
#print(self.__dict__)
# 我要控制类的名字,必须是大写开头
if not class_name.istitle():
print("类名 必须大写开头...... ")
# 该代码是主动抛出异常
raise TypeError("类名 必须大写开头...... ")
#要空类的创建,必须包含__doc__这个属性
if not self.__doc__:
raise TypeError("类中必须有文档注释.....")
class student(metaclass=MyMeta): # Student = MyMeta("Student",(object,),{})
"""
这是文档注释 可以通过__doc__来获取
这是一个学生类
"""
def __init__(self,name):
print("-----------------------")
print(self.__dict__)
self.name = name
print(student.__doc__)
元类的使用总结:
- 元类是用于创建类的类
- 元类是为了能控制类的创建过程以及类实例化对象的过程
一、控制类的创建过程:
- 创建一个元类(需要继承type)
- 覆盖
__
init__
方法,该方法会将新建的类对象、类名,父类们、名称空间都传进来,可以利用这些信息在做处理 - 对于需要被控制的类,需要指定metaclass 为上面的元类
二、控制类实例化对象的过程:
- 创建一个元类(需要继承type)
- 覆盖
__
call__
方法,会将正在实例化对象的类,调用类传入的参数都传进来 - 在
__
call__
方法中必须要先编写模板代码- 创建空对象
- 调用类的
__
init__
方法来初始化这个空对象 - 返回该对象
- 加入你需要控制的逻辑
类的三个组成部分:
类名、父类们、名称空间
元类===》实例化产生===》类===》实例化产生===》对象
九、单例模式
- 什么是单例模式:单个实例,一种设计模式
class MyMeta(type):
obj = None
def __call__(self, *args, **kwargs):
if not MyMeta.obj:
obj = object.__new__(self)
self.__init__(obj,*args,**kwargs)
MyMeta.obj = obj
return MyMeta.obj
#打印机类
class Printer(metaclass=MyMeta):
"""
这是一个单例类,请不要直接实例化,使用get方法来获取实例
"""
obj = None
def __init__(self,name,brand,type):
self.name = name
self.brand = brand
self.type = type
def printing(self,text):
print("正在打印 %s" %text)
# 通过该方法来获取对象可以保证只有一个对象
# 但是这还不够,因为还是可以通过调用类产生新对象
# 就应该使用元类来控制实例化的过程 __call__
# 在__call__ 中编写代码,保证每次调用call都返回同一个实例即可
@classmethod
def get_printer(cls):
if not cls.obj:
obj = cls("ES005","爱普生","彩色打印机")
cls.obj = obj
print("创建了新的对象")
return cls.obj
p = Printer.get_printer()
print(p) #<__main__.Printer object at 0x0000023FCEAA1208>
p = Printer.get_printer()
print(p) #<__main__.Printer object at 0x0000023FCEAA1208>
p1 = Printer("ES005","爱普生","彩色打印机")
p2 = Printer("ES005","爱普生","彩色打印机")
print(p1) #<__main__.Printer object at 0x0000023FCEAA1208>
print(p2) #<__main__.Printer object at 0x0000023FCEAA1208>