美文网首页
day34-元类

day34-元类

作者: 天行_b6d0 | 来源:发表于2020-08-25 14:41 被阅读0次

一、什么是元类

python中一切皆对象,我们可以定义一个类,那么这个类也是一个对象,对象是实例化类得到的,所以类肯定也是某个类实例化得到的,而这个类就是元类。通俗的说,元类就是负责产生类的类。

class Dog(object):

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def say(self):
        print('%s says wang!' % self.name)


obj = Dog('wangcai', 2)  # 调用Dog类=》对象obj
#                                  调用元类=》Dog类

# print(type(obj))
print(type(Dog))

元类>>实例化>>Dog类>>实例化>>对象

得到一个结论:默认的元类是type,默认情况下我们用class关键字定义的类都是由type产生的。

二、class关键字底层的运作

  1. 先拿到一个类名
class_name = "Dog"
  1. 然后拿到类的父类
class_bases = (object,)
  1. 再运行类体代码,将产生的名字放到名称空间中
class_dic = {}
class_body = """

def __init__(self, name, age):
    self.name = name
    self.age = age

def say(self):
    print('%s says wang' % self.name)
"""
exec(class_body,{},class_dic)
# print(class_dic)
  1. 调用元类(传入类的三大要素:类名、基类、类的名称空间)得到一个元类的对象,然后将元类的对象赋值给变量名Dog,Dog就是我们用class自定义的那个类.
Dog = type(class_name,class_bases,class_dic)

三、补充之exec的用法

exec:三个参数
参数一:包含一系列python代码的字符串
参数二:全局作用域(字典形式),如果不指定,默认为globals()
参数三:局部作用域(字典形式),如果不指定,默认为locals()
可以把exec命令的执行当成是一个函数的执行,会将执行期间产生的名字存放于局部名称空间中

g={
    'x':1,
    'y':2
}
l={}

exec('''
global x,z
x=100
z=200

m=300
''',g,l)

print(g) #{'x': 100, 'y': 2,'z':200,......}
print(l) #{'m': 300}

四、自定义元类

class Mymeta(type):  # 只有继承了type类的类才是自定义的元类
    pass


class Dog(object, metaclass=Mymeta):

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def say(self):
        print('%s says wang' % self.name)

1、先拿到一个类名:"Dog"
2、然后拿到类的父类:(object,)
3、再运行类体代码,将产生的名字放到名称空间中{...}
4、调用元类(传入类的三大要素:类名、基类、类的名称空间)得到一个元类的对象,然后将元类的对象赋值给变量名Dog,Dog就是我们用class自定义的那个类
Dog= Mymeta("Dog",(object,),{...})

五:自定义元类来控制Dog类的产生

import re


class Mymeta(type):  # 只有继承了type类的类才是自定义的元类
    def __init__(self, class_name, class_bases, class_dic):
        # print(self)  # 类<class '__main__.OldboyTeacher'>
        # print(class_name)
        # print(class_bases)
        # print(class_dic)

        if not re.match("[A-Z]", class_name):
            raise BaseException("类名必须用驼峰体")

        if len(class_bases) == 0:
            raise BaseException("至少继承一个父类")

        # print("文档注释:",class_dic.get('__doc__'))
        doc=class_dic.get('__doc__')

        if not (doc and len(doc.strip()) > 0):
            raise BaseException("必须要有文件注释,并且注释内容不为空")

# Dog= Mymeta("Dog",(object,),{...})
class Dog(object,metaclass=Mymeta):
    """
    adsaf
    """

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def say(self):
        print('%s says wang!' % self.name)

六:自定义元类来控制Dog类的调用

import re


class Mymeta(type):  # 只有继承了type类的类才是自定义的元类
    def __init__(self, class_name, class_bases, class_dic):
        # print(self)  # 类<class '__main__.OldboyTeacher'>
        # print(class_name)
        # print(class_bases)
        # print(class_dic)

        if not re.match("[A-Z]", class_name):
            raise BaseException("类名必须用驼峰体")

        if len(class_bases) == 0:
            raise BaseException("至少继承一个父类")

        # print("文档注释:",class_dic.get('__doc__'))
        doc = class_dic.get('__doc__')

        if not (doc and len(doc.strip()) > 0):
            raise BaseException("必须要有文件注释,并且注释内容不为空")

    # res = Dog('wangcai',2)
    def __call__(self, *args, **kwargs):
        # 1、先创建一个Dog的空对象
        dog_obj = object.__new__(self)
        # 2、调用Dog类内的__init__函数,然后将Dog的空对象连同括号内的参数的参数一同传给__init__
        self.__init__(dog_obj, *args, **kwargs)
        dog_obj.__dict__ = {"_%s__%s" %(self.__name__,k): v for k, v in dog_obj.__dict__.items()}

        # 3、将初始化好的Dog对象赋值给变量名res
        return dog_obj


# Dog= Mymeta("Dog",(object,),{...})
class Dog(object, metaclass=Mymeta):
    """
    adsaf
    """

    def __init__(self, name, age):
        self.name = name  # dog_obj.name='wangcai'
        self.age = age  # dog_obj.age=2

    def say(self):
        print('%s says wang!' % self.name)


res = Dog('wangcai', 2)
print(res.__dict__)
# print(res.name)
# print(res.age)
# print(res.say)

调用Dog类做的事情:

  1. 先创建一个dog的空对象
  2. 调用Dog类内的__init__方法,然后将Dog的空对象连同括号内的参数的参数一同传给__init__
  3. 将初始化好的dog对象赋值给变量名res

七:单例模式

实现方式1:classmethod
import settings


class MySQL:
    __instance = None

    def __init__(self, ip, port):
        self.ip = ip
        self.port = port

    @classmethod
    def singleton(cls):
        if cls.__instance:
            return cls.__instance
        cls.__instance = cls(settings.IP, settings.PORT)
        return cls.__instance


# obj1=MySQL("1.1.1.1",3306)
# obj2=MySQL("1.1.1.2",3306)
# print(obj1)
# print(obj2)


obj3 = MySQL.singleton()
print(obj3)

obj4 = MySQL.singleton()
print(obj4)
方式2:元类
import settings


class Mymeta(type):
    __instance = None
    def __init__(self,class_name,class_bases,class_dic):
        self.__instance=object.__new__(self)  # Mysql类的对象
        self.__init__(self.__instance,settings.IP,settings.PORT)

    def __call__(self, *args, **kwargs):
        if args or kwargs:
            obj = object.__new__(self)
            self.__init__(obj, *args, **kwargs)
            return obj
        else:
            return self.__instance

# MySQL=Mymeta(...)
class MySQL(metaclass=Mymeta):
    def __init__(self, ip, port):
        self.ip = ip
        self.port = port


# obj1 = MySQL("1.1.1.1", 3306)
# obj2 = MySQL("1.1.1.2", 3306)
# print(obj1)
# print(obj2)

obj3 = MySQL()
obj4 = MySQL()

print(obj3 is obj4)
方式3:装饰器
import settings

def outter(func):  # func = MySQl类的内存地址
    _instance = func(settings.IP,settings.PORT)
    def wrapper(*args,**kwargs):
        if args or kwargs:
            res=func(*args,**kwargs)
            return res
        else:
            return _instance
    return wrapper

@outter  # MySQL=outter(MySQl类的内存地址)  # MySQL=》wrapper
class MySQL:
    def __init__(self, ip, port):
        self.ip = ip
        self.port = port


# obj1 = MySQL("1.1.1.1", 3306)
# obj2 = MySQL("1.1.1.2", 3306)
# print(obj1)
# print(obj2)

obj3 = MySQL()
obj4 = MySQL()
print(obj3 is obj4)

相关文章

  • day34-元类

    一、什么是元类 python中一切皆对象,我们可以定义一个类,那么这个类也是一个对象,对象是实例化类得到的,所以类...

  • 3.isa

    isa指向 ->实例isa -> 类|类isa -> 元类 | 元类isa -> 根元类|根元类isa -> 根元...

  • Python元类

    元类 元类就是用来创建类的,元类就是类的类。 实例 关于type()函数的使用戳这里 元类为一个函数 元类为一个类

  • isa 和 superclass

    实例对象的 isa 指向类对象,类对象的 isa 指向元类对象,元类的isa 指向基类的元类对象,基类的元类对象的...

  • 友元类和嵌套类

    友元类 友元函数用于类的扩展接口中,类并非只能拥有友元函数,也可以将类作为友元,该类称为友元类。 友元类的所有方法...

  • 29.Python之面向对象的元类

    Python之面向对象的元类 什么是元类?类的类就是元类,元类创建对象。使用class定义的类,用来产生程序员自己...

  • 面向对象 六

    目录 1.元类 1.1 类创建过程 1.2 元类控制类的创建 1.3 元类控制类的创建过程案例 1.4 自定义元...

  • Python 元类

    什么是元类?元类就是创建类的类,type是最原始的一个元类。(实例是实例化的类,而类是元类的实例)python中一...

  • isa

    NSObject的父类为nil NSObject的isa为根元类 元类的isa都为根元类 根元类的isa为本身 根...

  • iOS开发中方法查找流程图

    实例对象的isa指针指向类对象,类对象的isa指针指向元类,元类的isa指针指向根元类,根元类的isa指针指向自己...

网友评论

      本文标题:day34-元类

      本文链接:https://www.haomeiwen.com/subject/tmxkjktx.html