重新加载模块后Python中的对象类型转换? [用于即时代码更改]

Posted

技术标签:

【中文标题】重新加载模块后Python中的对象类型转换? [用于即时代码更改]【英文标题】:object type casting in Python after reloading a module? [for on-the-fly code changes] 【发布时间】:2012-02-28 06:16:03 【问题描述】:

我正在运行一个交互式 python 会话,它构建 big python 数据结构(5+ GB),需要很长时间才能加载,所以我想利用 Python -fly 代码更改 能力最大化(尽管有时,不必为此做太多计划)。

我当前的问题如下:我有一个类的旧实例,后来我修改了代码并重新加载了模块——我希望旧实例能够使用新的函数定义。在不手动将所有信息从旧实例复制到新实例的情况下,如何做到这一点?

这是我尝试过的。假设我有模块M.py:

class A():
    def f(self):
        print "old class"

这是一个交互式会话:

import M
old_a = M.a()

# [suppose now I change the definition of M.A.f in the source file]

reload(M)
# I attempt to use the new class definition with the old instance:
M.A.f(old_a)

此时我从 Python 收到以下类型错误:

TypeError: unbound method f() must be called with A instance as first argument (got A instance instead)

Python 显然不乐意接收 A 的旧实例,即使它们在功能上基本上是等效的类型(在我的代码中)——有什么方法可以将它“类型转换”为新的实例类型,以便 Python 不会不抱怨?道德上的东西:M.A.f( (M.A) old_a ) ?

【问题讨论】:

你遇到的问题是你试图在一个类上调用一个对象方法。对于您想要的解决方案是获取模块功能,因为方法与对象相关联,因此当您重新加载模块时旧对象将保留旧方法 【参考方案1】:

Python 中没有强制转换,但您可以更改现有对象的类:这是完全合法的并且可以完成工作:

old_a.__class__=M.A
old_a.f()

只要您没有更改类方法和实例变量之间的关系,更改 __init__ 所做的或类似的事情就可以了。

编辑:正如jsbueno 指出的那样:__init____new__ 方法在更改__class__被调用。此外,新的__del__ 将在销毁时调用。

【讨论】:

这显然是所问问题的确切答案。只要记住__init____new__ 方法不会在__class__ 这样分配时运行(尽管__init__ 可以在需要时从提示中手动调用)。另外,应该提到的是,因为它在问题的措辞中,Python 中没有强制转换。 那么鉴于上述 cmets,我们是否可以说以下内容会有效地伪造 Python 中的类型转换:old_class = old_a.__class__old_a.__class__ = M.AM.A.f(old_a) # function which needed type castingold_a.__class__ = old_class @SimonLacoste-Julien 我会说不。例如,类型转换(如在 C++ 中)是完全不同的。例如,它可以生成完全不同类型的新对象。例如,想象一个复杂的对象,它有一个转换为const char * 的操作符,并带有一些内容的文本表示。所以 cast 在这个意义上更像 str(someObject)。【参考方案2】:

由于您无法投射,因此您需要修改您的代码,以便这些神秘的“即时代码更改”能够发挥作用。

步骤 1. 将算法与数据分离。为原始数据编写一个非常简单(并且不太可能更改)的类。通常,您只需要一个命名元组列表即可。

第 2 步。通过“包装”而不是“更新”它们来创建适用于数据对象的算法。

像这样。

def some_complex_algo( list_of_named_tuples ):
    for item in list_of_named_tuples:
        # some calculation
        yield NewTuple( result1, result2, ..., item )

现在您可以尝试处理:

result = list( some_complex_algo( source_data ) )

如果你不喜欢这个结果,你只需要重新定义你的some_complex_algo 并重新运行它。 source_data 保持不变。事实上,它可以是不可变的。

【讨论】:

感谢您的设计建议。但主要问题是这需要一些代码规划。我的问题的重点是,我希望能够修改一些东西即使我一开始并没有计划进行更改——这就是使用像 Python 这样的快速原型设计语言的重点恕我直言... 这需要没有代码规划。仅将数据与算法分开。就是这样。 “快速原型设计语言”并不是回避所有思考的借口,顺便说一句。在处理 5GB 文件时或多或少地随机编码并不是一个好主意。然而。如果没有计划,您可以编写处理不可变数据的代码,避免像强制转换这样的事情。 为了更好地了解上下文,我不是在读取 5 GB 的文件,而是在读取几个 200 MB 的文件,这些文件会产生 5 GB 以上的构建数据结构。大数据结构的重点是使某些算法的运行时执行效率更高(我基本上是在将知识库 IMDb 与 Wikipedia 对齐——这是试图匹配数百万个实体,你显然不能只看在所有对)。我怀疑我是否可以仅使用不可变数据有效地实现上述所有内容。 @SimonLacoste-Julien:所有函数式编程语言的人都会告诉你,你肯定可以使用可变集合中的不可变对象来完成所有这些工作。他们一直这样做。可变对象不是必需的。 “为了使某些算法的运行时执行效率更高”,您必须拥有正确的数据结构和正确的算法。可变性与此无关。正确使用映射和集合比可变性更重要。

以上是关于重新加载模块后Python中的对象类型转换? [用于即时代码更改]的主要内容,如果未能解决你的问题,请参考以下文章

从模块重新加载的 Python 递归函数

python对象保存和重新加载

脚本编译后如何在python中重新加载模块?

python如何重新加载模块

Python模块 实现过渡性模块重载

在 Python 中重新加载现实生活中的模块?