Python元编程被称为“黑魔法”。Python界的传奇人物Tim Peters有云:

引用

Python的元编程这种黑魔法99%的人都无需了解,如果你拿不准是否应该用到它时,你不需要它.

OpenERP基本遵循了Tim Peters的教诲,但是却在6.1版本之后忍不住触及了一点点,从此游走于黑白两道之间:)

其实OpenERP中用到的元类(MetaClass)作用非常简单:就是在V6.1后我们在模块中所定义的实体类,不需要进行实例化,比如

OpenERPV6.1之前的实体类定义:

程序代码: [选择]

Class MyProduct(osv.osv):     _inherit="product.product"     pass

MyProduct()

在OpenERPV6.1之后则不需要上面的类的实例化过程了。即,不需要下面这句了:

程序代码: [选择]

MyProduct()

为了了解元类如何实现取消实例化过程,首先我们来看一下OpenERP中实体类的实例化过程到底做了些什么。

我们一般知道,Python类的调用或称为实例化,会生成该类的一个实例对象(instance object),比如:

程序代码: [选择]

class A(object):    ...:     def __init__(self, x):    ...:         self.x = x    ...:          In [2]: a = A(2)

In [3]: a

Technorati 标签:

Openerp,

Python,

元编程

Out[3]: <__main__.a at>

a就是类A的一个实例对象。这是Python的基础知识,很好理解。但是,我要告诉你的是:在OpenERP中,MyProduct()并不产生MyProduct类的实例,甚至再深究的话,我们经常在代码中用到的pool.get('product.product')从对象池中获取的实例对象,也非这个MyProduct类所生成的实例。

这到底是怎么一回事?我们首先要了解什么是类的实例化,或者类的调用到底是怎样的一个过程,比如上例中A(2),其实其执行过程基本上可以分为两个部分,用Python 来表示就是:

程序代码: [选择]

n = A.__new__(A, 2)      #创建类的实例对象

if isinstance(n, A): A.__init__(n, 2)     #实例对象初始化

类A本身并没有定义__new__类方法,所以直接调用其父类即:object的__new__方法获得实例对象,如果获得的对象是A的实例则执行__init__方法

同样的,Myproduct所继承的osv.osv类(或OE6.1以后称为BaseModel)就有一个__new__方法,而这个方法返回的是None,所以按照上面的说明它都不会运行到实例初始化的部分,当然也就无法获得Myproduct的实例。

如果我们仔细分析代码,发现这个__new__的主要作用基本上就是下面这点代码:

程序代码: [选择]

module_model_list = MetaModel.module_to_models.setdefault(cls._module, [])         if cls not in module_model_list:             if not cls._custom:                 module_model_list.append(cls)

其实MetaModel是一个元类(metaclass)等会儿要讲到,module_to_models则是这个类上的一个变量,其对应一个字典,字典的key对应每一个“模块”就是OpenERP的addons,其值对应这个模块中所定义的实体类(比如我们上例中的MyProduct)

所以调用实体类并没有实例化,只是就这样登记备案了一下,事实上只有在模块载入(loading)过程中才会对所注册的实体类实例化,其实也不是一般意义的实例化,而是要另外创造一个新类,再做实例化。(这部分以后有空再介绍)

那么问题回到原点,OpenERPV6.1以后如何做到,不调用实体类,即不运行BaseModel上的__new__方法就可以做到上述的类的注册过程。把OpenERP变色的那一点黑,这就出现了。对,就是那个叫MetaModel的家伙。在介绍MetaModel之前我们先快速的讲解一下Python的metaclass。

在Python中一切皆为“对象”, 类的实例是对象,类本身也是对象。类的实例对象是通过对类的调用获得的,那么类本身这个对象又是如何获得的呢?

其实上面的例子中类A的定义可以改写为:

程序代码: [选择]

A = type('A', (object,), {'__init__': lambda self,x: self.x=x})

从上面的代码可以看出类A是通过调用type,或者是通过对type的实例化来获得的,事实上默认情况下所有的类都是由type实例化获得,这个type类就是所生成类的元类。

类的实例对象可以对应五花八门我们定义的各种类,同理,我们是否可以定义除type以外用来生成类对象的五花八门的元类呢?答案当然是肯定的。看看我们的MetaModel:

程序代码: [选择]

class MetaModel(type):     ....

它与我们的普通的类定义没有什么差别,唯一需要注意的是其继承的父类是‘type',

而在OpenERP所有的实体类的基类BaseModel的类定义中有这么一句:

程序代码: [选择]

__metaclass__ = MetaModel

这句有特殊的含义,表示该类对象将由元类MetaModel实例化生成。在Python3.x中则用如下的语法:

程序代码: [选择]

Class MyProduct(metaclass=MetaModel, osv.osv)

还记得上面提到的类的实例化,__new__, __init__两步,元类的实例化也是一样。

我们看到MetaModel的__init__方法与上面提到的BaseModel类的__new__方法中有完全类似的代码:

程序代码: [选择]

if not self._custom:             self.module_to_models.setdefault(self._module, []).append(self)

就是做了一个注册备案的动作。所以类对象本身产生的过程就已经注册了类,可以不用和6.0及以前版本的OpenERP每次定义实体类都要调用一下了。

« 最后编辑时间: 二月 25, 2013, 07:02:00 下午 作者 digitalsatori »

OpenERP高级实施顾问

上海先安科技 (http://cn.openerp.cn)

tony AT openerp.cn

021 50323731

python函数myproduct_OpenERP与Python 元编程相关推荐

  1. python小老鼠编程_成都python函数学习教程,Python编写课程

    1.urllib2/urllib实现urllib2和urllib是Python中的两个内置模块,要实现HTTP功能,实现方式是以urllib2为主,urllib为辅.1.1首先实现一个完整的请求与响应 ...

  2. shell调用python函数_shell调用python函数

    最近遇到一个需求,需要通过shell调用python中的一个函数,发现其实也挺简单的: python脚本如下: test.py: import ConfigParser config = Config ...

  3. python函数模块_06.Python函数和模块

    函数基础 目标 函数的快速体验 函数的基本使用 函数的参数 函数的返回值 函数的嵌套调用 在模块中定义函数 函数的快速体验 1.1 快速体验 所谓函数,就是把 具有独立功能的代码块 组织为一个小模块, ...

  4. python函数转换_将Python函数转换为PL/Python函数

    我编写了几个python函数来对数据集中的连续变量进行幂变换.第一个函数基本上查找每个列的数据类型,并返回数据类型的dict以及相应的列名称作为值.在 第二个函数现在接受数据类型和列名的dict,并获 ...

  5. python函数库_ctypes --- Python 的外部函数库 — Python 3.9.0 文档

    加载动态链接库¶ 有很多方式可以将动态链接库加载到 Python 进程.其中之一是实例化以下类的其中一个: classctypes.CDLL(name, mode=DEFAULT_MODE, hand ...

  6. c调用python函数_C调用Python的函数

    1 /*2 module: Python脚步的模块名3 function: 要调用的函数名4 format: 传递给Py_VaBuildValue函数的可变参数模板5 */6 intPyCall(co ...

  7. python函数映射教学,Python 序列与映射的解包操作

    解包就是把序列或映射中每个元素单独提取出来,序列解包的一种简单用法就是把首个或前几个元素与后面几个元素分别提取出来,例如: first, seconde, *rest = sequence 如果seq ...

  8. c#调用python函数_C#调用python脚本的方法步骤(2种)

    因项目需要,需要使用C#控制台程序执行python脚本,查询各种资料后可以成功调用了,记录一下,以备后面遗忘. 只尝试了两种调用方式,第一种只适用于python脚本中不包含第三方模块的情况,第二种针对 ...

  9. python函数代码,这个python函数代码如何工作?

    这个with_default_value函数经常被称为(不精确地)为"闭包"(技术上,闭包是返回的内部函数,这里是newfunc – 参见例如 here).更一般地说,with_d ...

最新文章

  1. 想法:javac:源版本1.7需要目标版本1.7
  2. python实现一种检测postgresql数据库是否已经连接且为主节点的办法
  3. 小样本不符合正态_金莎相亲对象不符合择偶标准,男生单眼皮小眼睛,但她还是沦陷了...
  4. 数据算法之二叉树平衡(BinTreeNode Rotate)的Java实现
  5. java JDK11对比JDK8
  6. 最优化算法之粒子群算法(PSO)
  7. python步态识别算法_步态识别
  8. 陈一为担任BCF理事
  9. This request has been blocked; the content must be served over HTTPS.
  10. hdu-2191悼念512汶川大地震遇难同胞——珍惜现在,感恩生活 HDU - 2191(多重背包)
  11. ubuntu mysql无法启动服务器_ubuntu – Mysql无法启动mysqld.sock缺失
  12. 用户调查显示,Rust语言很难学习和使用
  13. 在C ++中将二进制转换为十进制
  14. 《炬丰科技-半导体工艺》半导体封装中金丝键合技术
  15. ios录音文件路径_iOS中录音功能
  16. 中国自媒体行业竞争格局与运营盈利模式分析报告2022年
  17. 关于印发《黑龙江省农村土地承包经营权确权登记试点工作操作规程(试行)》的通知
  18. Python/练习题
  19. delphi7微信支付宝支付单机版前台源码
  20. 2018 OpenInfra Days China大咖来袭——开源,我们是认真的

热门文章

  1. 字典、集合与字符串——Python基础语法
  2. c语言倒计时不影响进程_初学C语言没有项目练手怎么行,这17个小项目收下不谢...
  3. 通俗易懂的Monte Carlo的积分方法(三)
  4. html如何添加时钟效果,基于HTML5+CSS3实现简单的时钟效果
  5. 计算机硬件课题,计算机硬件技术基础免试课题.pptx
  6. java亚马逊模拟登录_java – 亚马逊MWS入门
  7. java获取classes_一个Java项目布署到weblogic里,听说weblogic会把classes目录打成jar包,怎么获取classes里文件的路径...
  8. react多个网络请求_react中网络请求的优化!
  9. GO语言学习之路10
  10. [记录] Ubuntu 配置Apache虚拟站点