如何为所有调用覆盖导入的python类 [英] How to overwrite a imported python class for all calls

查看:78
本文介绍了如何为所有调用覆盖导入的python类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个python-packages / MyLibPackage,将其导入到我的项目中。

I create a python-packages /MyLibPackage which I will import in my projects.

MyLibPackage .____ init ____。py 包含mymodiciation.py。此外,MyLibPackage文件夹包含另一个文件:base_classes.py(=外部项目)

MyLibPackage.____init____.py includes mymodiciation.py. Furthermore the MyLibPackage Folder contains another file :base_classes.py(=external project)

mymodiciation.py import from base_classes import *

mymodiciation.py imports "from base_classes import *".

目标:
我可以导入MyLibPackage,该库具有base_classes(= external project)中的所有类。
如果需要修改某些类或函数,可以在mymodiciation.py中覆盖它。它有效,但是我遇到了问题。例如:

Goal: I can import MyLibPackage which has all classes from base_classes (=external project). And if I have need to modifiy some classes or functions, I can overwrite this in mymodiciation.py. It works but I got a problem. For example:

我在mymodiciation.py中覆盖了此类:

I overwrite this classes in mymodiciation.py:

class Bookcollection(Bookcollection):
   new_member = "lalala"


class user(user):
   def get_books(self):
      return Bookcollection()

如果我这样做:

from MyLibPackage import *
x = user()
books = x.get_books()

,则对象Bookcollection具有属性 new_member。好!
但是,如果我愿意这样做:

then the object Bookcollection has the property "new_member". Good! But if i will do this:

from MyLibPackage import *
x = shelf() #this class is not overwritten and used also the object "Bookcolelction"
books = x.get_books()

然后对象Bookcollection不具有属性 new_member,因为他是使用MyLibPackage.base_classes.Bookcollection而不是我覆盖的类MyLibPackage.mymodiciation.Bookcollection实例的。

then the object Bookcollection has NOT the property "new_member" because he is instanced with MyLibPackage.base_classes.Bookcollection and not with my overwritten class MyLibPackage.mymodiciation.Bookcollection

如何我说:如果我在mymodiciation中覆盖了一个类,则尽管调用来自MyLibPackage.base_classes.shelf(get_books),但MyLibPackage必须使用该类。

How can I say: If I overwrite a class in mymodiciation then MyLibPackage has to use this although when the call cames from MyLibPackage.base_classes.shelf (get_books).

推荐答案

您要执行的操作称为猴子修补,与对象定向无关。

What you want to do is called "monkey patching", and has little to do with Object Orientation.

Python确实支持它,但是您有控制所有的类,您应该认真检查您的项目以检查是否确实需要它。

Python does support it, but you have control over all your classes, you should seriously review your project to check if you will really need it.

也许使用诸如Zope Component Archi之类的框架tecture,它可以让您用接口标记类,并提供适配器对象,以便您可以干净地使用一个对象,因为它具有最初设计时没有的某些接口。

Maybe using a framework like Zope Component Architecture, which allows you to mark classes with interfaces, and provides adapter objects so that you can cleanly use one object as having some interface it was not designed to have in first place, will be a better idea.

也就是说,您要更改的是在其他模块中的类所在的位置-以便所有其他模块都可以看到更改。

That said, what you are asking for is to change the class, in the other module, where it is - so that the changes are visible to all the other modules.

您可以这样做:在所属模块中更改类。在Python中,只需在来源模块中将新类分配给所需的名称即可完成

You do just that: change the class in the module where it belongs. In Python it can be done simply attributing your new class to the desired name, in the module of origin:

import base_classes

class Bookcollection(base_classes.Bookcollection):
   new_member = "lalala"

base_classes.Bookcollection = Bookcollection

(为了使类似的代码正常工作,在任何大于单个脚本的项目中都必须避免 from x import *-在这种情况下,您必须使用在整个代码中使用相同的名称和不同的含义:例如基类和继承的类。Python名称空间可以避免这种情况。)

(For things like this to work, you have to avoid "from x import *" in any project larger than single script - in this case you had 2 variables with the same name, and different meanings throughout your code:the base class, and the inherited class, for example. Python namespaces allow you to avoid that).

因此,更改base_class模块中的Bookcollection类-但仅适用于从现在起在您的执行链上将引用它的代码。如果您的示例中的 x类是在 base_classes模块中定义的,或者在导入 MyModule之前进行了定义,则它将获得对旧 Bookcollection类的引用。

So, this will change the Bookcollection class in the base_class module - BUT only for code that will reference it from this point and on on your execution chain. If the "x" class in your example,is defined in the "base_classes" module, or otherwise is defined before the "MyModule" is imported, it will get a reference to the old "Bookcollection" class.

如您所见,它很快就会变成一团糟,如果您真的选择这种方法,那么保持项目甚至可用的唯一方法就是进行单元测试。验证要修补的所有类均已实际修补。如您所见,甚至模块的导入顺序也会有所不同。如果您有测试的地方,那么如果您按破坏猴子补丁的顺序进行导入,它们就会破坏。

As you can see, it can quickly become a mess, and if you really choose this approach, the only way of keeping your project even usable, is to have unit tests to verify that all the classes that you want patched, are actually patched. Even the importing order of modules will make a difference, as you see. If you have tests place, they will break if you make imports in an order that breaks your monkey patching.

如果您只需要添加和替换现有类中的内容, ,您可以猴子修补类本身以替换其组件,而不是猴子修补其中用于替换类的模块。这样,模块的导入顺序就无关紧要-甚至会影响该类的现有实例:

If you just need to add and replace things in an existing class, you can monkey patch the class itself to replace its components, instead of monkey patching the module it is in to replace the class. This way, the import order of modules won't matter much -- it will affect even existing instances of that class:

 import base_classes

 base_classes.Bookcollection.new_member = "lalala"

 def new_bookcol_method(self):
      pass

 # to replace or register a method in the other class:
 base_classes.Bookcollection.__dict__["old_bookcol_method"] = new_bookcol_method

与为原始模块中的同一个名称分配一个新类(本身是一个对象)相比,这将给您更一致的行为。

This will give you a more consistent behaviour than trying to assign a new class (which is an object in itself) to the same name in the original module.

所有总之,您应该按照@jamesj的建议进行操作,并使用不同的类,或者,如果您需要动态的行为,请为此使用可维护的框架,例如Zope Component Architecture。无论采用哪种方法,都可以编写单元测试。

All in all, you should either do as @jamesj suggests in his answer, and use distinct classes, or if you need the dynamic behaviour, use a maintainable framework for that, like Zope Component Architecture. And whatever approach you take, do write unit tests.

这篇关于如何为所有调用覆盖导入的python类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆