导入Python类的方法

时间:2009-06-29 12:01:58

标签: python import methods

我想知道是否可以将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)

谢谢!

8 个答案:

答案 0 :(得分:9)

人们似乎在思考这个问题。方法只是类构造范围中的函数值局部变量。所以以下工作正常:

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)

答案 1 :(得分:7)

我认为你想要的东西在Python中是不可能的。

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

  1. 生成to_import_from.py时,也会在此处添加非生成的内容。这条路, 所有方法都在同一个类定义中。
  2. to_import_from.py包含Instrument类的基类定义 继承。
  3. 换句话说,在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):
            ...
    

答案 2 :(得分:6)

比你想象的容易:

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

完成!

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

答案 3 :(得分: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")

答案 4 :(得分:3)

对不起,这有点像"You shouldn't be putting nails in the wall" answer,但你忽略了python类定义。您应该将具有所有方法的类放在它自己的python文件中,并放在main_module.py

from instrument import Instrument

如果您打算将方法用于多个类,则应考虑进行子类化。在您的情况下,机器生成的文件可以包含Instrument继承的基类。

最后,为您的班级提供一个很好的文档字符串,向其用户解释API,因此不需要使用“标题文件”作为您班级的概述。

答案 5 :(得分:2)

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

选择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

答案 6 :(得分:0)

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

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

答案 7 :(得分:0)

从技术上讲,是的,这是可能的,但以这种方式解决它并不是真正惯用的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.