重新加载模块后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.A
、M.A.f(old_a) # function which needed type casting
和 old_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中的对象类型转换? [用于即时代码更改]的主要内容,如果未能解决你的问题,请参考以下文章