面向对象-元类

 http://www.cnblogs.com/linhaifeng/articles/8029564.html

类的类就为元类

元类所需知识

#exec()
#参数1:字符串形式的命令
#参数2:全局作用域(字典形式),不指定默认使用全局globals()
#参数3:局部作用域(字典形式),不指定默认使用局部locals()
g={'x':1,
   'y':2}
l={}
#把exec中代码当一个函数来看待
exec("""
global x,m
x=10
m=100
z=3""",g,l)
print(g)
print(l)

一切皆对象,对象可以怎么来用,共性?

  1. 都可以被应用,x=obj
  2. 都可以当函数的参数传入
  3. 都可以当函数的返回值
  4. 都可以当作容器类型的元素,如都可当列表的元素
#类也是一个对象
class Foo:
    pass
obj=Foo()
print(type(obj))
print(type(Foo))

  • 产生类的类称之为元类,默认所有用class定义的类,他们的元类是type

定义类的方式

#方式一定义类:
class Chinese:
    country='China'
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def talks(self):
        print("%s is talking" % self.name)

#方式二定义类:
#定义类的三要素
# 类名,类的基类,类的命名空间
class_name='Chinese'
class_base=(object,)
class_body="""
country='China'
def __init__(self,name,age):
    self.name=name
    self.age=age
def talks(self):
    print("%s is talking" % self.name)
"""
class_dic={}
exec(class_body,globals(),class_dic)
Chinese1=type(class_name,class_base,class_dic)
print(Chinese)
print(Chinese1)

自定义元类来控制类的创建

 自己写一个元类

#自定义一个元类,因需要使用类中的其他方法,所以自定义元类继承于type
class Mymeta(type):
    def __init__(self,class_name,class_bases,class_dic):
        print(class_name)#打印类名字
        print(class_bases)#打印类的基类
        print(class_dic)#打印类的名称空间
        super(Mymeta,self).__init__(class_name,class_bases,class_dic)#引用父类方法
#定义一个类,继承于自己定义的元类
class Chinese(object,metaclass=Mymeta):
    country='China'
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def talks(self):
        print("%s is talking" % self.name)

对元类进行控制,以达到自定义

#自定义元类,控制类的行为
class Mymeta(type):
    def __init__(self,class_name,class_bases,class_dic):
        #强制首字母大写
        if not class_name.istitle():
            raise TypeError("类名首字母必须大写")
        #强制写注释
        if '__doc__' not in class_dic or not class_dic['__doc__'].strip():
            raise TypeError("类必须有注释,且不为空")
        print(class_dic)
        super(Mymeta,self).__init__(class_name,class_bases,class_dic)#引用父类方法
#定义一个类,继承于自己定义的元类
class chinese(object,metaclass=Mymeta):
    country='China'
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def talks(self):
        print("%s is talking" % self.name)

#自定义元类,控制类的行为
class Mymeta(type):
    def __init__(self,class_name,class_bases,class_dic):
        #强制首字母大写
        if not class_name.istitle():
            raise TypeError("类名首字母必须大写")
        #强制写注释
        if '__doc__' not in class_dic or not class_dic['__doc__'].strip():
            raise TypeError("类必须有注释,且不为空")
        print(class_dic)
        super(Mymeta,self).__init__(class_name,class_bases,class_dic)#引用父类方法
#定义一个类,继承于自己定义的元类
class Chinese(object,metaclass=Mymeta):
    country='China'
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def talks(self):
        print("%s is talking" % self.name)

自定义元类控制类实例化行为

知识储备__call__()

#知识储备__call__方法
class Foo:
    def __call__(self, *args, **kwargs):
        print(self)
        print(args)
        print(kwargs)
obj=Foo()
obj(1,2,3,a=4,b=5)
View Code

Foo默认继承元类,那么元类中则有一个__call__方法,会在调用Foo时会触发

Foo(1,2,3)等同于Foo.__call__(Foo,1,2,3)

 自定义一个元类来控制类的实例化

#自定义元类,控制类的行为
class Mymeta(type):
    def __init__(self,class_name,class_bases,class_dic):
        #强制首字母大写
        if not class_name.istitle():
            raise TypeError("类名首字母必须大写")
        #强制写注释
        if '__doc__' not in class_dic or not class_dic['__doc__'].strip():
            raise TypeError("类必须有注释,且不为空")
        super(Mymeta,self).__init__(class_name,class_bases,class_dic)#引用父类方法
    def __call__(self, *args, **kwargs):
        #1、制造一个空对象obj
        obj=object.__new__(self)
        #2、初始化obj
        self.__init__(obj,*args,**kwargs)
        #3、返回obj
        return obj
#定义一个类,继承于自己定义的元类
class Chinese(object,metaclass=Mymeta):
    """中文人的类"""
    country='China'
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def talks(self):
        print("%s is talking" % self.name)
obj=Chinese('ya',18)#Chinese.__call__(Chinese,'ya,18)
print(obj.__dict__)
View Code

验证创建是否成功

自定义元类控制类的实例化应用

 单例模式

#单例模式,参数一样的对象就不要多次创建多次占用内存
class MySQL:
    def __init__(self):
        self.host='127.0.0.1'
        self.port=3306

obj1=MySQL()
obj2=MySQL()
obj3=MySQL()
print(obj1)
print(obj2)
print(obj3)
View Code

单例模式的实现

class MySQL:
    __instance=None
    def __init__(self):
        self.host='127.0.0.1'
        self.port=3306
    @classmethod
    def singleton(cls):
        if not cls.__instance:
            obj=cls()
            cls.__instance=obj
        return cls.__instance
    def conn(self):
        pass
    def execute(self):
        pass
obj1=MySQL.singleton()
obj2=MySQL.singleton()
obj3=MySQL.singleton()
print(obj1)
print(obj2)
print(obj3)
View Code

通过元类来实现单例模式

#元类实现单例模式
class Mymeta(type):
    def __init__(self,class_name,class_bases,class_dic):
        #强制首字母大写
        if not class_name.istitle():
            raise TypeError("类名首字母必须大写")
        #强制写注释
        if '__doc__' not in class_dic or not class_dic['__doc__'].strip():
            raise TypeError("类必须有注释,且不为空")
        super(Mymeta,self).__init__(class_name,class_bases,class_dic)#继承父类方法
        self.__instance=None
    def __call__(self, *args, **kwargs):
        if not self.__instance:
            obj=object.__new__(self)
            self.__init__(obj)
            self.__instance=obj
        return self.__instance
class Mysql(object,metaclass=Mymeta):
    """
    Mysql
    """
    def __init__(self):
        self.host='127.0.0.1'
        self.port=3306
    def conn(self):
        pass
    def execute(self):
        pass

obj1=Mysql()
obj2=Mysql()
obj3=Mysql()
print(obj1)
print(obj2)
print(obj3)
View Code

posted @ 2018-04-20 13:43  丫丫625202  阅读(141)  评论(0编辑  收藏  举报