Python:如何编写补丁(swap)类

Jam*_*Lin 6 python

假设我在模块中有以下2个类 a

class Real(object):
    ...
    def print_stuff(self):
        print 'real'

class Fake(Real):
    def print_stff(self):
        print 'fake'
Run Code Online (Sandbox Code Playgroud)

在模块中b它使用Real该类

from a import Real
Real().print_stuff()
Run Code Online (Sandbox Code Playgroud)

如何修补补丁,以便在b导入Real时实际与它交换Fake

我试图在初始化脚本中这样做,但它不起作用.

if env == 'dev':
    from a import Real, Fake
    Real = Fake 
Run Code Online (Sandbox Code Playgroud)

我的目的是在开发模式下使用Fake类.

Ana*_*mar 2

问题是当你这样做时 -

from a import Real, Fake
Run Code Online (Sandbox Code Playgroud)

您基本上是将这两个类导入到initialize脚本的命名空间中,并在脚本的命名空间中创建RealFake命名initializeReal然后,您使脚本中的名称initialize指向Fake,但这不会改变实际a模块中的任何内容。

如果initialize脚本是.py在原始程序开始时运行的另一个模块/脚本,那么您可以使用以下命令 -

if env == 'dev':
    import a
    a.Real = a.Fake
Run Code Online (Sandbox Code Playgroud)

请注意,在执行上述行后,每当您使用from module 时,这都会a.Real引用该类。FakeReala


虽然我建议更好的方法是在模块本身中执行此操作a,通过使检查该模块成为可能env,如 -

if <someothermodule>.env == 'dev':
    Real = Fake
Run Code Online (Sandbox Code Playgroud)

正如评论中所问的那样 -

不导入也导入到初始化脚本的命名空间中吗?导入模块和类有什么区别?

问题是,当您仅使用 导入类时from a import class,您实际上所做的是class在您的模块命名空间中(在您将其导入到的模块中)创建该变量,将该变量更改为指向该模块命名空间中的新内容并不会影响其原始模块对象中的原始类,仅在其更改的模块中受到影响。

但是当你这样做时import a,你只是导入模块a(并且在导入模块对象时也会缓存在字典中sys.modules,因此任何a其他模块的任何其他导入都将从中获取此缓存版本sys.modules)(另一个注意点是,这from a import something也是内部导入的a并将其缓存在 中sys.modules,但我们不要讨论这些细节,因为我认为这里没有必要)。

然后,当您这样做时a.Real = <something>,您正在更改指向该类的模块对象Real的属性,这会直接改变模块,因此当模块从其他模块导入时,更改也会反映出来。aaa