How to overwrite a imported python class for all calls

后端 未结 2 529
没有蜡笔的小新
没有蜡笔的小新 2021-02-04 08:29

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

MyLibPackage.____init____.py includes mymodiciation.py. Furthermore the MyLibPa

相关标签:
2条回答
  • 2021-02-04 08:53

    Having classes with the same name is generally a bad idea as you get namespace clashes. I would recommend changing your MyLibPackage.base_classes.Bookcollection to MyLibPackage.base_classes.BaseBookcollection or similar. This should then work as expected.

    0 讨论(0)
  • 2021-02-04 09:12

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

    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.

    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.

    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
    

    (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).

    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.

    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.

    0 讨论(0)
提交回复
热议问题