Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/356.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何为所有调用覆盖导入的python类_Python_Class - Fatal编程技术网

如何为所有调用覆盖导入的python类

如何为所有调用覆盖导入的python类,python,class,Python,Class,我创建了一个python包/MyLibPackage,我将在我的项目中导入它 MyLibPackage.\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。此外,MyLibPackage文件夹还包含另一个文件:base_classes.py(=外部项目) MyModification.py导入“自基本类导入*” 目标: 我可以导入MyLibPackage,它包含来自基本类(=外部项目

我创建了一个python包/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
将失败。你有