更改导入的模块导入

时间:2019-07-29 10:24:29

标签: python python-import monkeypatching

如何更改导入模块的导入?

我创建了一个程序包,我想在另一个项目中对其进行扩展。 导入的软件包如下所示:

/pck_name
   /__init__.py
   /point.py
   /triangle.py

point.py:

class Point(object):
    def __init__(self, name='test'):
        self.name = name

triangle.py:

from pck_name.point import Point

class Triangle(object):        
    def __init__(self, points=None):    
        if points is None:
            points = list()
            for i in range(2):
                points.append(Point())         
        self.points = points   

然后我有另一个项目,其中我使用新方法定义了NewPoint类:

class NewPoint(object):    
    def __init__(self, name='test'):
        self.name = name

    def print_name(self):
        print(self.name)

我要实现的是导入pck_name.triangle并使用NewPoint更改导入的Point以获取新功能:

from pck_name.triangle import Triangle

triangle = Triangle()
triangle.points[0].print_name()

我尝试了猴子补丁,但如果我对Point类进行补丁,则它是无用的,因为triangle.py中的import语句始终会导入原始Point类。

非常感谢您!

3 个答案:

答案 0 :(得分:0)

您可以将工厂(类或函数)传递给Triangle的“构造函数”:

class Triangle:
    def __init__(self, points=None, factory=None):
        if points is None:
            if factory is None:  
                # instead of raising an error, you can use Point class by default
                raise ValueError("Both points and factory not provided")
            points = [factory() for _ in range(3)]
        self.points = points

现在您可以通过以下方式使用它:

triangle = Triangle()  # raises error
triangle = Triangle(points=...)  # uses provided points
triangle = Triangle(factory=NewPoint)  # creates a triangle with NewPoints

编辑:;此外,如果您想使用某种别名,则可以使用functools.partial

NewPointTriangle = functools.partial(Triangle, factory=NewPoint)
DefaultPointTriangle = functools.partial(Triangle, factory=Point)

现在:

triangle = NewPointTriangle()  # creates NewPoints
triangle = DefaultPointTriangle()  # creates Points

triangle = NewPointTriangle(points=...)  # uses provided points
triangle = DefaultPointTriangle(points=...)  # uses provided points

答案 1 :(得分:0)

如果我正确理解,您想修改Triangle类的行为,而无需实际“接触”代码。这不是最好或优雅的方法,但也许会以某种方式有用:

  • 导入NewPoint时修改Triangle.points列表:
import sys

if sys.modules.get('NewPoint'):

  # clear and update the Triangle.points list
  triangle.__dict__['points'].clear()

  for i in range(2):
    triangle.__dict__['points'].append(NewPoint()) 

enter image description here

答案 2 :(得分:0)

目前,我已经通过覆盖导入的模块解决了该问题。缺点是我必须以正确的顺序导入和覆盖模块。这意味着我必须先导入并覆盖要覆盖的类或函数,然后再将其导入其他任何地方。这不是一个完美的解决方案,因为很难确定何时导入某些内容。 一位朋友告诉我,他通过助手功能解决了一个相关问题。您对此有任何经验吗?