如何在python中扩展内置类

时间:2017-03-18 03:13:17

标签: python class monkeypatching cpython

我正在使用micro-python为esp8266微控制器编写一些代码,它有一些不同的类以及标准内置类中的一些其他方法。为了允许我在我的桌面上调试,我已经构建了一些帮助程序类,以便代码运行。然而,我遇到了一个微型时间函数的障碍,它具有time.sleep_ms方法,因为在micropython上的标准time.sleep方法不接受浮点数。我尝试使用以下代码来扩展内置时间类,但无法正确导入。有什么想法吗?

class time(time):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def sleep_ms(self, ms):
        super().sleep(ms/1000)

此代码存在于文件time.py中。其次,我知道我必须导入我想修复的time.time问题。我也意识到我可以把它称为其他东西并在我的微控制器代码中设置陷阱但是我想避免在加载到控制器中的任何特殊功能以节省空间和周期。

1 个答案:

答案 0 :(得分:0)

你并没有试图覆盖一个类,而是试图对一个模块进行修补。

首先,如果您的模块名为time.py,则永远不会优先加载内置的time模块。真正内置(如编译到解释器核心,而不仅仅是CPython附带的C扩展模块)模块是特殊的,they are always loaded without checking sys.path,所以你甚至不能试图遮蔽time模块,即使你想(你通常不做,这样做非常难看)。在这种情况下,内置的time模块会影响您;您根本无法以简单名称time导入模块,因为内置资源甚至不会查看sys.path

其次,假设您使用不同的名称并将其导入仅用于猴子修补时间(或做一些可怕的事情,例如将猴子补丁添加到custom sitecustomize module),这不是一件容易的事情。猴子修补模块真正原生的功能(以任何正常方式定义它给它定义模块的范围,与time模块中的其他功能不同)。如果你不&# 39;不需要将它真正定义为time的一部分,最简单的方法就是:

import time

def sleep_ms(ms):
    return time.sleep(ms / 1000)

time.sleep_ms = sleep_ms

当然,如上所述,sleep_ms仍然是您模块的一部分,并且随身携带您的模块范围(这就是您time.sleep的原因,而不仅仅是sleep from time import sleep;您可以执行time.sleep以避免对其进行限定,但如果其他人在稍后修补time.sleep,那么它仍然是可能与time不匹配的本地别名)。

如果你想使它的行为类似于time模块的一部分,那么你可以在没有限定条件的情况下引用time命名空间中的任意内容,并始终看到eval中的当前函数,您需要使用time来编译import time # Compile a string of the function's source to a code object that's not # attached to any scope at all # The filename argument is garbage, it's just for exception traceback # reporting and the like code = compile('def sleep_ms(ms): sleep(ms / 1000)', 'time.py', 'exec') # eval the compiled code with a scope of the globals of the time module # which both binds it to the time module's scope, and inserts the newly # defined function directly into the time module's globals without # defining it in your own module at all eval(code, vars(time)) del code, time # May as well leave your monkey-patch module completely empty 范围内的代码:

SQLiteDatabase db = this.getReadableDatabase();   
if(DatabaseUtils.queryNumEntries(db, TABLE_PRODUCTS) == 5){ 
   ContentValues values = new ContentValues(); 
   values.put(COLUMN_PRODUCTNAME, product.get_productname()); 
   db.insert(TABLE_PRODUCTS, null, values); db.close(); 
 }