Python находит, кто вызывает функцию [duplicate]

erase_if для std :: map (и других контейнеров)

Для этого я использую следующий шаблон.

namespace stuff { template< typename ContainerT, typename PredicateT > void erase_if( ContainerT& items, const PredicateT& predicate ) { for( auto it = items.begin(); it != items.end(); ) { if( predicate(*it) ) it = items.erase(it); else ++it; } }; }

Это ничего не вернет, но это удалит элементы из std :: map.

Пример использования:

// 'container' could be a std::map // 'item_type' is what you might store in your container using stuff::erase_if; erase_if(container, []( item_type& item ) { return /* insert appropriate test */; });

Второй пример (позволяет передать тестовое значение):

// 'test_value' is value that you might inject into your predicate. // 'property' is just used to provide a stand-in test using stuff::erase_if; int test_value = 4; // or use whatever appropriate type and value erase_if(container, [&test_value]( item_type& item ) { return item.property < test_value; // or whatever appropriate test });
119
задан SilentGhost 16 April 2010 в 16:29
поделиться

6 ответов

inspect.getframeinfo и другие связанные функции в проверять могут помочь:

  & gt; & gt; & gt; & gt;  проверка импорта & gt; & gt; & gt; & gt; & gt; & gt;  def f1 (): f2 () ... & gt; & gt; & gt; & gt; & gt;  def f2 (): ... curframe = inspect.currentframe () ... calframe = inspect.getouterframes (curframe, 2) ... print 'имя вызывающего абонента:', calframe [1] [3] ... & gt;  & GT; & GT;  f1 () имя вызывающего абонента: f1 & gt; & gt; & gt; & gt;   

эта интроспекция предназначена для помощи в отладке и разработке; нецелесообразно полагаться на это для производственных целей.

159
ответ дан Alex Martelli 16 August 2018 в 04:38
поделиться
  • 1
    & quot; нецелесообразно полагаться на него для целей производственной функциональности. & quot; Почему нет? – beltsonata 11 November 2014 в 20:52
  • 2
    @beltsonata зависит от реализации CPython, поэтому код, использующий это, сломается, если вы попытаетесь использовать PyPy или Jython или другие среды выполнения. это прекрасно, если вы просто разрабатываете и отлаживаете локально, но не очень хотите, чтобы вы в своей производственной системе. – robru 10 February 2015 в 03:08
  • 3
    Привет, народ! В конце концов. Готово ли это еще не производство? – Eugene Krevenets 7 August 2016 в 14:14
  • 4
    @EugeneKrevenets нет, читайте комментарий Робру. – Marcus 19 December 2016 в 22:42
  • 5
    @EugeneKrevenets. Помимо просто версии python, я просто столкнулся с проблемой, когда он запускает код, который запускается под вторым запуском за несколько минут после введения. он крайне неэффективен – Dmitry 7 April 2017 в 21:35

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

https://gist.github.com/2151727 (rev 9cccbf)

  # Public Domain, то есть не стесняйтесь копировать / вставлять  # Считается, что взлом в Python 2 import проверяет def caller_name (skip = 2): "" "Получить имя вызывающего абонента в формате module.class.method` skip` указывает, сколько уровней стека пропустить при получении имени вызывающего абонента.  skip = 1 означает «кто меня звонит», skip = 2 «кто звонит моему абоненту» и т. д. Пустая строка возвращается, если пропущенные уровни превышают высоту стека »« »stack = inspect.stack () start = 0 + skip if len (  стек)  start + 1: return '' parentframe = stack [start] [0] name = [] module = inspect.getmodule (parentframe) # `modname` может быть None, когда кадр выполняется непосредственно в консоли # TODO (techtonik): рассмотрите возможность использования  __main__ if module: name.append (module .__ name__) # обнаружить имя класса, если «self» в parentframe.f_locals: # Я не знаю, какой способ обнаружить вызов из метода объекта # XXX: похоже, нет способа обнаружить  статический вызов метода - это будет # просто вызов функции name.append (parentframe.f_locals ['self'] .__ class __.__ name__) codename = parentframe.f_code.co_name, если codename! = '& lt; module & gt;': # верхний уровень  обычно name.append (кодовое имя) # функция или метод ## Избегайте циклических ссылок и исправлений кадров # https://docs.python.org/2.7/library/inspect.html#the-interpreter-stack del parentframe, возврат в стеке "  . ". join (name)  
24
ответ дан anatoly techtonik 16 August 2018 в 04:38
поделиться
  • 1
    Удивительно, это хорошо сработало для меня в моем протоколе регистрации, где меня можно вызвать из разных мест. Огромное спасибо. – little_birdie 24 July 2015 в 06:50
  • 2
    Если вы также не удаляете stack , он все еще теряет фреймы из-за циклических ссылок, как описано в inspect-docs – ankostis 10 December 2016 в 12:56
  • 3
    @ankostis, есть ли у вас некоторый тестовый код, чтобы доказать это? – anatoly techtonik 15 December 2016 в 17:17
  • 4
    Трудно показать в комментарии ... Скопируйте в редактор этот код вождения (введите из памяти) и попробуйте обе версии вашего кода: `` `import weakref class C: pass def kill (): print ('Killed' ) def leaking (): caller_name () local_var = C () weakref.finalize (local_var, kill) утечка () print («Local_var, должно быть, был убит») `` `Вы должны получить:` `` Killed Local_var должен иметь был убит `` `, а не:` `` Local_var, должно быть, был убит Killed `` ` – ankostis 15 December 2016 в 19:42
  • 5
    Потрясающие! Это сработало, когда другие решения не удались! Я использую методы класса и лямбда-выражения, поэтому это сложно. – osa 19 September 2017 в 00:04

Кажется, что все работает отлично:

  import sys print sys._getframe (). f_back.f_code.co_name  
28
ответ дан Augiwan 16 August 2018 в 04:38
поделиться
  • 1
    вау, ты прибил это человек. спасибо, что сработало – Sanjay Poongunran 28 June 2018 в 06:38

Я нашел способ, если вы проходите через классы и хотите, чтобы класс принадлежал методу AND. Это требует немного работы по извлечению, но это делает ее точкой. Это работает в Python 2.7.13.

  import inspect, os class ClassOne: def method1 (self): classtwoObj.method2 () class ClassTwo: def method2 (self): curframe = inspect.currentframe  () calframe = inspect.getouterframes (curframe, 4) print '\nI был вызван из', calframe [1] [3], \ 'in', calframe [1] [4] [0] [6: -2]  # создавать объекты для доступа к классам classoneObj = ClassOne () classtwoObj = ClassTwo () # запустить программу os.system ('cls') classoneObj.method1 ()  
1
ответ дан Michael Swartz 16 August 2018 в 04:38
поделиться

Более короткая версия:

  import проверить def f1 (): f2 () def f2 (): print 'имя вызывающего абонента:', inspect.stack () [1] [3] f1  ()  

(благодаря @Alex и Stefaan Lippen )

72
ответ дан Todd Owen 16 August 2018 в 04:38
поделиться
  • 1
    Привет, я получаю ниже ошибки, когда я запускаю это: File & quot; /usr/lib/python2.7/inspect.py" ;, строка 528, в findource, если не исходный файл и файл [0] + файл [-1]! = '& lt; & gt;': IndexError: индекс строки вне диапазона. Можете ли вы предоставить предложение. Thanx заранее. – Pooja 13 August 2014 в 12:07
  • 2
    Этот подход дал мне ошибку: KeyError: ' main ' – Praxiteles 1 October 2016 в 03:30

Немного об объединении вещей выше.

  def print_caller_name (stack_size = 3): def wrapper (fn): def internal (* args, ** kwargs): import проверить stack = inspect.stack (  ) modules = [(index, inspect.getmodule (stack [index] [0])) для индекса в обратном (диапазон (1, stack_size))] module_name_lengths = [len (module .__ name__) для _, модуль в модулях] s  = '{index: & gt; 5}: {module: ^% i}: {name}'% (max (module_name_lengths) + 4) callers = ['', s.format (index = 'level', module = '  module ', name =' name '),' - '* 50] для индекса, модуль в модулях: callers.append (s.format (index = index, module = module .__ name__, name = stack [index] [3]  )) callers.append (s.format (index = 0, module = fn .__ module__, name = fn .__ name__)) callers.append ('') print ('\n'.join (вызывающие)) fn (* args  , ** kwargs) return inner return wrapper  

Использование:

  @print_caller_name (4) def foo (): return 'foobar' def bar ()  : return foo () def baz (): return bar () def fizz (): return baz () fizz ()  

output is

  level  : module: name --------  ------------------------------------------ 3: Нет: fizz 2: None  : baz 1: None: bar 0: __main__: foo  
9
ответ дан Xie Yanbo 16 August 2018 в 04:38
поделиться
  • 1
    Это повысит значение IndexError, если требуемая глубина стека больше фактической. Используйте modules = [(index, inspect.getmodule (stack [index] [0])) для индекса в обратном (диапазон (1, мин (stack_size, len (inspect.stack ()))))] , чтобы получить модули. – jake77 27 February 2018 в 14:37
Другие вопросы по тегам:

Похожие вопросы: