面向对象高级-反射/魔法方法/元类

day25

面向对象高级

一、isinstance and issubclass:

1、isinstance() 判断一个对象是不是一个类的实例化对象;

2、issubclass 判断一个类是不是另一个类的子类。

class People(object):
    pass
class Student(People):
    pass
​
stu = Student()
isinstance() 判断一个对象是不是一个类的实例化对象
print(isinstance(stu, Student))       #True
print(isinstance(stu, People))        #True
print(isinstance(stu, object))        #True
print(isinstance(stu, int))           #False
issubclass 判断一个类是不是另一个类的子类
print(issubclass(Student, People))    #True

二、反射

1、什么是反射:程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。

2、反射提供的四种方法:

a、hasattr 是否存在某个属性

b、getattr 获取某个属性的值

c、setattr 设置某个属性的值

d、delattr 删除某个属性

注:以上的四个方法都是通过字符串来操作属性

class Student:
    def __init__(self,name,sex,age):
        self.name = name
        self.age = age
        self.sex = sex
​
    def study(self):
        print("学生正在学习...")
​
stu = Student("egon","woman",38)
# # print(stu.name)
# stu.name = "gogon"
# del stu.name
# 当你获取到一个对象 但是并不清楚搞对象的内部细节时  就需要使用反射了
def test(obj):
    if hasattr(obj,"name"):
        print(getattr(obj,"name","没有name属性"))
​
test(stu)
​
setattr(stu,"school","beijing")
delattr(stu,"school")
print(getattr(stu,"school","没有学校属性"))
delattr(stu,"age")
print(stu.age)
##反射练习##
# class Student:
#     def study(self):
#         print("学习中....")
#
# stu = Student()
# res = getattr(stu,"study",None)
# print(res)
# def eat(self):
#     print("正在吃饭...")
#
# # 可以通过反射的方式为对象增加一个方法 但是注意 这样增加的方法就是一个普通函数 不会自动传值
# setattr(stu,"eat",eat)
#
# print(getattr(stu,"eat",None))
​
​
# 需要编写一个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("安米")
​
print(int(1).__str__())
# print([1,2,3,5])
# print(t)
# 在讲一个对象转换字符串时  本质就是在调用这个对象 __str__方法
print(str(t))

四、__ del__析构函数

当程序运行结束时,python解释器在清理内存时,会自动调用该方法。针对此特性,我们可以在此方法中加入一些Python解释器无法自动完成的清理操作,已达到释放内存的效果。


# class Student:
#
#     def __del__(self):
#         print("对象被删除了....")
#
# stu = Student()
#
# # 手动删除 立即执行__del__
# del stu
# import time
# time.sleep(5)
​
​
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("2.今日内容.txt")
print(tf.read())
# tf.file.close() 不需要手动关闭了  在对象删除时会自动关闭
tf.read()

 

五、exec

1、作用:帮助解析字符串形式的python代码,并且将得到的名称存储到指定的名称空间中,Python解释器的内部也是通过调用它来执行代码的。

需要传入三个参数:

参数一:需要一个字符串对象 表示需要被执行的python语句;

参数二:是一个字典 表示全局名称空间;

参数三:也是一个字典 表示局部名称空间。

globalsdic = {}  #相当于是python内置域
localsdic = {}   #相当于前面提到的全局域
exec("""
aaaaaaaaaaaaaaaaaaaa = 1
bbbbbbbbbbbbbbbbbbbbbbbbbbbb = 2
def func1():
    print("我是func1")
""",globalsdic,localsdic)
​
# 如果同时制定了 全局和局部 则 会字符串中包含名称 解析后存到局部中
# print(globalsdic)
print(localsdic)
localsdic["func1"]()

六、元类

1、元类用于产生类的类,type就是元类,所有的自定义类都是通过type实例化得来的。

2、类也是一个对象,可以通过使用type发现,类就是type类型的实例(对象),因此我们也可以自己调用type来实例化产生一个类。

#通过调用type来实例化一个类
classname = "student"
student = type(classname, (object,),{})
print(student)
print(student.__dict__)
p1 = student()
​
class Test(object):  #Test = type("Test",(object,),{}) 等价
    pass

总结:1、类是由type实例化产生的;

2、我们可以使用type来实例化出来一个类;

3、一个类是由类名字、类的父类元组和类的名称空间三个部分组成。


 

七、__ call__

在对象被调用时执行

自定义元类的目的:

1、可以通过__ call__来控制对象的创建过程:

#用__call__来控制对象的创建过程
class MyMeta(type):
    def __call__(self,*args,**kwargs):
        print("Meta call run!")
        obj = object.__new__(self)  #创建一个空对象
        self.__init__(obj,*args,**kwargs)  #调用初始化函数
        return obj           #得到一个完整的对象
class People(metaclass = MyMeta):
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def __call__(self):
        print("call run!")
#调用Person这个对象时 执行的是 Person的类(MyMeta)中__call__ 方法
p = Person("张三疯",80)
print(p)
# 当调用对象时 会执行该对象所属类中的__call__方法
# p()    
print(p.name)
print(p.age)

2、可以控制类的创建过程,(__ init__):

class MyMeta(type):
    def __init__(self,class_name,bases,namespace):
        print(self.__dic__)
        if not class_name.istitle:
            raise TypeError("类名首字母必须大写。。")
        if not self.__doc__:
            raise TypeError("类中必须要有文档注释。。。")
class Student(metaclass = MyMeta):
"""
    这是文档注释
"""
    def __init__(self,name,age):
        self.name = name
        self.age = age
 

总结:

1、控制类的创建过程:

a、创建一个元类(需要继承type);

b、覆盖__ init__方法,该方法会将新建的类对象,类名,父类元组,名称空间一同传入;

c、对于需要被控制的类,需要在类名后面指定metaclass为上面的元类。

2、控制类实例化对象的过程

a、创建一个元类(需要继承type);

b、覆盖__ call__方法,会将正在实例化对象的类、调用类时传入的参数一同传入;

c、在__ call__方法中,必须要先编写模板代码;

1、创建空对象; 2、调用类的__ init__方法来初始化这个空对象; 3、返回该对象。

d、加入你需要控制的逻辑 。


 

八、单例

1、什么是单例:如果一个类只有一个实例,那么该类称之为单例

# 单例的实现
class MyMeta(type):
    obj = None
    def __call__(self, *args, **kwargs):
        if not MyMeta.obj:
            MyMeta.obj = object.__new__(self)
            self.__init__(MyMeta.obj, *args, **kwargs)
        return MyMeta.obj
​
class Printer(metaclass=MyMeta):
    obj = None
    def __init__(self, name, brand, type):
        self.name = name
        self.brand = brand
        self.type = type
​
    @classmethod
    def get_printer(cls):
        if not cls.obj:
            cls.obj = cls("et202","aideli","2018")
        return cls.obj
​
​
    def printing(self):
        print("%s is printing!"%self.name)
​
p = Printer.get_printer()
print(p)
p = Printer.get_printer()
print(p)
p = Printer.get_printer()
print(p)
​
p = Printer("et202","aideli","2018")
print(p)
​
#result:
#<__main__.Printer object at 0x0000000002528E80>
#<__main__.Printer object at 0x0000000002528E80>
#<__main__.Printer object at 0x0000000002528E80>
#<__main__.Printer object at 0x0000000002528E80>

 

原文地址:https://www.cnblogs.com/peng-zhao/p/10145402.html