我想列出给定类中返回self
的所有方法。
我知道在Python中无法在运行之前检查函数的返回类型。
也许可以在函数体(源)中检查return self
还是有其他方法?
我需要它才能与Python 3.5及更高版本一起使用
编辑:
此类(不是完整的代码)是gremlinpython库的一部分。
class GraphTraversal(Traversal):
def __init__(self, graph, traversal_strategies, bytecode):
super(GraphTraversal, self).__init__(graph, traversal_strategies, bytecode)
def __getitem__(self, index):
if isinstance(index, int):
return self.range(long(index), long(index + 1))
elif isinstance(index, slice):
low = long(0) if index.start is None else long(index.start)
high = long(sys.maxsize) if index.stop is None else long(index.stop)
if low == long(0):
return self.limit(high)
else:
return self.range(low,high)
else:
raise TypeError("Index must be int or slice")
def __getattr__(self, key):
return self.values(key)
def V(self, *args):
self.bytecode.add_step("V", *args)
return self
def addE(self, *args):
self.bytecode.add_step("addE", *args)
return self
def addV(self, *args):
self.bytecode.add_step("addV", *args)
return self
它允许使用像这样的流利的API查询图形数据库
g.V().hasLabel('label').has('id','xxx').addE('relation').to(g.V().hasLabel('otherlabel').has('id','yyy')
到目前为止,我能够获得如下方法:
from inspect import getsourcelines, signature
def contains_return_self(f):
lines, _ = getsourcelines(f)
return any("return self" in line for line in lines)
def check_signature(f):
sig = signature(f)
if(len(sig.parameters) == 2
and 'self' in sig.parameters.keys()
and 'args' in sig.parameters.keys()):
return True
return False
fluent_methods = [
method_name for method_name in dir(GraphTraversal)
if callable(getattr(GraphTraversal, method_name))
and ('__' not in method_name)
and contains_return_self(getattr(GraphTraversal, method_name))
and check_signature(getattr(GraphTraversal, method_name))]
我想返回所有具有以下签名的方法:
def foo(self, *args)
# some code
return self
答案 0 :(得分:1)
尽管与@RafaelC一样,我强烈怀疑这很可能是XY Problem,但有些东西(部分基于inspect
模块)似乎可行(在这种方法的固有局限性内) 。为了进行测试,我添加了Traversal
基类的定义以及它和派生的GraphTraversal
类的一些不匹配方法。
from collections import namedtuple
import inspect
import re
class Traversal:
def inherited_method1(self, *args):
return self
def inherited_method2(self, foobar):
return foobar + 13
class GraphTraversal(Traversal):
def __init__(self, graph, traversal_strategies, bytecode):
super(GraphTraversal, self).__init__(graph, traversal_strategies, bytecode)
def __getitem__(self, index):
if isinstance(index, int):
return self.range(long(index), long(index + 1))
elif isinstance(index, slice):
low = long(0) if index.start is None else long(index.start)
high = long(sys.maxsize) if index.stop is None else long(index.stop)
if low == long(0):
return self.limit(high)
else:
return self.range(low,high)
else:
raise TypeError("Index must be int or slice")
def __getattr__(self, key):
return self.values(key)
def non_match1(self, *args):
self.bytecode.add_step("V", *args)
return 42
def non_match2(self, arg1, arg2):
self.bytecode.add_step("V", *args)
return self
def V(self, *args):
self.bytecode.add_step("V", *args)
return self
def addE(self, *args):
self.bytecode.add_step("addE", *args)
return self
def addV(self, *args):
self.bytecode.add_step("addV", *args)
return self
### Introspect class
DUNDER = re.compile(r"^_{2,}\w*_{2,}\Z", re.UNICODE)
MethInfo = namedtuple('MethInfo', ['name', 'value'])
methods = [MethInfo(*pair) for pair in inspect.getmembers(GraphTraversal, inspect.isfunction)
if not DUNDER.match(pair[0])]
def contains_return_self(meth_info):
src = inspect.getsource(meth_info.value)
for line in src.splitlines():
if 'return self' in line.strip():
return True
else:
return False
def check_signature(meth_info):
sig = inspect.signature(meth_info.value)
return str(sig) == '(self, *args)'
fluent_methods = [meth_info.name for meth_info in methods
if contains_return_self(meth_info) and check_signature(meth_info)]
print('fluent_methods:', fluent_methods)
输出:
fluent_methods: ['V', 'addE', 'addV', 'inherited_method1']