Is it possible in Python to decorate a function so that its begin and end are logged?
<p>For logging, I would like each function to log its own name at the start and end of the function.</p>

<pre><code>def my_function():
    print("Enter my_function")
    # ...
    print("Leave my_function")
</code></pre>

<p>If I change the name of the function, I have to update these print messages as well. I am looking for a way to automate this.</p>

<pre><code>def my_decorator(func):
    print("Enter ", func.__name__)
    func()
    print("Leave ", func.__name__)

def my_function():
    # do the work
    pass

# main:
my_decorator(my_function)
</code></pre>

<p>Is this possible in a simple way, maybe using decorators? How would this look like if my_function had parameters?</p>

<p>You are right, using a decorator is a perfect way to implement such behavior.</p>

<p>What you need to know is <a class='doc-link' href="http://stackoverflow.com/documentation/python/229/decorators#t=201608270936002345573">how a decorator works</a>: it simply takes a function as an argument, and returns another function. This other returned function is intended to wrap your argument function.</p>

<pre><code>def log_in_out(func):

    def decorated_func(*args, **kwargs):
        print("Enter ", func.__name__)
        result = func(*args, **kwargs)
        print("Leave ", func.__name__)
        return result

    return decorated_func

@log_in_out
def my_function():
    print("Inside my_function")
    return 42


val = my_function()

print(val)

# Output:
# Enter  my_function
# Inside my_function
# Leave  my_function
# 42
</code></pre>

<p>Also, note that the answer of @ÅukaszRogalski using <a href="https://docs.python.org/3/library/functools.html#functools.wraps" rel="nofollow"><code>functools.wraps</code></a> is usefull for preserving the function docstring.</p>

<p>Finally, a good idea from @MartinBonner, is that you can also use it to log the errors in your function:</p>

<pre><code>def log_in_out(func):

    def decorated_func(*args, **kwargs):
        name = func.__name__
        print("Enter", name)
        try:
            result = func(*args, **kwargs)
            print("Leave", name)
        except:
            print("Error in", name)
            raise
        return result

    return decorated_func
</code></pre>

<p>Note that I re-throw the error because I think the control flow should be managed from the outside of the function.</p>

<p>For more advanced logging, you should use <a href="https://docs.python.org/3.5/library/logging.html#logging.Logger.exception" rel="nofollow">the built-in module</a> which provides many facilities.</p>

python python-decorators