Импорт методов для класса Python
интересно, можно ли сохранить методы для класса 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 ответов
Я не думаю, что то, что вы хотите, непосредственно возможно в Python.
вы можете, однако, попробовать одно из следующих действий.
- при создании
to_import_from.py
, добавьте туда и не сгенерированный материал. Именно такой образ, все методы находятся в одном определении класса. - есть
to_import_from.py
содержит определение базового класса, которое класс инструмента наследует.
другими словами, в 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):
...
люди, кажется, слишком много об этом думаешь. Методы - это просто локальные переменные с функциональным значением в области построения класса. Таким образом, следующее отлично работает:
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)
Это проще, чем вы думаете:
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
готово!
хотя наличие машинного кода генерирует определение класса и подклассы из него было бы более аккуратным решением.
вы можете сделать это с помощью __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")
мне жаль, что это своего рода " вы не должны класть гвозди в стену " ответ, но вы упускаете суть определений классов python. Вы должны скорее поместить класс со всеми его методами в свой собственный файл python и в свой main_module.py
do
from instrument import Instrument
Если вы планируете использовать методы для нескольких классов, вы должны рассмотреть подклассы. В вашем случае созданный машиной файл может содержать базовый класс, который Instrument
наследует от.
наконец, дайте вашему классу хорошую docstring, которая объясняет API своему пользователю, поэтому нет необходимости в "файле заголовка", используемом в качестве обзора вашего класса.
то, что вы делаете, это расширение базового класса с помощью некоторого "машинного" кода.
выбор 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
.
вот моя попытка. Думаю, с метаклассами можно было бы подойти лучше...
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
технически, да, это возможно, но решение его таким образом на самом деле не является идиоматическим 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
class, а также добавление еще нескольких методов. Примечание. Если вы также хотите скопировать глобальные переменные в качестве переменных экземпляра, вам необходимо уточнить проверку. Также обратите внимание, что он добавляет все отзывной объекты, которые он находит в пространстве имен to_import_from, включая импорт из других модулей (т. е. from module import some_func
стиль импорт)
однако, это не очень хороший способ сделать это. Лучше было бы вместо этого настроить генерацию кода на производства класс, и ваш класс наследуется от него. Это позволяет избежать ненужных копирование методов в пространстве имен прибора, и вместо этого использует обычный inheritcance. т. е.:
class Instrument(to_import_from.BaseClass):
# Add new methods here.