Импорт методов для класса Python - PullRequest
9 голосов
/ 29 июня 2009

Интересно, возможно ли сохранить методы для класса 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 ]

9 голосов
/ 29 июня 2009

Люди, кажется, обдумывают это. Методы - это просто локальные переменные с функциональным значением в области построения класса. Таким образом, следующее прекрасно работает:

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)
7 голосов
/ 29 июня 2009

Я не думаю, что то, что вы хотите, напрямую возможно в 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):
        ...
6 голосов
/ 29 июня 2009

Это проще, чем вы думаете:

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

Готово! * * 1004

Несмотря на то, что машинно-сгенерированный код генерирует определение класса, и создание подклассов из него было бы более точным решением.

4 голосов
/ 29 июня 2009

вы можете сделать это с помощью метода __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")
3 голосов
/ 29 июня 2009

Мне жаль, что это что-то вроде "Вы не должны вбивать гвозди в стену", ответ , но вы упускаете смысл определений классов Python. Лучше поместить класс со всеми его методами в собственный файл python и в свой main_module.py do

from instrument import Instrument

Если вы планируете использовать методы для нескольких классов, вам следует рассмотреть возможность создания подклассов. В вашем случае сгенерированный компьютером файл может содержать базовый класс, от которого наследуется Instrument.

Наконец, дайте вашему классу хорошую строку документации, которая объясняет API для его пользователя, так что нет необходимости в «заголовочном файле», используемом в качестве обзора вашего класса.

2 голосов
/ 29 июня 2009

То, что вы делаете, это расширение базового класса с помощью некоторого «машинно-генерируемого» кода.

Вариант 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.

0 голосов
/ 29 июня 2009

Технически, да, это возможно, но решить его таким способом - не совсем идиоматический питон, и, вероятно, есть лучшие решения. Вот пример того, как это сделать:

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 импорт в стиле)

Однако это не очень хороший способ сделать это. Лучше было бы вместо этого настроить генерацию кода, чтобы создал класс, и чтобы ваш класс наследовал от него. Это позволяет избежать ненужного копирования методов в пространство имен инструмента и вместо этого использует обычное наследование. то есть:

class Instrument(to_import_from.BaseClass):
    # Add new methods here.
0 голосов
/ 29 июня 2009

Вот моя попытка. Я думаю, что с метаклассами можно сделать более хороший подход ...

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...