为 Python 类导入方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1057934/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 21:22:56  来源:igfitidea点击:

Importing methods for a Python class

pythonimportmethods

提问by Martin Gustafsson

I wonder if it's possible to keep methods for a Python class in a different file from the class definition, something like this:

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

main_module.py:

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:

to_import_from.py:

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

In my case, to_import_from.pyis machine-generated, and contains many methods. I would rather not copy-paste these into main_module.py or import them one by one, but have them all recognized as methods of the Instrument class, just as if they had been defined there:

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

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

Thanks!

谢谢!

采纳答案by Martin Gustafsson

I don't think what you want is directly possible in Python.

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

You could, however, try one of the following.

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

  1. When generating to_import_from.py, add the non-generated stuff there too. This way, all methods are in the same class definition.
  2. Have to_import_from.pycontain a base class definition which the the Instrument class inherits.
  1. 生成时to_import_from.py,也在那里添加非生成的东西。这样,所有方法都在同一个类定义中。
  2. 已经to_import_from.py包含一个 Instrument 类继承的基类定义。

In other words, in to_import_from.py:

换句话说,在to_import_from.py

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

and then in main_module.py:

然后在main_module.py

import to_import_from

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

回答by Ants Aasma

People seem to be overthinking this. Methods are just function valued local variables in class construction scope. So the following works fine:

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

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)

回答by Lennart Regebro

It's easier than you think:

这比你想象的要容易:

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

Done!

完毕!

Although having the machine generated code generate a class definition and subclassing from it would be a neater solution.

尽管让机器生成的代码生成类定义并从中生成子类将是一个更简洁的解决方案。

回答by balpha

I'm sorry that this is kind of a "You shouldn't be putting nails in the wall" answer, but you're missing the point of python class definitions. You should rather put the class with all its methods in its own python file, and in your main_module.pydo

很抱歉,这是一种“您不应该在墙上钉钉子”的答案,但是您忽略了 Python 类定义的重点。你应该把类和它的所有方法放在它自己的 python 文件中,并在你main_module.py

from instrument import Instrument

If you plan on using the methods for several classes, you should consider subclassing. In your case, the machine generated file could contain the base class that Instrumentinherits from.

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

Finally, give your class a good docstring that explains the API to its user, so there is no need for a "header file" used as an overview of your class.

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

回答by Otto Allmendinger

you can do this with the __getattr__method

你可以用这个__getattr__方法来做到这一点

external.py

外部文件

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

main.py:

主要.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")

回答by S.Lott

What you're doing is extending a base class with some "machine-generated" code.

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

Choice 1. Extend a base class with machine-generated code.

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

machine_generated.py

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...

Your application can then import machine_generatedand use machine_generated.Instrument_Implementation.

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

Choice 2. Simply use first-class functions.

选择 2. 只需使用一流的功能。

machine_generated.py

machine_generated.py

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

main_module.py

main_module.py

import machine_generated

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

Your application can import main_moduleand use main_module.Instrument.

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

回答by yanjost

Here's my try. I think a nicer approach could be made with metaclasses...

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

to_import_from.py :

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 :

仪器.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)

when you run this code

当您运行此代码时

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

here's the output :

这是输出:

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

回答by Brian

Technically, yes this is possible, but solving it this way is not really idiomatic python, and there are likely better solutions. Here's an example of how to do so:

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

That will import all callable functions defined in to_import_fromas methods of the Instrumentclass, as well as adding some more methods. Note: if you also want to copy global variables as instance variables, you'll need to refine the check. Also note that it adds allcallable objects it finds in to_import_from's namespace, including imports from other modules (ie from module import some_funcstyle imports)

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

However, this isn't a terribly nice way to do it. Better would be to instead tweak your code generation to producea class, and have your class inherit from it. This avoids the unneccessary copying of methods into Instrument's namespace, and instead uses normal inheritcance. ie:

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

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