Расширение класса в Python внутри декоратора - PullRequest
0 голосов
/ 16 декабря 2018

Я использую декоратор для расширения определенных классов и добавления к ним некоторой функциональности, например:

def useful_stuff(cls):
  class LocalClass(cls):
    def better_foo(self):
      print('better foo')
  return LocalClass

@useful_stuff
class MyClass:
  def foo(self):
    print('foo')

К сожалению, MyClass больше не маринован из-за неглобального LocalClass

AttributeError: Can't pickle local object 'useful_stuff.<locals>.LocalClass'
  • Мне нужно мариновать свои классы.Можете ли вы порекомендовать лучший дизайн?
  • Учитывая, что в классе может быть несколько декораторов, лучше было бы переключиться на множественное наследование, если MyClass наследует все функции?

1 Ответ

0 голосов
/ 16 декабря 2018

Вам необходимо установить метаданные так, чтобы подкласс выглядел как оригинал:

def deco(cls):
    class SubClass(cls):
        ...
    SubClass.__name__ = cls.__name__
    SubClass.__qualname__ = cls.__qualname__
    SubClass.__module__ = cls.__module__
    return SubClass

Классы выбираются с использованием их модуля и имени для записи, где найти класс.Ваш класс должен быть найден в том же месте, в котором находился бы исходный класс, если бы он не был оформлен, поэтому Pickle должен видеть тот же модуль и имя квалификации.Это похоже на то, что funcutils.wraps делает для декорированных функций.

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

def better_foo(self):
    print('better_foo')

def useful_stuff(cls):
    cls.better_foo = better_foo
    return cls
...