赞
踩
学习python时,对 meta class 并不陌生,django 的model, form定义中经常会遇到class Meta 的代码, 但 django中没有介绍模型与表单中的 meta 属性是怎么回事。 python的众多教程,也很少有作者提到,或把meta class 讲清楚,造成大家以为metaclass 很难理解。 今天我尝试用实例代码的方式,让metaclass 更容易理解与使用。
# django model类可以配置 Meta 类的属性
class Person(models.Model):
......
class Meta:
verbose_name = "人员信息"
db_table = "tbl_person"
Python与Java 一样,宣称自己一切皆对象,且有过之而不及。python的数据类型是类对象,甚至函数本身也是对象。 Python object 是所有类型的基类,各种数据类型、函数、class 都是object 的派生类,因此,从object的概念上推理: 存在某些类,可以生成其它类, 这种类就称为meta class
., 也称元类。
开始之前,我们先看1个经典的问题, 以下的代码的执行结果是什么?
>>> isinstance(type, object)
>>> isinstance(object, type)
>>> isinstance(object, object)
>>> isinstance(type, type)
答案:True
,True
,True
,True
在 Python 中,一切皆对象,所以任何对于 object
的实例检查都会返回 True
:isinstance(任何东西, object)
=> True
。
而 isinstance(object, type)
也返回 True
, 表明 type又是object的父类。
type
就是一个元类,用于构造所有的 Python 类型。因此所有的类型,无论是 int
、str
或是 object
,都是 type
类的实例,同时也是对象。
type
还有一个独一无二的特性:它是自身类的实例。
>>> type(5)
<class 'int'>
>>> type(int)
<class 'type'>
>>> type(type)
<class 'type'>
本文将讨论 meta class的定义,以及使用方式。 内容共包含3个主题:
1个 class 也是1个object, 其包含若干属性,以及一些方法。如何用type()方法来实现呢?
type() 方法有两个使用方式
(1) type(x) 返回 x 的类型,
(2) type(cls_name, bases, dict) , 返回1个新类
第(1)种用法就不多说了。 下面使用第(2)种用法来创建一个class对象, 需要传入3个参数:
__init__
上。。下面演示如何用type创建1个新类。 首先,先用标准的方式,class关键字来创建1个 Food 类。
class Food(object):
def __init__(self, food):
self.food = food
def get_food(self):
return self.food
def main():
myfood = Food(food='蛋炒饭')
print(myfood.get_food())
main()
output
蛋炒饭
下面用 type来创建1个Food 类
def init(self, food): self.food = food def get_food(self): return self.food Food = type("Food", (object,), { '__init__': init, 'get_food': get_food, }) myfood = Food(food="蛋炒饭") print(myfood.get_food())
output:
蛋炒饭
通过type()
函数创建的类和直接写class是完全一样的,因为Python解释器遇到class定义时,仅仅是扫描一下class定义的语法,然后调用type()
函数创建出class
用 type来增加1个子类VegFood, 其父类为Food
def init(self, food): self.food = food def get_food(self): return self.food Food = type("Food", (object,), { '__init__': init, 'get_food': get_food, }) def get_vegfood(self): return {'清炒菠菜', '干煸豆角'} # 新建子类,父类为Food VegFood = type("VegFood", (Food,), { "get_vegfood": get_vegfood, }) veg = VegFood(food="蛋炒饭") print(veg.get_food()) print(veg.get_vegfood())
output:
蛋炒饭
{'干煸豆角', '清炒菠菜'}
可以看到,子类 VegFood可以继承 父类Food的方法get_food(),也可以使用子类的方法 get_vegfood()
metaclass,直译为元类,继承自type. 因此,如前一节的示例, metaclass 也可以用来创建类。
用metaclass来创建类过程:先定义metaclass,然后创建类,最后创建实例。
所以,metaclass允许你创建类或者修改类。换句话说,你可以把类看成是metaclass创建出来的“实例”。
metaclass的定义过程,主要是实现 __new__
方法,有4个传入参数, 与 type创建类的参数相似
metaclass还可以实现1个 __call__
方法,在该类被调用时执行此方法。
metacalss 示例 :
class MetaCls(type): """metaclass的示例""" def __new__(cls, clsname, superclasses, attributedict): print("clsname:", clsname) print("superclasses:", superclasses) print("attrdict:", attributedict) return super(MetaCls, cls).__new__(cls, clsname, superclasses, attributedict) def demo(self): print("Info from demo method") # generate a class, Example Example = MetaCls('Example', (object, ), {"demo": demo, }) Example.clsname = "ExampleClass" # 修改 metaclass的属性值 print("class type:", type(Example)) myexample = Example() # 新建1个Example的实例对象 print(myexample.clsname) # 打印父类属性值 myexample.demo() # 打印子类方法
output
clsname: Example
superclasses: (<class 'object'>,)
attrdict: {'demo': <function demo at 0x00000169DF2CC280>}
class type: <class '__main__.MetaCls'>
ExampleClass
Info from demo method
从上例 可以看到, Example类的生成方式,就是 MetaCls类的实例 化过程,example可以添加自己的方法,可以修改从父类继承的属性。
实际开发中遇到的metaclass是django中定义model, form时,可以定义metaclass的属性,其实就是django的ORM使用了 metaclass的编程方式,由于其实现较复杂,就不深入讨论。
这里我们来看1个更简单,而且非常实用的metaclass的例子: 用metaclass实现单例模式。
单例模式提供了这样一个机制,即确保类有且只有一个特定类型的对象,并提供全局 访问点。因此,单例模式通常用于下列情形,例如日志记录或数据库操作、打印机后台处 理程序,以及其他程序—该程序运行过程中只能生成一个实例,以避免对同一资源产生 相互冲突的请求。
class SingletonMeta(type): _instances = {} def __call__(cls, *args, **kwargs): if cls not in cls._instances: cls._instances[cls] = super( SingletonMeta, cls).__call__(*args, **kwargs) return cls._instances[cls] class SingletonClass(metaclass=SingletonMeta): _name = '' _age = 20 def greet(self, name): self._name = name print("hello ",self._name) def set_age(self,age): self._age=age def get_age(self): return self._age s = SingletonClass() print("Object created", s) s.greet("Jack") s.set_age(25) s1 = SingletonClass() print("Object created", s1) s1.greet("Peter") print(s1.get_age())
output :
Object created <__main__.SingletonClass object at 0x000001685344DC40>
hello Jack
Object created <__main__.SingletonClass object at 0x000001685344DC40>
hello Peter
25
可以看到,SingletonMeta用metaclass的方法定义了1个单例类, SingletonClass继承自SingletonMeta, s 与 s1 虽然分别实例化,但内存中的地址都指向同1个SingletonClass对象,实现了单例化。
而且metaclass实现单例模式,比 object方式实现的单例化有明显的优势,任何类都可以通过继承SingletonMeta实现单例模式, 是不是很酷.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。