python中面向对象元类的自定义用法

面向对象中的常用方法

1.instance 和 issubclass

instance :判断两个对象是不是一类

issubclass :判断某个类是不是另一个类的子类

#两个常用方法的使用
class Person:
    passclass Student(Person):
    pass
​
stu = Student()
print(isinstance(stu, Student))
print(issubclass(Student,Person))
True
True  ##输出的结果是布尔值。

2.反射

反射,其实就是反省。简单来讲就是对象要具备一种修正错误的能力。

#四种方法:
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('student is studying')
deng = Student('deng', 'male', 25)
#当我们获取一个对象,但是不清楚对象内部细节,就需要用反射。
def test(obj):
    if hasattr(obj, 'name'):
        print(getattr(obj, 'name', "no 'name' attribute"))
​
test(deng)
​
#示例:反射方法
#通过反射方法的方式为对象增加一个方法,但是注意,这样增加的方法就是一个普通函数,不会自动传值。
res = getattr(deng, 'study', None)
print(res)
res()
def run(obj):
    print('student is running')
​
setattr(deng,'run',None)
res1 = getattr(deng, 'run',None)
run(deng)
​
#deng
#<bound method Student.study of <__main__.Student object at 0x00000272D8DB8C50>>
#student is studying
#student is running

3._ _str _ _内置方法

当我们需要自定义显示内容时,就需要实现 _ _str _ _方法

#该方法必须返回一个字符串,返回是什么,打印出来就是什么。
class Test:
    def __init__(self,name):
        self.name = name
    def __str__(self):
        print('str run...')
        return self.name
​
t = Test('ming')
print(t)

其实,在我们将一个对象转换为字符串时,本质就是在调用这个对象的_ str _ _方法。

 

4.  _ _del _ _内置方法

该方法在对象(程序,文件,等等)被从内存中删除时会自动执行该方法。

class Student:
    def __del__(self):
        print('对象被删除。。。')
​
stu = Student()  #创建stu对象
#当该stu对象创建完成后该程序就运行结束,就会运行del方法。
#触发__del__有两种:
    1.程序自动运行结束
    2.手动删除,会立即执行__del__
#示例:
class Student:
    def __del__(self):
        print('对象被删除。。。')
​
stu = Student()
del stu     #在这就会打印,但这是程序并未结束
import time
time.sleep(5) 
什么时候使用它
在python中 有自动内存管理机制 所以 python自己创建的数据 不需要我们做任何操作
但是有一种情况 我们使用python打开了一个不属于python管理的数据
比如打开了一个文件  这个文件一定是操作系统在打开 会占用系统内存  而python解释器无法操作系统内存的
所以 当你的python解释器运行结束后  文件依然处于打开状态  这时候就需要使用__del__来关闭系统资源
​
简单地说 当程序运行结束时 需要做一些清理操作 就使用__del__
​
__del__也称之为 析构函数
​
分析构造 并拆除这个对象

 

5.exec方法

该方法是解析执行python代码(字符串类型) 并且将得到的名称 存储到制定的名称空间  解释器内部也是调用它来执行代码。解释器内部也是将代码看做字符串。

该方法有三个参数:

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

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

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

#示例:
globals_dic = {}
locals_dic = {}
exec('''
a = 1  
if a >1: 
    print('ming') 
else:
    print('deng')''', globals_dic, locals_dic)

#注意:

1.如果同时制定了全局和局部的,则会将字符串中包含的名称解析后存到局部名称空间。

2.如果只传了一个传参数 则 将字符串中包含名称 解析后存到全局中。

 

6.元类

  • 使用class可以发现,类其实是type类型的实例(对象)。

  • 一切皆对象

  • 元类是指 用于产生类的类  type就是元类

class Student:
    def study(self):
        print('studying')
print(type(Student))

总结:

1.类由type实例化产生

2.我们可以使用type产生一个类

3.一个类由类名,类的父类,类的名称空间组成。

type类实例化可以得到类,类实例化可以得到对象。

 

7._ _ call _ _ 内置方法

_ _ call _ _调用的意思,在对象被调用的时候执行该方法(执行该对象所属的类)

#示例:
class Person:
    def __call__(self, *args, **kwargs):
        print('call  running')
p = Person()   #创建对象不会执行call内置方法
p()   # call  running  对象被调用时会自动执行该方法。
自定义元类 的目的

1.可以通过call 来控制对象的创建过程
2.可用控制类的创建过程

自定义一个元类(元类也是一个类),但该类需继承元类type。

#1.通过__call__来控制对象的创建过程
#1.创建一个元类(需要继承type)
#2.覆盖__call__方法,会将正在实例化对象的类转化为传入的参数
#3.在新的__call__方法中,需要按下面编写,然后再加你需要的控制逻辑即可。
class MyMeta(type):
    #self表示创建对象的那个类,*args, **kwargs参数
    def __call__(self, *args, **kwargs):
        print('MyMeta中的call')
        #下面三步是固定的
        #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 is running...')
deng = Person('deng', 26)
print(deng)
deng()
####
MyMeta中的call
<__main__.Person object at 0x00000251588D89B0>
call is running...
​
​
#2.通过元类控制类的创建过程:
#1.创建一个元类(需要继承type)
#2.覆盖__init__方法,该方法会新建类的对象,类名,父类名,名称空间,可以利用这些信息做处理
#3.对于需要控制的类,需要指定metaclass为上面元类
class MyMeta(type):
    def __init__(self, class_name, bases, namespace):
        print('=======')
        #控制类名必须大写
        if not class_name.istitle():
            print('类名必须大写开头。。。')
            #该代码主动抛出异常
            raise TypeError('类名,开头必须大写开头。。。')
        if not self.__doc__:
            raise TypeError
        pass
class Student(metaclass=MyMeta):
    '''
    这是文档注释,可以通过__doc__获取
    '''
    #在类的__init__中可以控制该类对象的创建过程
    def __init__(self, name):
        print('+++++++++++++')
        print(self.__doc__)
        self.name = name
print(Student.__doc__)

8.单例模式

单例   一种设计模式

单个对象,一个类如果只有一个实例,那么该类称之为单例

为什么需要单例?

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, type):
        self.name = name
        self.type = type
    def printing(self, text):
        print('正在打印%s' % text)
    @classmethod
    def get_printer(cls):
        if not cls.obj:
            obj = cls('ec001', 'sharp')
            cls.obj = obj
            print('创建新对象')
        return cls.obj
​
p = Printer.get_printer()
print(p.name)
print(p)
p1 = Printer('ming','002')
print(p1.name)
print(p1)

 

总结:

单例的优点:就是可以优化内存,减少重复对象的产生占用内存。

猜你喜欢

转载自www.cnblogs.com/5j421/p/10147109.html
今日推荐