Python 使用decorator跟踪和返回方法
我试图定义一个装饰器,它将标记某些方法,然后稍后提供按方法调用所有标记方法的功能 下面这篇文章应该让我知道我希望所有的东西都是如何运作的,但是由于明显的原因,它没有功能Python 使用decorator跟踪和返回方法,python,python-3.x,Python,Python 3.x,我试图定义一个装饰器,它将标记某些方法,然后稍后提供按方法调用所有标记方法的功能 下面这篇文章应该让我知道我希望所有的东西都是如何运作的,但是由于明显的原因,它没有功能 def mark(method): # mark_methods should belong to the class wherein methods are being marked mark_methods.append(method) return method class BaseClass()
def mark(method):
# mark_methods should belong to the class wherein methods are being marked
mark_methods.append(method)
return method
class BaseClass():
# This should belong to each subclasses independently
marked_methods = []
def bundle(self):
data = {}
for marked_method in Person.marked_methods:
data[marked_method.__name___] = marked_method()
return data
class Person(BaseClass):
@mark
def name(self):
return 'Fred'
def say_hi(self):
return 'Hi'
class Dog(BaseClass):
@mark
def name(self):
return 'Fido'
@mark
def fur_color(self):
return 'Black'
def bark(self):
return 'Woof'
Person.marked_methods # => [name]
Person().bundle() # => {'name': 'Fred'}
Dog.marked_methods # => [name, fur_color]
Dog().bundle() # => {'name': 'Fido', 'fur_color': 'Black'}
理想情况下,此行为将被包装在一个类中,该类也可以被其他类继承
这是我正在寻找的一个版本,它在不使用装饰器的情况下表现出类似的行为。相反,它依赖于操作以某个前缀开始的函数
MARK_PREFIX = 'mark_'
class TrackingWithoutDecoratorClass():
@classmethod
def __init_subclass__(cls, **kwargs):
"""Tracks all methods added on init
"""
# Mapping of transformer names to transformer functions
cls.marked = {}
for name, func in vars(cls).items():
# Add all functions starting with the `MARK_PREFIX` to the
# marked registry
if name.startswith(MARK_PREFIX):
registry_name = name.replace(MARK_PREFIX, '')
cls.marked[registry_name] = func
class Example(TrackingWithoutDecoratorClass):
def mark_one(self):
return 1
def mark_two(self):
return 2
def not_marked_three(self):
return 3
print(Example.marked.keys())
以下是。我建议标记方法本身:
import inspect
def mark(func):
func.marked = True
return func
class Base():
@classmethod
def marked_methods(cls):
return [n for n, f in inspect.getmembers(cls) if hasattr(f, 'marked')]
def bundle(self):
return {m: getattr(self, m)() for m in self.marked_methods()}
class Person(Base):
@mark
def name(self):
return 'Fred'
def say(self):
return 'Hi'
class Dog(Base):
@mark
def name(self):
return 'Fido'
def bark(self):
return 'Woof'
@mark
def color(self):
return 'Black'
print(Person.marked_methods()) #=> ['name']
print(Person().bundle()) #=> {'name': 'Fred'}
print(Dog.marked_methods()) #=> ['color', 'name']
print(Dog().bundle()) #=> {'color': 'Black', 'name': 'Fido'}
诀窍是一旦目标类从基类继承,就使用元类存储修饰的方法:
def mark(method):
method.marked = True
return method
class MarkTracking(type):
def __new__(cls, name, bases, attr):
marked = []
for obj in attr.values():
if hasattr(obj, 'marked'):
marked.append(obj)
attr['marked_methods'] = marked
return type.__new__(cls, name, bases, attr)
class BaseClass(metaclass=MarkTracking):
def bundle(self):
data = {}
for marked_method in self.__class__.marked_methods:
data[marked_method.__name__] = marked_method(self)
return data
class Person(BaseClass):
@mark
def name(self):
return 'Fred'
def say_hi(self):
return 'Hi'
class Dog(BaseClass):
@mark
def name(self):
return 'Fido'
@mark
def fur_color(self):
return 'Black'
def bark(self):
return 'Woof'
print(Person.marked_methods) # => [name]
print(Person().bundle()) # => {'name': 'Fred'}
print(Dog.marked_methods) # => [name, fur_color]
print(Dog().bundle()) # => {'name': 'Fido', 'fur_color': 'Black'}
Person不必存在,您可以从方法引用获取类。请看,这似乎在语义上有所不同,两次调用同一个方法只会在列表中出现一次。如果海报真的想要跟踪调用,这是行不通的。因此,虽然这实现了预期的行为,但实现要求您在调用标记的方法时迭代所有函数,并确定哪些被标记,而不是存储在某种注册表中。我在问题中添加了一个不使用装饰器的示例。