Python: 获取方法使用的属性列表
Python: Get a list of attributes used by a method
我想要一个 (Python 3.7+) 函数,给定一个 (class, method) 对,它会给我一个执行该方法所需的属性列表计算。
我知道一般情况下可能很难(甚至不可能)解决,所以我会凑合使用涵盖大多数情况的东西(如果无法安全处理的情况,我会很高兴可以检测到(并且用户对此发出警告))。
考虑以下几点:
def func(obj):
return obj.a + obj.b
class A:
e = 2
def __init__(self, a=0, b=0, c=1, d=10):
self.a = a
self.b = b
self.c = c
self.d = d
def target_method(self, x=3):
t = func(self)
tt = self.other_method(t)
return x * tt / self.e
def other_method(self, x=1):
return self.c * x
我想要的 attr_used_by_method
函数会做这样的事情:
>>> attr_used_by_method(cls=A, method_name='target_method')
['a', 'b', 'c', 'e']
因为:a
和b
是在对象传递给func
时使用的,c
是在other_method
方法中使用的,而self.e
用于计算 return 值。但是属性 d
对计算机 target_method
来说不是必需的,因此没有 returned。
我搜索了 inspect
和 trace
软件包,看它们是否可以完成工作,但看起来只有 ast
才能正确完成任务。
有 ast
书呆子吗?
对于上下文:我想要这样一个函数的原因是能够创建一个 "specialized json-serialization",它只会序列化执行对象的特定方法所需的那些属性。
您可以跟踪其他函数正在使用的变量并将它们存储在列表中,return 该列表由您命名的函数 "attr_used_by_method"
ast
module可以做到。如果我们假设源存储在名为 source
的变量中(可以从文件中读取):
import ast
root = ast.parse(source)
names = sorted({node.id for node in ast.walk(root) if isinstance(node, ast.Name)})
为了获得唯一性和友好的显示顺序而失去了顺序,但是如果您不需要唯一性但想要排序,您可以只使用列表理解或生成器表达式而不是集合理解。结果 list
是:
['a', 'b', 'c', 'do_something', 'f', 'myList', 'range', 'someMethod', 'something', 'x']
class Tracker:
"""
Tracks the attribute access right after `start_track` is set to True.
Add this to __metaclass__ for any class that you need to track attributes for given a
target method.
"""
attrs_to_ignore = []
attr_used = []
start_track = False
def __getattribute__(self, item):
"""
Inspect getter for tracking the attributes accessed.
"""
if item not in ['on_access']:
self.on_access(item)
return super().__getattribute__(item)
def __setattr__(self, key, value):
"""
Inspect setter for tracking the attributes accessed.
"""
if self.start_track:
self.on_access(key)
super().__setattr__(key, value)
def on_access(self, key):
"""
on attribute access, record attribute if and only if its not from
core attribute or `attrs_to_ignore` set to class.
"""
if key in ['start_track', 'attr_used', 'on_access', 'attrs_to_ignore'] or key in self.attrs_to_ignore:
return
if self.start_track:
self.attr_used.append(key)
def attr_used_by_method(cls, method_name, method_params):
"""
Tracks the access to attributes within an execution.
"""
# create meta class with the above tracker and `cls` from parameters.
tracker = type('Tracker', (Tracker, cls), dict(cls.__dict__, **Tracker.__dict__))()
tracker.attrs_to_ignore = [func for func in dir(tracker) if callable(getattr(tracker, func))]
if hasattr(tracker, method_name):
candidate_method = getattr(tracker, method_name)
# Now, we want to track attributes.
tracker.start_track = True
candidate_method(**method_params)
attr_used = tracker.attr_used.copy()
tracker.attr_used = []
return attr_used
else:
# Error class/obj do not have that method.
return 1
我想要一个 (Python 3.7+) 函数,给定一个 (class, method) 对,它会给我一个执行该方法所需的属性列表计算。
我知道一般情况下可能很难(甚至不可能)解决,所以我会凑合使用涵盖大多数情况的东西(如果无法安全处理的情况,我会很高兴可以检测到(并且用户对此发出警告))。
考虑以下几点:
def func(obj):
return obj.a + obj.b
class A:
e = 2
def __init__(self, a=0, b=0, c=1, d=10):
self.a = a
self.b = b
self.c = c
self.d = d
def target_method(self, x=3):
t = func(self)
tt = self.other_method(t)
return x * tt / self.e
def other_method(self, x=1):
return self.c * x
我想要的 attr_used_by_method
函数会做这样的事情:
>>> attr_used_by_method(cls=A, method_name='target_method')
['a', 'b', 'c', 'e']
因为:a
和b
是在对象传递给func
时使用的,c
是在other_method
方法中使用的,而self.e
用于计算 return 值。但是属性 d
对计算机 target_method
来说不是必需的,因此没有 returned。
我搜索了 inspect
和 trace
软件包,看它们是否可以完成工作,但看起来只有 ast
才能正确完成任务。
有 ast
书呆子吗?
对于上下文:我想要这样一个函数的原因是能够创建一个 "specialized json-serialization",它只会序列化执行对象的特定方法所需的那些属性。
您可以跟踪其他函数正在使用的变量并将它们存储在列表中,return 该列表由您命名的函数 "attr_used_by_method"
ast
module可以做到。如果我们假设源存储在名为 source
的变量中(可以从文件中读取):
import ast
root = ast.parse(source)
names = sorted({node.id for node in ast.walk(root) if isinstance(node, ast.Name)})
为了获得唯一性和友好的显示顺序而失去了顺序,但是如果您不需要唯一性但想要排序,您可以只使用列表理解或生成器表达式而不是集合理解。结果 list
是:
['a', 'b', 'c', 'do_something', 'f', 'myList', 'range', 'someMethod', 'something', 'x']
class Tracker:
"""
Tracks the attribute access right after `start_track` is set to True.
Add this to __metaclass__ for any class that you need to track attributes for given a
target method.
"""
attrs_to_ignore = []
attr_used = []
start_track = False
def __getattribute__(self, item):
"""
Inspect getter for tracking the attributes accessed.
"""
if item not in ['on_access']:
self.on_access(item)
return super().__getattribute__(item)
def __setattr__(self, key, value):
"""
Inspect setter for tracking the attributes accessed.
"""
if self.start_track:
self.on_access(key)
super().__setattr__(key, value)
def on_access(self, key):
"""
on attribute access, record attribute if and only if its not from
core attribute or `attrs_to_ignore` set to class.
"""
if key in ['start_track', 'attr_used', 'on_access', 'attrs_to_ignore'] or key in self.attrs_to_ignore:
return
if self.start_track:
self.attr_used.append(key)
def attr_used_by_method(cls, method_name, method_params):
"""
Tracks the access to attributes within an execution.
"""
# create meta class with the above tracker and `cls` from parameters.
tracker = type('Tracker', (Tracker, cls), dict(cls.__dict__, **Tracker.__dict__))()
tracker.attrs_to_ignore = [func for func in dir(tracker) if callable(getattr(tracker, func))]
if hasattr(tracker, method_name):
candidate_method = getattr(tracker, method_name)
# Now, we want to track attributes.
tracker.start_track = True
candidate_method(**method_params)
attr_used = tracker.attr_used.copy()
tracker.attr_used = []
return attr_used
else:
# Error class/obj do not have that method.
return 1