Как я могу определить, передал ли вызывающий объект переменные в мою функцию в Python? - PullRequest
0 голосов
/ 27 марта 2010

Я думаю, что тема звучит довольно глупо, поэтому я покажу код:

def foo(**kwargs):
    # How can you detect the difference between (**{}) and ()?
    pass
foo(**{})
foo()

Есть ли способ обнаружить внутри foo, как этот метод вызывался?

Обновление 1

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

super(MyClass, self).foo(*args, **kwargs) отстой - много расточительного дублирования. Я хочу написать 'self.super ()'. В этом случае просто вызовите суперкласс и передайте все параметры, которые получил вызывающий метод. Работает как шарм.

Теперь проблемная магическая часть:

Я хочу сказать «self.super (что-то)», и в этом случае только «что-то» передается методу super. Работает для большинства случаев.

Вот где он ломается:

def foo(self, fnord=42, *args, **kwargs):
    self.super(*args, **kwargs)

Таким образом, супер метод должен получить аргументы, которые вызывает метод - однако если *args, **kwargs пустые, в настоящее время библиотека не может обнаружить это условие и передала все аргументы, включая 'fnord' ...

Конечно, я мог бы использовать self.super.foo(*args, **kwargs) в качестве альтернативного синтаксиса, но это плохо: -)

PS: Да, я знаю, что p3k супер, но все же не очень хорошо, и он не работает с Python 2.x ...

Обновление 2

На самом деле даже модуль Ast Python удаляет **{} (ast.parse('foo(**{})')), поэтому похоже, что это происходит на раннем этапе процесса синтаксического анализа, и вы не сможете получить эту информацию позже ...

Итак, в конце я должен либо отказаться от этой конкретной проблемы (вызывая AmbiguousSyntaxError), либо использовать синтаксический анализ текста, предложенный ~ unutbu. Переосмысливая мой подход, последний может на самом деле осуществиться, потому что мне нужно только знать, если это self.super(\s*), self.super(\S+).

Ответы [ 3 ]

0 голосов
/ 27 марта 2010

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

def foo(self, fnord=42, *args, **kwargs):
    self.super(*args, **kwargs)

Делает ли это то, что вы хотите?

def foo(self, fnord=42, *args, **kwargs):
    self.super(fnord=fnord, *args, **kwargs)
0 голосов
/ 17 апреля 2010

Так что в принципе это невозможно сделать с помощью предоставленных модулей Python. Мне пришлось прибегнуть к регулярным выражениям в простом тексте, которые мне очень помогли, учитывая простоту моих требований.

0 голосов
/ 27 марта 2010

Этот хак работает только с CPython.

import traceback

def foo(**kwargs):
    # stack is a list of 4-tuples: (filename, line number, function name, text)
    # see http://docs.python.org/library/traceback.html#module-traceback

    (filename,line_number,function_name,text)=traceback.extract_stack()[-2]
    print('foo was called: %s'%text)

foo(**{})
# foo was called: foo(**{})
foo()
# foo was called: foo()

В качестве примера того, как это может быть полезно:

def pv(var):
    (filename,line_number,function_name,text)=traceback.extract_stack()[-2]
    print('%s: %s'%(text[text.find('(')+1:-1],var))

x=5
pv(x)
# x: 5

Обратите внимание, что pv вызывается только со значением x, но он печатает как «имя» переменной (как она была вызвана), так и значение переменной. Иногда я использую это при отладке, и мне лень писать полный оператор печати. ​​

...