代码之家  ›  专栏  ›  技术社区  ›  bialix

在Python中使用基类构造函数作为工厂?

  •  7
  • bialix  · 技术社区  · 17 年前

    我使用基类构造函数作为工厂,并在这个构造函数/工厂中更改类以选择合适的类——这种方法是好的python实践还是有更优雅的方法?

    我曾尝试阅读有关元类的帮助,但没有取得很大成功。

    这里是我正在做的例子。

    class Project(object):
      "Base class and factory."
      def __init__(self, url):
          if is_url_local(url):
            self.__class__ = ProjectLocal
          else:
            self.__class__ = ProjectRemote
          self.url = url
    
    class ProjectLocal(Project):
      def do_something(self):
        # do the stuff locally in the dir pointed by self.url
    
    class ProjectRemote(Project):
      def do_something(self):
        # do the stuff communicating with remote server pointed by self.url
    

    有了这段代码,我可以通过基类Project创建ProjectLocal/ProjectRemote的实例:

    project = Project('http://example.com')
    project.do_something()
    

    def project_factory(url):
          if is_url_local(url):
            return ProjectLocal(url)
          else:
            return ProjectRemote(url)
    
    project = project_factory(url)
    project.do_something()
    

    我的第一个方法只是品味的问题,还是有一些隐藏的陷阱?

    6 回复  |  直到 17 年前
        1
  •  19
  •   Brian    17 年前

    你不应该为此需要元类。看一看 __new__

    class Project(object):
      "Base class and factory."
      def __new__(cls, url):
        if is_url_local(url):
           return super(Project, cls).__new__(ProjectLocal, url) 
        else:
           return super(Project, cls).__new__(ProjectRemote, url) 
    
      def __init__(self, url):
        self.url = url
    
        2
  •  13
  •   scottynomad    17 年前

    如果第一个例子奏效,那更多的是运气,而不是设计。如果你想有一个 __init__

        3
  •  3
  •   batbrat    17 年前

    http://www.suttoncourtenay.org.uk/duncan/accu/pythonpatterns.html#factory http://code.activestate.com/recipes/86900/

    此外,当您使用新样式类时,通常会使用_unew_uu作为工厂函数(而不是在基类中,单独的类更好)(据我所知)。

    工厂函数通常比较简单(其他人已经发布过)

    我希望你发现答案和链接对你有帮助。

    祝你一切顺利。

        4
  •  2
  •   andreypopp    16 年前

    考虑下面的类层次结构:

    class Base(object):
    
        def __init__(self, config):
            """ Initialize Base object with config as dict."""
            self.config = config
    
        @classmethod
        def from_file(cls, filename):
            config = read_and_parse_file_with_config(filename)
            return cls(filename)
    
    class ExtendedBase(Base):
    
        def behaviour(self):
            pass # do something specific to ExtendedBase
    

    >>> Base({"k": "v"})
    >>> Base.from_file("/etc/base/base.conf")
    

    但是,您也可以免费使用ExtendedBase:

    >>> ExtendedBase({"k": "v"})
    >>> ExtendedBase.from_file("/etc/extended/extended.conf")
    

    因此,这个类方法工厂也可以被看作是辅助构造函数。

        5
  •  1
  •   Ber    17 年前

    我通常有一个单独的工厂类来做这件事。这样,您就不必使用元类或作业来 self.__class__

    对我来说效果很好,还实现了封装和信息隐藏等功能。

        6
  •  0
  •   unbeknown unbeknown    17 年前

    我认为使用工厂函数的第二种方法比让基类的实现依赖于它的子类要干净得多。