Python: adding a code routine to each line of a code block

I want a piece of code to run after each line of another block of code. For example, you want to be able to evaluate a global variable before or after the next line of a function.

For example, below I am trying to type "hello" before each line of the function foo(). I think the decorator can help me, but in order to edit each line of my function foo()and add what I want, before or after it, some kind of introspection function will be required.

I am trying to execute something like this:

>>> def foo():
...    print 'bar'
...    print 'barbar'
...    print 'barbarbar'

>>> foo()
hello
bar
hello
barbar 
hello
barbarbar

How to do it? can an object __code__help? Do I need a decorator and introspection at the same time?

EDIT: Here is another example of the purpose of this thread:

>>> def foo():
...    for i in range(0,3):
...        print 'bar'

>>> foo()
hello
bar
hello
bar 
hello
bar

"" "".

, . , True, ; False, .

EDIT: , .

EDIT: unutbu :

import sys
import time
import threading

class SetTrace(object):
    """
    with SetTrace(monitor):
    """
    def __init__(self, func):
        self.func = func
    def __enter__(self):
        sys.settrace(self.func)
        return self
    def __exit__(self, ext_type, exc_value, traceback):
        sys.settrace(None)
        # http://effbot.org/zone/python-with-statement.htm
        # When __exit__ returns True, the exception is swallowed.
        # When __exit__ returns False, the exception is reraised.
        # This catches Sentinel, and lets other errors through
        # return isinstance(exc_value, Exception)

def monitor(frame, event, arg):
    if event == "line":
        if not running:
            raise Exception("global running is False, exiting")
    return monitor

def isRunning(function):
    def defaultBehavior(*args):
        with SetTrace(monitor):
            ret = function(*args)
            return ret
    return defaultBehavior

@isRunning
def foo():
    while True:
        time.sleep(1)
        print 'bar'

global running
running = True
thread = threading.Thread(target = foo)
thread.start()
time.sleep(3)
running = False
+4
3

, sys.settrace:

import sys
class SetTrace(object):
    def __init__(self, func):
        self.func = func

    def __enter__(self):
        sys.settrace(self.func)
        return self

    def __exit__(self, ext_type, exc_value, traceback):
        sys.settrace(None)

def monitor(frame, event, arg):
    if event == "line":
        print('hello')
        # print(frame.f_globals) 
        # print(frame.f_locals)  
    return monitor



def foo():
   print 'bar'
   print 'barbar'
   print 'barbarbar'

with SetTrace(monitor):
    foo()

hello
bar
hello
barbar
hello
barbarbar
hello

monitor foo, frame.f_locals frame.f_globals.

post , sys.settrace .


foo monitor:

- foo, foo , . monitor , foo .

, foo, monitor. , . SetTrace.__exit__, , foo .

import sys
class Sentinel(Exception): pass

class SetTrace(object):
    """
    with SetTrace(monitor):
        ...
    """
    def __init__(self, func):
        self.func = func

    def __enter__(self):
        sys.settrace(self.func)
        return self

    def __exit__(self, ext_type, exc_value, traceback):
        sys.settrace(None)
        # http://effbot.org/zone/python-with-statement.htm
        # When __exit__ returns True, the exception is swallowed.
        # When __exit__ returns False, the exception is reraised.

        # This catches Sentinel, and lets other errors through
        return isinstance(exc_value, Sentinel)

def monitor(frame, event, arg):
    if event == "line":
        l = frame.f_locals
        x = l.get('x', 0)
        print('x = {}'.format(x))
        if x > 3:
            raise Sentinel()
    return monitor

def foo():
    x = 0
    while True:
        print 'bar'
        x += 1

with SetTrace(monitor):
    foo()
+6

, , pdb. pdb :

>>> def foo():
...     import pdb;pdb.set_trace()
...     print 'bar'
...     print 'barbar'
...     print 'barbarbar'
... 
>>> 
>>> foo()
> <stdin>(3)foo()
(Pdb) print 'hi'
hi
(Pdb) n
bar
> <stdin>(4)foo()
(Pdb) n
barbar
> <stdin>(5)foo()
(Pdb) n
barbarbar
--Return--
> <stdin>(5)foo()->None
(Pdb) n
--Return--
> <stdin>(1)<module>()->None
(Pdb) n
>>> 

, . , pdb.set_trace() -call pdb. . n next, .

0

The best answer probably depends on what you really want to do, but to do what you asked, I would do the following:

from itertools import chain

def print_(s):
    print s

def print_f(s):
   return (lambda: print_(s))

def execute_several(functions):
    for f in functions:
        f()

def prepend_printhello(function):
    return (print_f("hello"), function)

def foo():
    execute_several(chain(*map(prepend_printhello, map(print_f, ("bar", "barbar", "barbarbar")))))
0
source

Source: https://habr.com/ru/post/1546850/


All Articles