Травление и расстегивание в разных модулях

Я знаю, что это было затронуто рядом других вопросов (Невозможно загрузить файлы с помощью модулей pickle и multipile), но я не вижу, как их решения применимы к моей ситуации.

Это моя структура проекта (максимально минимальная):

classify-updater/
├── main.py
└── updater
    ├── __init__.py
    └── updater.py
classify
└── main.py

In classify-updater/main.py:

import sys
from sklearn.feature_extraction.text import CountVectorizer
from updater.updater import Updater

def main(argv):
    vectorizer = CountVectorizer(stop_words='english')
    updater = Updater(vectorizer)
    updater.update()

if __name__ == "__main__":
    main(sys.argv)

In classify-updater/updater/updater.py:

import dill

class Updater:

    def __init__(vectorizer):
        vectorizer.preprocessor = lambda doc: doc.text.encode('ascii', 'ignore')
        self.vectorizer = vectorizer

    def update(self):
        pickled_vectorizer = dill.dumps(self.vectorizer)
        # Save to Google Cloud Storage

In classify/main.py

import dill
import sys

def main(argv):
    # Load from Google Cloud Storage
    vectorizer = dill.loads(vectorizer_blob)

if __name__ == "__main__":
    main(sys.argv)

Это приводит к ImportError.

Traceback (most recent call last):
  File "classify.py", line 102, in <module>
    app.main(sys.argv)
  File "classify.py", line 50, in main
    vectorizer = self.fetch_vectorizer()
  File "classify.py", line 86, in fetch_vectorizer
    vectorizer = dill.loads(vectorizer_blob.download_as_string())
  File "/usr/local/lib/python2.7/site-packages/dill/dill.py", line 299, in loads
    return load(file)
  File "/usr/local/lib/python2.7/site-packages/dill/dill.py", line 288, in load
    obj = pik.load()
  File "/usr/local/Cellar/python/2.7.13_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 864, in load
    dispatch[key](self)
  File "/usr/local/Cellar/python/2.7.13_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1096, in load_global
    klass = self.find_class(module, name)
  File "/usr/local/lib/python2.7/site-packages/dill/dill.py", line 445, in find_class
    return StockUnpickler.find_class(self, module, name)
  File "/usr/local/Cellar/python/2.7.13_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1130, in find_class
    __import__(module)
ImportError: No module named updater.updater

В другом месте было объяснено, что pickle нуждается в определении класса для загрузки объекта, но я не вижу, откуда берется ссылка на модуль средства обновления, поскольку я обрабатываю только экземпляр векторизатора.

Я сильно упростил этот пример. С точки зрения нашей кодовой базы, эти два пакета довольно далеко друг от друга. Импорт одного модуля в другой может оказаться невозможным. Есть ли способ обойти это?


person Josh    schedule 28.07.2017    source источник
comment
В качестве обходного пути вы можете добавить путь средства обновления к PYTHONPATH, а затем импортировать его. Нет обходного пути. Боюсь (насколько мне известно) вам потребуется импортировать программу обновления.   -  person cs95    schedule 28.07.2017
comment
@ cᴏʟᴅsᴘᴇᴇᴅ, когда я говорю «работать», я имею в виду что-то вроде общего класса, который просто занимается маринованием и распаковкой. Что именно спасает маринад? Это непосредственный родитель вызвал рассол или что-то еще?   -  person Josh    schedule 28.07.2017
comment
Что-то вроде снимка экземпляра - его данные и атрибуты маринованы. При загрузке вам все равно понадобится контейнер для прикрепления снимка.   -  person cs95    schedule 28.07.2017
comment
@ cᴏʟᴅsᴘᴇᴇᴅ не могли бы вы рассказать о том, что вам все еще нужен контейнер для прикрепления снимка? Я действительно не понимаю, что это значит в данном контексте.   -  person Josh    schedule 28.07.2017
comment
Мне немного сложно объяснить ... Я плохо разбираюсь в технических терминах. Но в основном вам нужен исходный файл в виде байтового кода. Просто объекта недостаточно.   -  person cs95    schedule 28.07.2017
comment
@ cᴏʟᴅsᴘᴇᴇᴅ Я, должно быть, совершенно неправильно понял цель pickle, потому что не имеет смысла иметь ссылку на произвольный объект, который имеет ссылку на то, что вы маринуете. На любом другом языке (мой опыт - не Python, простите меня), если вы хотите сериализовать объект, вам просто нужно знать, как его десериализовать. Это безумие, что отправитель и получатель некоторых сериализованных данных должны иметь один и тот же модуль. Вы вынуждены пропускать функциональность через границы, когда все, что я хочу сделать, это передать объект между двумя совершенно не связанными между собой объектами.   -  person Josh    schedule 28.07.2017


Ответы (1)


Проблема здесь в лямбде (анонимной функции).

Вполне возможно обработать автономный объект, такой как векторизатор. Однако функция предварительной обработки, используемая в примере, относится к классу Updater, поэтому класс Updater требуется для извлечения.

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

person Josh    schedule 28.07.2017