Detecting empty function definitions in python

后端 未结 4 820
野的像风
野的像风 2021-02-20 01:37

I need to detect whether a function is an empty definition or not. It can be like:

def foo():
    pass

or like:

def foo(i, *arg         


        
相关标签:
4条回答
  • 2021-02-20 01:56

    Why would you do that? It looks like bad design. I would bet you wouldn't make anything faster.

    python -m timeit -s'def a(): pass' -s'def b(): pass' 'if a.__code__.co_code == b.__code__.co_code: pass'
    1000000 loops, best of 3: 0.293 usec per loop
    
    python -m timeit -s 'def a(): pass' -s 'def b(): pass' 'a()'
    10000000 loops, best of 3: 0.0941 usec per loop
    

    It seems like it is magnitude slower to compare than to just do call, because there were 10 times more loops in the latter timeit. The equals operator actually is surely calls a.code.co_code.eq. So you are just making things slower.

    0 讨论(0)
  • 2021-02-20 02:02

    The method you propose does not quite work because empty functions that have docstrings have a slightly different bytecode.

    The value of func.__code__.co_code for an empty function with no docstring is 'd\x00\x00S', while the value of it for a function with a docstring is 'd\x01\x00S'.

    For my purposes, it works just to add the additional case to test for:

    def isEmptyFunction(func):
        def empty_func():
            pass
    
        def empty_func_with_doc():
            """Empty function with docstring."""
            pass
    
        return func.__code__.co_code == empty_func.__code__.co_code or \
            func.__code__.co_code == empty_func_with_doc.__code__.co_code
    
    0 讨论(0)
  • 2021-02-20 02:05

    The way you're using works. A perhaps more "elegant" solution would be to have a list of functions, and in all your empty (or all your non-empty) functions you would add it to the list, and then check whether the function is in the list or not.

    0 讨论(0)
  • 2021-02-20 02:06

    To answer the original question: I don't think there is a better way, but definitely a more resilient one.

    Building on top of this answer by @kcon:

    def isEmptyFunction(func): 
        def empty_func(): 
            pass
    
        def empty_func_with_doc(): 
            """Empty function with docstring.""" 
            pass 
    
        return func.__code__.co_code == empty_func.__code__.co_code or \
            func.__code__.co_code == empty_func_with_doc.__code__.co_code
    

    which fails for the following:

    def not_empty_returning_string():
        return 'not empty'
    
    isEmptyFunction(just_return_string) # True
    

    as well as for lambdas:

    not_empty_lambda_returning_string = lambda x: 'not empty'
    
    isEmptyFunction(not_empty_lambda_returning_string) # True
    

    I built an extended version which also checks constants with the exception of docstrings:

    def is_empty_function(f):
        """Returns true if f is an empty function."""
    
        def empty_func():
            pass
    
        def empty_func_with_docstring():
            """Empty function with docstring."""
            pass
    
        empty_lambda = lambda: None
    
        empty_lambda_with_docstring = lambda: None
        empty_lambda_with_docstring.__doc__ = """Empty function with docstring."""
    
        def constants(f):
            """Return a tuple containing all the constants of a function without:
                * docstring
            """
            return tuple(
                x
                for x in f.__code__.co_consts
                if x != f.__doc__
            )
    
        return (
                f.__code__.co_code == empty_func.__code__.co_code and
                constants(f) == constants(empty_func)
            ) or (
                f.__code__.co_code == empty_func_with_docstring.__code__.co_code and
                constants(f) == constants(empty_func_with_docstring)
            ) or (
                f.__code__.co_code == empty_lambda.__code__.co_code and
                constants(f) == constants(empty_lambda)
            ) or (
                f.__code__.co_code == empty_lambda_with_docstring.__code__.co_code and
                constants(f) == constants(empty_lambda_with_docstring)
            )
    

    Testing:

    #
    # Empty functions (expect: is_empty_function(f) == True)
    #
    
    def empty():
        pass
    
    def empty_with_docstring():
        """this is just an example docstring."""
        pass
    
    empty_lambda = lambda: None
    
    empty_lambda_with_docstring = lambda: None
    empty_lambda_with_docstring.__doc__ = """this is just an example docstring."""
    
    #
    # Not empty functions (expect: is_empty_function(f) == False)
    #
    
    def not_empty():
        print('not empty');
    
    def not_empty_with_docstring():
        """this is just an example docstring."""
        print('not empty');
    
    not_empty_lambda = lambda: print('not empty')
    
    not_empty_lambda_with_docstring = lambda: print('not empty')
    not_empty_lambda_with_docstring.__doc__ = """this is just an example docstring."""
    
    #
    # Not empty functions returning a string (expect: is_empty_function(f) == False)
    #
    
    def not_empty_returning_string():
        return 'not empty'
    
    def not_empty_returning_string_with_docstring():
        return 'not empty'
    
    not_empty_lambda_returning_string = lambda: 'not empty'
    
    not_empty_lambda_returning_string_with_docstring = lambda: 'not empty'
    not_empty_lambda_returning_string_with_docstring.__doc__ = """this is just an example docstring."""
    
    
    all([
      is_empty_function(empty) == True,
      is_empty_function(empty_with_docstring) == True,
      is_empty_function(empty_lambda) == True,
      is_empty_function(empty_lambda_with_docstring) == True,
    
      is_empty_function(not_empty) == False,
      is_empty_function(not_empty_with_docstring) == False,
      is_empty_function(not_empty_lambda) == False,
      is_empty_function(not_empty_lambda_with_docstring) == False,
    
      is_empty_function(not_empty_returning_string) == False,
      is_empty_function(not_empty_returning_string_with_docstring) == False,
      is_empty_function(not_empty_lambda_returning_string) == False,
      is_empty_function(not_empty_lambda_returning_string_with_docstring) == False,
    
    ]) # == True
    
    0 讨论(0)
提交回复
热议问题