Python 如何将动态数据传递给装饰器

Python 如何将动态数据传递给装饰器,python,decorator,Python,Decorator,我正在尝试编写一个基本crud控制器类,它执行 以下: class BaseCrudController: model = "" field_validation = {} template_dir = "" @expose(self.template_dir) def new(self, *args, **kwargs) .... @validate(self.field_validation, error_handler=n

我正在尝试编写一个基本crud控制器类,它执行 以下:

class BaseCrudController:
    model = ""
    field_validation = {}
    template_dir = ""

    @expose(self.template_dir)
    def new(self, *args, **kwargs)
        ....

    @validate(self.field_validation, error_handler=new)
    @expose()
    def  post(self, *args, **kwargs):
        ...
我的目的是让我的控制器扩展这个基类,设置 模型、现场验证和模板位置,我已准备就绪

不幸的是,装饰师(据我所知)在 定义了该函数。因此,它将无法访问实例的 价值是否有方法从子系统传入动态数据或值 上课

例如:

class AddressController(BaseCrudController):
    model = Address
    template_dir = "addressbook.templates.addresses"
import functools

def expose(attname=None):
  if attname:
    def makewrapper(f):
      @functools.wraps(f)
      def wrapper(self, *a, **k):
        attvalue = getattr(self, attname, None)
        ...use attvalue as needed...
      return wrapper
    return makewrapper
  else:
    ...same but without the getattr...
当我尝试加载AddressController时,它说“未定义self”。我假设基类在初始化子类之前正在评估decorator

谢谢,
Steve

使用工厂创建类可能比子类化更好:

def CrudControllerFactory(model, field_validation, template_dir):
    class BaseCrudController:
        @expose(template_dir)
        def new(self, *args, **kwargs)
            ....

        @validate(field_validation, error_handler=new)
        @expose()
        def  post(self, *args, **kwargs):
            ....

    return BaseCrudController
不幸的是,装饰师(对我来说) 理解),当 定义了该函数。因此 无法访问实例的值。 有没有办法传入动态数据 或者来自子类的值

需要使用相关属性的名称调用模板;然后包装器可以动态地获取该属性的值。例如:

class AddressController(BaseCrudController):
    model = Address
    template_dir = "addressbook.templates.addresses"
import functools

def expose(attname=None):
  if attname:
    def makewrapper(f):
      @functools.wraps(f)
      def wrapper(self, *a, **k):
        attvalue = getattr(self, attname, None)
        ...use attvalue as needed...
      return wrapper
    return makewrapper
  else:
    ...same but without the getattr...
请注意,复杂的原因只是,从Q中的代码片段判断,您希望允许
expose
装饰器与参数一起使用,也可以不使用参数(如果attname保护在
包装中,您可以移动
,但是在每次调用时重复检查是无用的——我想,在这两种情况下,包装中的代码可能也需要非常不同——因此,将两个不同的控制流塞入一个包装中可能会更加复杂)顺便说一句,这是一个可疑的设计决策,IMHO。但是,它与您关于“动态数据”的实际Q完全不同


关键是,通过使用属性名作为参数,您可以授权装饰程序在需要时“及时”动态获取值。可以将其视为“额外的间接层次”,这是解决编程中所有困难的广为人知的灵丹妙药!-)

有趣的想法。但这不会限制我扩展实际控制器的能力吗?我希望基本控制器能帮助我处理所有crud情况,并允许我向扩展基类的控制器添加功能。您必须像
class ExtendedClass(CrudControllerFactor(model,field\u validation,template\u dir)这样创建子类:
。如果希望对子类进行子类化,则可能会出现问题。只要在同一个文件中定义了值,我就可以设置该值:template\u dir=“address”@expose(template\u dir),但当我尝试这样做时:@expose(self.template\u dir)然后在子类中定义self.template\u dir,它说self未定义。我用一个例子编辑了我的Q。@steve,当然了:在模板执行时没有
self
。正如我所解释的,通过传递属性名,你可以获得额外的间接级别,并完全解决问题。我想我现在就得到了这个。所以我会我必须编写另一个@expose来覆盖现有的一个。调用@expose(attrname=“template_dir”),并编写一个包装器来计算template_dir的值?@steve,是的,大致上是这样,但是要小心在同一命名空间中有几个同名的对象:你不能!Python不支持C++之类的“重载”(不同的函数具有相同的名称,根据其类型和参数数量进行区分)。您可能希望为不同的功能使用不同的名称(这比将许多不同的功能塞进一个函数中要清楚得多)。