在Python中重新加载模块后进行对象类型转换?【用于动态代码更改】

4 投票
2 回答
569 浏览
提问于 2025-04-17 12:27

我正在运行一个交互式的Python会话,这个会话会构建很大的数据结构(超过5GB),加载这些数据结构需要很长时间。因此,我想充分利用Python动态修改代码的能力(虽然有时候我并不想太过计划)。

我现在面临的问题是:我有一个旧的类实例,后来我修改了代码并重新加载了模块——我希望这个旧的实例能够使用新的函数定义。我该怎么做,而不是手动把旧实例的所有信息复制到一个新的实例中呢?

下面是我尝试过的内容。假设我有一个模块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 )

2 个回答

0

因为你不能直接转换类型,所以你需要调整你的代码,让这些神秘的“即时代码修改”能够正常工作。

第一步:将算法和数据分开。你需要写一个非常简单(而且不太可能改变)的类来处理原始数据。通常,一个命名元组的列表就足够用了。

第二步:创建一些算法,这些算法在数据对象上“包装”它们,而不是“更新”它们。

像这样。

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 就不会被改变。实际上,它可以是不可变的。

6

在Python中没有“类型转换”这个概念,但你可以改变一个已有对象的类。这是完全合法的,而且能达到目的:

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

只要你没有改变类的方法和实例变量之间的关系,也没有改动__init__方法的功能,或者类似的事情,这样做是没问题的。

补充说明:正如jsbueno所提到的,当你改变__class__的时候,__init____new__方法并不会被调用。此外,新的__del__方法会在对象被销毁时被调用。

撰写回答