我创建Python-包/ MyLibPackage,我将在我的项目中导入。
MyLibPackage.____init____.py
包括mymodiciation.py。 此外,MyLibPackage文件夹包含另一个文件:base_classes.py(=外部项目)
mymodiciation.py进口“ from base_classes import *
”。
目标:我可以导入MyLibPackage其中有来自base_classes所有类(=外部项目)。 如果我有需要modifiy一些类或函数,我可以在mymodiciation.py覆盖此。 它的工作原理,但我有一个问题。 例如:
我在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”。 好! 但是,如果我将做到这一点:
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
我怎么能说:如果我在mymodiciation覆盖类,然后MyLibPackage必须使用这个,虽然当呼叫从MyLibPackage.base_classes.shelf(get_books)卡梅斯。
你想要做什么是所谓的“猴子补丁”,并没有什么用面向对象。
Python做支持它,但你必须在所有的类的控制,你必须认真检讨你的项目检查,如果你真的需要它。
也许使用如Zope组件架构的框架,它允许您标记与接口的类,并且让你可以干净地使用一个对象有一些接口它不是设计有排在首位,将是一个更好的主意提供适配器对象。
这就是说,你问的是改变类,其他模块,它是 - 这样的改变是对所有其他模块可见。
你做到这一点:改变它所属的模块中的类。 在Python这是可以做到简单地归咎于你的新类所需的名称,产地的模块:
import base_classes
class Bookcollection(base_classes.Bookcollection):
new_member = "lalala"
base_classes.Bookcollection = Bookcollection
(强烈建议,以避免“从X导入*”比单一脚本更大的任何项目 - 在这种情况下,你有2个变量具有相同的名称,以及不同的含义整个代码:基类和继承类,用于例如,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组件架构。 而你采取任何方式, 做写单元测试。
有类具有相同的名称通常是你得到的命名空间的冲突是一个坏主意。 我会建议改变你的MyLibPackage.base_classes.Bookcollection
到MyLibPackage.base_classes.BaseBookcollection
或相似。 这样,就可以预期。