1

I want to write a decorator in python: if a called function contains print's, the decorator prints her name before this function being called. I'm familiar with decorators syntax, but I have a problem with checking if a function has print within itself.

def preceeding_name(func):        
    @wraps(func)
    def wrapper(*args, **kwargs):
        if 'print' in func: 
            print(func.__name__)
        result = func(*args, **kwargs)
        return result
    return wrapper

It is not necessary to check if the print's from function will actually be called.

Macaronnos
  • 647
  • 5
  • 14
  • Finding out if a function calls another function is [hard](https://stackoverflow.com/questions/12013399/in-python-determine-if-a-function-calls-another-function). Can I suggest that you use the [`logging`](https://docs.python.org/3/library/logging.html) module instead? You can then easily use something like `%(funcName)s` when creating a formatter. – ash Feb 28 '17 at 13:39
  • @Josh, thank you, I will look at this functional – Macaronnos Feb 28 '17 at 13:48
  • This can be done by overriding sys.stdout – Abhishek J Feb 28 '17 at 14:14

2 Answers2

3

This can be done by holding the buffer of 'print' from flushing and checking it to see if a print has been done.

class Out(object):
    def write(self,s):
        self.s += s
    def __init__(self)
        self.s = '' 

Now to check

def wrapper(*args, **kwargs):
        our_out = Out()
        sys.stdout = our_out
        result = func(*args, **kwargs)

        if len(our_out.s)>0:
            sys.stdout = sys.__stdout__
            print func.__name__
            for s in our_out.s.split('\n'):
                print s     

        return result
Abhishek J
  • 2,386
  • 2
  • 21
  • 22
-1

I this case you can redefine print

def preceeding_name(func):
    @wraps(func)
    def wrapper(*args, **kwargs):

        old_print = print

        def print(*arg, **kwarg):
            old_print(func.__name__)
            old_print(*arg, **kwarg)

        result = func(*args, **kwargs)
        return result
    return wrapper

EDIT: i test and this work

old_print = print

def preceeding_name(func):

    def print(*arg, **kwarg):
        old_print(func.__name__, end='')
        old_print(*arg, **kwarg)

    def wrapper(*args, **kwargs):
        print('')
        result = func(*args, **kwargs)
        return result
    return wrapper

@preceeding_name
def a():
    print('hi')


a()

@preceeding_name
def b():
    print('hi')


b()

EDIT2:

old_print = print


def preceeding_name(func):
    global print
    def print(*arg, **kwarg):
        old_print(func.__name__)
        old_print(*arg, **kwarg)

    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return result

    return wrapper


@preceeding_name
def a():
    print('hi')


a()


@preceeding_name
def b():
    # print('hi')
    pass

b()
sahama
  • 669
  • 8
  • 16
  • This decorator doesn't do anything at all. Just because you redefine print in your current scope doesn't mean the decorated function will also use the new print. – Aran-Fey Feb 28 '17 at 13:50
  • @Rawing new edit of my code work in my computer. i use python 3.4 – sahama Feb 28 '17 at 13:56
  • This doesn't check if the function ever calls `print`. – Aran-Fey Feb 28 '17 at 14:00
  • No, this doesn't really work either. This replaces `print` globally, which means undecorated functions will also use the new print. And it'll only work if the decorator is in the same file as the decorated function. – Aran-Fey Feb 28 '17 at 14:08
  • This ones really good http://stackoverflow.com/questions/8391411/suppress-calls-to-print-python – Abhishek J Feb 28 '17 at 14:18