Как мариновать регистраторы? - PullRequest
7 голосов
/ 31 июля 2010

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

Я довольно широко использую библиотеку журналов python, и все мои классы начинаются с настройки регистратора, например:

class foo:
   def __init__(self):
       self.logger = logging.getLogger("package.foo")

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

Теперь по какой-то причине эти регистраторы ломают Пикл. Я получаю следующую ошибку, которая исчезнет, ​​если я удалю self.logger из всех классов:

Can't pickle 'lock' object: <thread.lock object at ... >

Таким образом, мой вопрос заключается в том, существует ли какой-либо способ удалить объекты блокировки со всех регистраторов без необходимости проходить через все мое дерево объектов, удаляя регистраторы, которые мне придется воссоздавать при разблокировке.

Ответы [ 5 ]

11 голосов
/ 26 января 2016

Вы также можете создать класс, который реализует свойство, которое возвращает необходимый регистратор. Каждый класс, который наследуется от этого «LoggerMixin», теперь может использовать регистратор так же, как вы использовали его раньше.

class LoggerMixin():
    @property
    def logger(self):
        component = "{}.{}".format(type(self).__module__, type(self).__name__)
        return logging.getLogger(component)

class Foo(LoggerMixin):
    def __init__(self):
        self.logger.info("initialize class")

    def bar(self):
        self.logger.info("execute bar")
4 голосов
/ 31 июля 2010

Вы можете создать класс, который упаковывает регистратор и реализует __getstate__ и __setstate__.

Это вставлено из http://docs.python.org/library/pickle.html.. fh обрабатывается таким образом, который может быть похож на то, что вам нужно.

#!/usr/local/bin/python

class TextReader:
    """Print and number lines in a text file."""
    def __init__(self, file):
        self.file = file
        self.fh = open(file)
        self.lineno = 0

    def readline(self):
        self.lineno = self.lineno + 1
        line = self.fh.readline()
        if not line:
            return None
        if line.endswith("\n"):
            line = line[:-1]
        return "%d: %s" % (self.lineno, line)

    def __getstate__(self):
        odict = self.__dict__.copy() # copy the dict since we change it
        del odict['fh']              # remove filehandle entry
        return odict

    def __setstate__(self, dict):
        fh = open(dict['file'])      # reopen file
        count = dict['lineno']       # read from file...
        while count:                 # until line count is restored
            fh.readline()
            count = count - 1
        self.__dict__.update(dict)   # update attributes
        self.fh = fh                 # save the file object
2 голосов
/ 02 июля 2018

Новое в Python 3.7 ( bpo30520 )

Logger теперь можно мариновать, как и многие другие объекты.

import pickle
import logging
log = logging.getLogger(__name__)
logger_pickle = pickle.dumps(log)

# and of coarse, to load:
log = pickle.loads(logger_pickle)
2 голосов
/ 31 июля 2010

Нашел очень похожий вопрос здесь, с ответом, который работал для меня:

Как предотвратить травление атрибутов в Python

edit: использовал этот ответ: Как остановить выбор атрибутов в Python

1 голос
/ 03 апреля 2015

Вы могли бы использовать dill здесь, который может засекать регистраторы и замки.

>>> class foo:
...    def __init__(self):
...        self.logger = logging.getLogger("package.foo")
... 
>>> import dill
>>> import logging
>>> 
>>> f = foo()
>>> _f = dill.dumps(f)  
>>> f_ = dill.loads(_f)
>>> f_.logger
<logging.Logger object at 0x110b1d250>
...