检测具有空体的函数

时间:2016-05-30 03:33:08

标签: python python-2.7 python-3.x

我(不是那样)是python的新手,所以我想知道,这是检查函数或可调用函数是否为“空”的有效方法吗?

def _empty_impl():
    pass

def is_empty_impl(fn, pfn = None):
    empty = None
    pfn = pfn or []
    if isinstance(fn, type):
        fn = fn.__init__
        if fn == object.__init__:
            # We don't really know, though
            empty = True
    if not empty:
        if hasattr(fn, '__code__'):
            # Covers real functions.
            empty = _empty_impl.__code__.co_code == fn.__code__.co_code
        # keep searching for a concrete function
        elif hasattr(fn, '__call__'):
            # Prevents stack overflows when passing some builtins
            # or if someone has made some funny callable implementation
            if fn in pfn:
                raise Exception("loop detected")
            fn = fn.__call__
            pfn.append(fn)
            empty = is_empty_impl(fn, pfn)
    if empty is None:
        raise Exception("object does not look like a function")
    return empty

“空”是指任何简单的仅传递函数实现,根据需要使用尽可能多的参数,并且在其正文中没有语句或表达式,就像在:

def empty_function():
    pass

我使用Python 2.7.11和3.5.1进行了一些测试(REPL优化!)。到目前为止,一切似乎都符合我的期望:

def _test(x):
    import sys
    try:
        return x()
    except:
        return "Exception: %s" % str(sys.exc_info()[1])

class A(object):
    def __call__(self): pass
    def empty(self): pass
    def not_empty(self): print("hello world")

class B(object):
    def __init__(self, x = 1): self._x = x
    def __call__(self): print("hello world")

class C(object):
    def __init__(self, *args, **kwargs): pass

_test(lambda: is_empty_impl(A))             # True
_test(lambda: is_empty_impl(A.empty))       # True
_test(lambda: is_empty_impl(A.not_empty))   # False
_test(lambda: is_empty_impl(A.__call__))    # True
_test(lambda: is_empty_impl(A()))           # True
_test(lambda: is_empty_impl(A().empty))     # True
_test(lambda: is_empty_impl(A().not_empty)) # False
_test(lambda: is_empty_impl(A().__call__))  # True
_test(lambda: is_empty_impl(B()))           # False
_test(lambda: is_empty_impl(B()))           # False
_test(lambda: is_empty_impl(C))             # True
_test(lambda: is_empty_impl(C()))           # 'Exception: object does not look like a function'
_test(lambda: is_empty_impl(int))           # True
_test(lambda: is_empty_impl(str))           # True
_test(lambda: is_empty_impl(tuple))         # True
_test(lambda: is_empty_impl(list))          # 'Exception: loop detected'
_test(lambda: is_empty_impl(dict))          # 'Exception: loop detected'

我知道这有多酷,但是有什么明显我可能会遗漏(例如__code__界面的稳定性),还是有更好的(pythonic?)方式来做到这一点?

修改

根据@ pvg的建议,我简化了实施。这是:

def _empty_impl():
    pass

def _is_empty_impl(fn, pfn = None):
    return _empty_impl.__code__.co_code == fn.__code__.co_code

对于我的用例,这就足够了。 Here就是我如何使用它。

0 个答案:

没有答案