Мне нравится ответ @ Space_C0wb0y, он похож на код, присланный мне Рэймондом Хеттингером для решения аналогичной ситуации в pyparsing (см. Ниже).Для вашего простого случая попробуйте использовать этот класс нормализатора, чтобы обернуть заданные обратные вызовы:
class _ArityNormalizer(object):
def __init__(self, fn):
self.baseFn = fn
self.wrapper = None
def __call__(self, value, domain_object):
if self.wrapper is None:
try:
self.wrapper = self.baseFn
return self.baseFn(value, domain_object)
except TypeError:
self.wrapper = lambda v,d: self.baseFn(v)
return self.baseFn(value)
else:
return self.wrapper(value, domain_object)
Ваш код теперь может обернуть обратные вызовы в _ArityNormalizer
, и во время обратного вызова всегда вызывать с 2 аргументами._ArityNormalizer
выполнит вызов методом проб и ошибок "с 2 аргументами", а если это не удастся, вызовет логику с 1 аргументом "только один раз, и с этого момента он перейдет непосредственно к правильной форме.
В режиме pyparsing,Я хотел поддержать обратные вызовы, которые могут быть определены как принимающие 0, 1, 2 или 3 аргумента, и написал код, который обернул бы вызываемую функцию одним из нескольких декораторов в зависимости от того, какой была сигнатура функции обратного вызова.Таким образом, во время выполнения / обратного вызова я просто всегда вызывал бы с 3 аргументами, и декоратор позаботился о том, чтобы сделать фактический вызов с правильным числом аргументов.
Мой код делал много хрупких / непереносимых / чувствительных к версии интроспекций подписи, чтобы сделать это (звучит как то, что сейчас делает OP), пока Raymond Hettinger не прислал мне хороший метод обрезки арности, который делаетпо сути, то, что предлагает ответ @ Space_C0wb0y.В коде RH использовалась очень аккуратная оболочка декоратора с нелокальной переменной, чтобы записать арность успешного вызова, так что вам придется проходить пробу и ошибку только один раз, а не каждый раз, когда вы вызываете обратный вызов.Вы можете увидеть его код в pyparsing SVN-репозитории на SourceForge, в функции _trim_arity
- обратите внимание, что его код имеет варианты Py2 / Py3 из-за использования ключевого слова "nonlocal".
_ArityNormalizer
Код выше был вдохновлен кодом Р.Х., прежде чем я полностью понял магию его кода.