如何为所有调用覆盖导入的python类
我创建了一个python包/MyLibPackage,我将在我的项目中导入它如何为所有调用覆盖导入的python类,python,class,Python,Class,我创建了一个python包/MyLibPackage,我将在我的项目中导入它 MyLibPackage.\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。此外,MyLibPackage文件夹还包含另一个文件:base_classes.py(=外部项目) MyModification.py导入“自基本类导入*” 目标: 我可以导入MyLibPackage,它包含来自基本类(=外部项目
MyLibPackage.\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。此外,MyLibPackage文件夹还包含另一个文件:base_classes.py(=外部项目)
MyModification.py导入“自基本类导入*
”
目标:
我可以导入MyLibPackage,它包含来自基本类(=外部项目)的所有类。
如果我需要修改某些类或函数,我可以在mymodification.py中覆盖它。它能工作,但我有个问题。例如:
我在MyModification.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”。好!!
但如果我愿意这样做:
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.MyModification.Bookcollection的实例
我怎么说:如果我在MyModification中覆盖了一个类,那么MyLibPackage必须使用它,尽管调用来自MyLibPackage.base_classes.shelf(get_books)。由于名称空间冲突,使用相同名称的类通常是个坏主意。我建议将您的MyLibPackage.base\u classes.Bookcollection
更改为MyLibPackage.base\u classes.BaseBookcollection
或类似版本。这应该会像预期的那样起作用。您想要做的是所谓的“猴子补丁”,与对象定向几乎没有关系
Python确实支持它,但是您可以控制所有的类,您应该认真地检查您的项目,以检查您是否真的需要它
也许使用像Zope组件体系结构这样的框架会是一个更好的主意,它允许您用接口标记类,并提供适配器对象,以便您可以干净地使用一个对象,因为它具有一些最初设计不具备的接口
也就是说,您要求的是在其他模块中更改类,在它所在的位置-以便所有其他模块都可以看到这些更改
您只需要这样做:在它所属的模块中更改类。在Python中,只需将新类赋给源模块中所需的名称即可:
import base_classes
class Bookcollection(base_classes.Bookcollection):
new_member = "lalala"
base_classes.Bookcollection = Bookcollection
(要使这类事情起作用,您必须避免在任何大于单个脚本的项目中使用“from x import*”——在本例中,您有两个名称相同、在整个代码中含义不同的变量:例如,基类和继承类。Python命名空间允许您避免这种情况)
因此,这将更改base_class模块中的Bookcollection类-但仅适用于从这一点以及执行链上引用它的代码。如果示例中的“x”类是在“base_classes”模块中定义的,或者是在导入“MyModule”之前定义的,那么它将获得对旧“Bookcollection”类的引用
如您所见,它很快就会变得一团糟,如果您真的选择了这种方法,那么保持项目可用性的唯一方法就是进行单元测试,以验证您想要修补的所有类实际上都已修补。正如您所看到的,即使模块的导入顺序也会有所不同。如果你有测试的地方,他们将打破如果你进口的顺序,打破你的猴子补丁
如果您只需要添加和替换现有类中的内容,您可以对该类本身进行猴子补丁以替换其组件,而不是对其所在的模块进行猴子补丁以替换该类。这样,模块的导入顺序就无关紧要了——它甚至会影响该类的现有实例:
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
这将使您的行为更加一致,而不是尝试将新类(其本身就是一个对象)分配给原始模块中的相同名称
总之,您应该按照@jamesj在其答案中的建议,使用不同的类,或者如果需要动态行为,则使用可维护的框架,如Zope组件体系结构。不管您采取什么方法,都要编写单元测试 如果你陷入继承链中,那么也许你应该看看其他的解决方案。也许我可以尝试使用钩子?!但是,当我只需要更改基类的某些部分时,它应该如何工作呢?对于exmaple函数。base_class.py的其余部分使用他的名称空间。其余基本类中的调用不知道我的新派生类OK,然后将派生类重命名为BookcollectionImproved或执行类似于从基本类导入Bookcollection作为BaseBookcollection的操作!谢谢你。解决了我的一个问题!我这样做是为了单元测试,但我想取消其他测试(一个测试更改模块使用的类,但另一个测试需要保留原始类)。您知道如何将其还原或使第二个测试导入原始类吗@EHAMBRIGHT如果我误解了您的答案,很抱歉,但是当我尝试执行datetime.datetime.\uu dict\uuu[“strtime”]=new\u strtime
时,我得到错误内容:“dictproxy”对象不支持项分配
。为了在datetime.datetime
中修补此strtime
方法,我的作业应该是什么样的?我对Python不太熟悉,只是试图解决现有标准库代码中一些长期存在的(缓存?)bug。我应该先调用datetime.datetime
来确保它被实例化,或者类似的东西吗?这个答案来自2012年-它是为Python 2编写的-在Python 3中,您不能直接在类dict中分配项-而是直接分配给属性。但是,datetime.datetime是用本机代码(内置扩展)编写的,因此,不能用这种方式覆盖其方法。也就是说:datetime.datetime.strtime=new\u strtime
将失败。你有