Инъекционный вызов функции после init с декоратором
Я пытаюсь найти лучший способ создать декоратор класса, который делает следующее:
- вводит несколько функций в украшенный класс
- вызывает вызов одной из этих функций после украшенного класса'
__init__
называется
в настоящее время я просто сохраняю ссылку на "оригинал"__init__
метод и замена его на my __init__
это вызывает исходную и мою дополнительную функцию. Похоже на это:
orig_init = cls.__init__
def new_init(self, *args, **kwargs):
"""
'Extend' wrapped class' __init__ so we can attach to all signals
automatically
"""
orig_init(self, *args, **kwargs)
self._debugSignals()
cls.__init__ = new_init
есть ли лучший способ "увеличить" оригинал __init__
или ввести мой вызов где-то еще? Все что мне нужно это для моего self._debugSignals()
вызывается через некоторое время после создания объекта. Я также хочу, чтобы это произошло автоматически, поэтому я подумал после __init__
хорошее место.
дополнительно смешанная. Примечания декоратора
возможно, стоит упомянуть некоторые предпосылки этого декоратора. Вы можете найти полный код здесь. Этот пункт декоратора автоматически прикрепиться к любым сигналам PyQt и напечатать когда они испущены. Декоратор отлично работает, когда я украшаю свои собственные подклассы QtCore.QObject
, однако я недавно пытался автоматически украсить все дети QObject.
Я хотел бы иметь режим "отладки" в приложении, где я могу автоматически печатать все сигналы, чтобы убедиться, что вещи делают то, что я ожидаю. Я уверен, что это приведет к тоннам отладки, но я все равно хотелось бы посмотреть, что происходит.
проблема моя текущая версия оформителя вызывает segfault при замене QtCore.QObject.__init__
. Я попытался отладить это, но код весь сгенерирован SIP, с которым у меня нет большого опыта.
Итак, мне было интересно, есть ли более безопасный, более питонический способ ввести вызов функции после __init__
и, надеюсь, избежать segfault.
2 ответов
на основе этот пост и ответ, альтернативный способ сделать это через пользовательский метакласс. Это будет работать следующим образом (проверено на Python 2.7):
# define a new metaclass which overrides the "__call__" function
class NewInitCaller(type):
def __call__(cls, *args, **kwargs):
"""Called when you call MyNewClass() """
obj = type.__call__(cls, *args, **kwargs)
obj.new_init()
return obj
# then create a new class with the __metaclass__ set as our custom metaclass
class MyNewClass(object):
__metaclass__ = NewInitCaller
def __init__(self):
print "Init class"
def new_init(self):
print "New init!!"
# when you create an instance
a = MyNewClass()
>>> Init class
>>> New init!!
основная идея заключается в том, что:
когда вы называете
MyNewClass()
он ищет метакласс, находит, что вы определилиNewInitCaller
метакласс
__call__
вызывается функция.эта функция создает
MyNewClass
экземпляр с помощьюtype
,экземпляр запускает свой собственный
__init__
(печать "init class").затем мета-класс вызывает
вот решение для Python 3.х, на основе этот пост принят ответ. Также смотрите PEP 3115 Для справки, я думаю, что рассуждение интересно читать.
изменения в приведенном выше примере показаны с комментариями; единственное реальное изменение-способ определения метакласса, все остальные-тривиальные модификации 2to3.
# define a new metaclass which overrides the "__call__" function
class NewInitCaller(type):
def __call__(cls, *args, **kwargs):
"""Called when you call MyNewClass() """
obj = type.__call__(cls, *args, **kwargs)
obj.new_init()
return obj
# then create a new class with the metaclass passed as an argument
class MyNewClass(object, metaclass=NewInitCaller): # added argument
# __metaclass__ = NewInitCaller this line is removed; would not have effect
def __init__(self):
print("Init class") # function, not command
def new_init(self):
print("New init!!") # function, not command
# when you create an instance
a = MyNewClass()
>>> Init class
>>> New init!!