【问题标题】:Change imported modules imports更改导入的模块导入
【发布时间】:2019-07-29 10:24:29
【问题描述】:

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

我创建了一个包,我想在进一步的项目中扩展它。 导入的包长这样:

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

point.py:

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

三角形.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 中的导入语句总是导入原始的 Point 类。

非常感谢!

【问题讨论】:

    标签: python python-import monkeypatching


    【解决方案1】:

    您可以将工厂(类或函数)传递给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
    

    【讨论】:

    • 非常感谢您的回答!这可能是一个解决方案,但这是否也可以在不更改导入包的情况下进行?造成这种情况的一个原因是使用了我自己没有创建的包,因此我无法更改包代码。另一个原因是该解决方案使代码对于使用包本身的其他用户来说不必要的复杂。
    【解决方案2】:

    如果我理解正确,您想修改 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()) 
    

    【讨论】:

      【解决方案3】:

      现在我已经通过覆盖导入的模块解决了这个问题。缺点是我必须以正确的顺序导入和覆盖模块。这意味着我必须先导入并覆盖要覆盖的类或函数,然后才能将其导入其他任何地方。这不是一个完美的解决方案,因为很难弄清楚什么时候导入的。 一位朋友告诉我,他用辅助函数解决了一个相关问题。你有这方面的经验吗?

      【讨论】:

        猜你喜欢
        • 2011-08-14
        • 2012-08-27
        • 1970-01-01
        • 2018-10-28
        • 1970-01-01
        • 2021-12-08
        • 2019-11-08
        • 1970-01-01
        • 2013-04-05
        相关资源
        最近更新 更多