Find Out If a Function has been Called

前端 未结 5 1283
遇见更好的自我
遇见更好的自我 2020-12-05 08:18

I am programming in Python, and I am wondering if i can test if a function has been called in my code

def example():
    pass
example()
#Pseudocode:
if exam         


        
相关标签:
5条回答
  • 2020-12-05 08:23

    If it's OK for the function to know its own name, you can use a function attribute:

    def example():
        example.has_been_called = True
        pass
    example.has_been_called = False
    
    
    example()
    
    #Actual Code!:
    if example.has_been_called:
       print("foo bar")
    

    You could also use a decorator to set the attribute:

    import functools
    
    def trackcalls(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            wrapper.has_been_called = True
            return func(*args, **kwargs)
        wrapper.has_been_called = False
        return wrapper
    
    @trackcalls
    def example():
        pass
    
    
    example()
    
    #Actual Code!:
    if example.has_been_called:
       print("foo bar")
    
    0 讨论(0)
  • 2020-12-05 08:25

    We can use mock.Mock

    from unittest import mock
    
    
    def check_called(func):
        return mock.Mock(side_effect=func)
    
    
    @check_called
    def summator(a, b):
        print(a + b)
    
    
    summator(1, 3)
    summator.assert_called()
    assert summator.called == True
    assert summator.call_count > 0
    
    summator.assert_called_with(1, 3)
    
    summator.assert_called_with(1, 5)  # error
    # AssertionError: Expected call: mock(1, 5)
    # Actual call: mock(1, 3)
    
    0 讨论(0)
  • 2020-12-05 08:30

    A minimal example using unittest.mock.Mock from the standard library:

    from unittest.mock import Mock
    
    def example():
        pass
    
    example_mock = Mock(side_effect=example)
    example_mock()
    #Pseudocode:
    if example_mock.called:
       print("foo bar")
    

    Console output after running the script:

    foo bar
    

    This approach is nice because it doesn't require you to modify the example function itself, which is useful if you want to perform this check in some unit-testing code, without modifying the source code itself (EG to store a has_been_called attribute, or wrap the function in a decorator).

    Explanation

    As described in the documentation for the unittest.mock.Mock class, the side_effect argument to the Mock() constructor specifies "a function to be called whenever the Mock is called".

    The Mock.called attribute specifies "a boolean representing whether or not the mock object has been called".

    The Mock class has other attributes you may find useful, EG:

    call_count: An integer telling you how many times the mock object has been called

    call_args: This is either None (if the mock hasn’t been called), or the arguments that the mock was last called with

    call_args_list: This is a list of all the calls made to the mock object in sequence (so the length of the list is the number of times it has been called). Before any calls have been made it is an empty list

    The Mock class also has convenient methods for making assert statements based on how many times a Mock object was called, and what arguments it was called with, EG:

    assert_called_once_with(*args, **kwargs): Assert that the mock was called exactly once and that that call was with the specified arguments

    0 讨论(0)
  • 2020-12-05 08:39

    Here's a decorator that will watch all your functiona, using colorama, and return a nice output.

    try:
        import colorama
    except ImportError:
        class StdClass: pass
        def passer(*args, **kwargs): pass
        colorama = StdClass()
        colorama.init = passer
        colorama.Fore = StdClass()
        colorama.Fore.RED = colorama.Fore.GREEN = ''
    
    def check_for_use(show=False):
        if show:
            try:
                check_for_use.functions
            except AttributeError:
                return
            no_error = True
            for function in check_for_use.functions.keys():
                if check_for_use.functions[function][0] is False:
                    print(colorama.Fore.RED + 'The function {!r} hasn\'t been called. Defined in "{}" '.format(function, check_for_use.functions[function][1].__code__.co_filename))
                    no_error = False
            if no_error:
                print(colorama.Fore.GREEN + 'Great! All your checked function are being called!')
            return check_for_use.functions
        try:
            check_for_use.functions
        except AttributeError:
            check_for_use.functions = {}
            if colorama:
                colorama.init(autoreset=True)
    
        def add(function):
            check_for_use.functions[function.__name__] = [False, function]
            def func(*args, **kwargs):
                check_for_use.functions[function.__name__] = [True, function]
                function(*args, **kwargs)
            return func
        return add
    
    @check_for_use()
    def hello():
        print('Hello world!')
    
    @check_for_use()
    def bonjour(nb):
        print('Bonjour tout le monde!')
    
    
    # hello(); bonjour(0)
    
    hello()
    
    
    check_for_use(True) # outputs the following
    
    Output:
    Hello world!
    The function 'bonjour' hasn't been called. Defined in "path_to_file.py" 
    
    0 讨论(0)
  • 2020-12-05 08:46

    Memoization functions have been around since the 1960s. In python you can use them as decorators on your example() function.

    The standard memoization function looks something like this:

    def memoize(func):
        memo = {}
        def wrapper(*args):
            if not args in memo:
                memo[args] = func(*args)
            return memo[args]
        return wrapper 
    

    and you decorate your function like this:

    @memoize
    def example():
        pass
    

    In python3.2, you can use the functools.lru_cache instead of the memoziation function.

    import functools
    
    @functools.lru_cache(maxsize=None)
    def example():
         pass
    
    0 讨论(0)
提交回复
热议问题