我(不是那样)是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就是我如何使用它。