【问题标题】:Importing methods for a Python class导入 Python 类的方法
【发布时间】:2009-06-29 12:01:57
【问题描述】:

我想知道是否可以将 Python 类的方法保存在与类定义不同的文件中,如下所示:

main_module.py:

class Instrument(Object):
    # Some import statement?
    def __init__(self):
        self.flag = True
    def direct_method(self,arg1):
        self.external_method(arg1, arg2)

to_import_from.py:

def external_method(self, arg1, arg2):
    if self.flag:
        #doing something
#...many more methods

在我的例子中,to_import_from.py 是机器生成的,并且包含许多方法。我宁愿不将它们复制粘贴到 main_module.py 中或将它们一一导入,而是将它们都识别为 Instrument 类的方法,就好像它们已经在那里定义一样:

>>> instr = Instrument()
>>> instr.direct_method(arg1)
>>> instr.external_method(arg1, arg2)

谢谢!

【问题讨论】:

  • 你控制to_import_from.py的生成,还是必须“按原样”使用它?
  • 是的,我可以通过调整ctypeslib的代码来控制它。

标签: python import methods


【解决方案1】:

人们似乎想多了。方法只是类构造范围内的函数值局部变量。所以以下工作正常:

class Instrument(Object):
    # load external methods
    from to_import_from import *

    def __init__(self):
        self.flag = True
    def direct_method(self,arg1):
        self.external_method(arg1, arg2)

【讨论】:

  • 语法警告:import * 只允许在模块级别
  • 这应该是答案。
  • 要克服SyntaxError (Python 3.6) 不要做import *。相反,命名要显式导入的方法,例如from to_import_from import method1, method2.
  • 在调用外部方法的时候这个不会作为第一个变量传给类吗?
【解决方案2】:

我不认为你想要的在 Python 中是直接可能的。

但是,您可以尝试以下方法之一。

  1. 在生成to_import_from.py 时,也要在其中添加非生成的东西。这边走, 所有方法都在同一个类定义中。
  2. to_import_from.py 包含一个基类定义,它是Instrument 类 继承。

换句话说,在to_import_from.py

class InstrumentBase(object):
    def external_method(self, arg1, arg2):
        if self.flag:
            ...

然后在main_module.py:

import to_import_from

class Instrument(to_import_from.InstrumentBase):
    def __init__(self):
        ...

【讨论】:

    【解决方案3】:

    这比你想象的要容易:

    class Instrument(Object):
        def __init__(self):
            self.flag = True
        def direct_method(self,arg1):
            self.external_method(arg1, arg2)
    
    import to_import_from
    
    Instrument.external_method = to_import_from.external_method
    

    完成!

    虽然让机器生成的代码生成类定义并从中继承子类会是一个更简洁的解决方案。

    【讨论】:

      【解决方案4】:

      您可以使用__getattr__ 方法来做到这一点

      external.py

      def external_function(arg):
          print("external", arg)
      

      main.py:

      import external
      
      class Instrument(object):
          def __getattr__(self, name):
              if hasattr(external, name):
                  return getattr(external, name)
              else:
                  return Object.__getattr__(self, name)
      
          def direct_method(self, arg):
              print("internal", arg)
      
      
      i = Instrument() 
      i.direct_method("foo")
      i.external_function("foo")
      

      【讨论】:

        【解决方案5】:

        很抱歉,这有点像"You shouldn't be putting nails in the wall" answer,但您错过了 python 类定义的重点。您应该将类​​及其所有方法放在它自己的 python 文件中,并在您的main_module.py do

        from instrument import Instrument
        

        如果您计划将这些方法用于多个类,则应考虑子类化。在您的情况下,机器生成的文件可能包含 Instrument 继承自的基类。

        最后,给你的类一个很好的文档字符串,向它的用户解释 API,这样就不需要一个“头文件”用作你的类的概述。

        【讨论】:

          【解决方案6】:

          你正在做的是用一些“机器生成”的代码扩展一个基类。

          选择 1. 使用机器生成的代码扩展基类。

          machine_generated.py

          # Start of boilerplate #
          import main_module
          class Instrument_Implementation( main_module.Instrument_Abstraction ):
              def direct_method(self,arg1): 
                 # End of boilerplate #
                 ...the real code...
          

          然后您的应用程序可以import machine_generated 并使用machine_generated.Instrument_Implementation

          选择 2。简单地使用一流的函数。

          machine_generated.py

          def external_method(self, arg1, arg2):
              ...the real code...
          

          main_module.py

          import machine_generated
          
          class Instrument( object ):
              def direct_method(self,arg1): 
                  return machine_generator.external_method( arg1, ... )
          

          您的应用程序可以import main_module 并使用main_module.Instrument

          【讨论】:

            【解决方案7】:

            这是我的尝试。我认为可以使用元类制作更好的方法...

            to_import_from.py:

            def external_method(self, arg1, arg2):
                if self.flag:
                    print "flag is set"
                else :
                    print "flag is not set"
            

            instrument.py:

            import imp
            import os
            import inspect
            import new
            
            import pdb
            
            class MethodImporter(object) :
                def __init__(self, path_to_module) :
                    self.load_module(path_to_module)
            
                def load_module(self, path_to_module) :
                    name = os.path.basename(path_to_module)
                    module_file = file(path_to_module,"r")
                    self.module = imp.load_module(name, module_file , path_to_module, ('','r',imp.PY_SOURCE))
                    print "Module %s imported" % self.module
                    for method_name, method_object in inspect.getmembers(self.module, inspect.isfunction) :
                        print "adding method %s to %s" % (method_name, self)
                        setattr(self, method_name, new.instancemethod(method_object, self, self.__class__))
            
            
            class Instrument(MethodImporter):
                def __init__(self):
                    super(Instrument,self).__init__("./to_import_from.py")
                    self.flag = True
                def direct_method(self,arg1):
                    self.external_method(arg1, arg2)
            

            当你运行这段代码时

            arg1, arg2 = 1, 2
            instr = Instrument()
            instr.direct_method(arg1)
            instr.external_method(arg1, arg2)
            

            这是输出:

            Module <module 'to_import_from.py' from './to_import_from.pyc'> imported
            adding method external_method to <__main__.Instrument object at 0x2ddeb0>
            flag is set
            flag is set
            

            【讨论】:

              【解决方案8】:

              从技术上讲,是的,这是可能的,但是以这种方式解决它并不是真正地道的 python,并且可能有更好的解决方案。以下是如何执行此操作的示例:

              import to_import_from
              
              class Instrument(object):
                  locals().update(dict((k,v) for (k,v) in 
                                  to_import_from.__dict__.iteritems() if callable(v)))
              
                  def __init__(self):
                      self.flag = True
                  def direct_method(self,arg1):
                      self.external_method(arg1, arg2)
              

              这会将to_import_from 中定义的所有可调用函数导入为Instrument 类的方法,并添加更多方法。注意:如果您还想将全局变量复制为实例变量,则需要细化检查。另请注意,它添加了在 to_import_from 的命名空间中找到的 所有 可调用对象,包括来自其他模块的导入(即 from module import some_func 样式导入)

              但是,这并不是一个非常好的方法。更好的做法是调整您的代码生成以生成一个类,并让您的类继承自它。这避免了将方法不必要地复制到 Instrument 的命名空间中,而是使用正常的继承。即:

              class Instrument(to_import_from.BaseClass):
                  # Add new methods here.
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2020-12-25
                • 2020-11-23
                • 2011-10-21
                • 1970-01-01
                • 2016-02-20
                • 2016-04-15
                • 1970-01-01
                • 2022-10-19
                相关资源
                最近更新 更多