在python中嵌套描述符/装饰器 [英] Nesting descriptors/decorators in python

查看:72
本文介绍了在python中嵌套描述符/装饰器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我尝试嵌套描述符/装饰器时,我很难理解会发生什么.我使用的是 python 2.7.

I'm having a hard time understanding what happens when I try to nest descriptors/decorators. I'm using python 2.7.

例如,让我们采用以下propertyclassmethod的简化版本:

For example, let's take the following simplified versions of property and classmethod:

class MyProperty(object):
    def __init__(self, fget):
        self.fget = fget
    def __get__(self, obj, objtype=None):
        print 'IN MyProperty.__get__'
        return self.fget(obj)

class MyClassMethod(object):
    def __init__(self, f):
       self.f = f
    def __get__(self, obj, objtype=None):
        print 'IN MyClassMethod.__get__'
        def f(*args, **kwargs):
            return self.f(objtype, *args, **kwargs)
        return f

试图嵌套它们:

class A(object):
    # doesn't work:
    @MyProperty
    @MyClassMethod
    def klsproperty(cls):
        return 555
    # works:
    @MyProperty
    def prop(self):
        return 111
    # works:
    @MyClassMethod
    def klsmethod(cls, x):
        return x**2

% print A.klsproperty
IN MyProperty.__get__
...
TypeError: 'MyClassMethod' object is not callable

内部描述符 MyClassMethod__get__ 方法没有被调用.不知道为什么,我尝试加入(我认为是)一个无操作描述符:

The __get__ method of the inner descriptor MyClassMethod is not getting called. Failing to figure out why, I tried throwing in (what I think is) a no-op descriptor:

class NoopDescriptor(object):
    def __init__(self, f):
       self.f = f
    def __get__(self, obj, objtype=None):
        print 'IN NoopDescriptor.__get__'
        return self.f.__get__(obj, objtype=objtype)

尝试在嵌套中使用无操作描述符/装饰器:

Trying to use the no-op descriptor/decorator in nesting:

class B(object):
    # works:
    @NoopDescriptor
    @MyProperty
    def prop1(self):
        return 888
    # doesn't work:
    @MyProperty
    @NoopDescriptor
    def prop2(self):
        return 999

% print B().prop1
IN NoopDescriptor.__get__
IN MyProperty.__get__
888
% print B().prop2
IN MyProperty.__get__
...
TypeError: 'NoopDescriptor' object is not callable

我不明白为什么 B().prop1 有效而 B().prop2 无效.

I don't understand why B().prop1 works and B().prop2 does not.

问题:

  1. 我做错了什么?为什么我收到 object is not callable 错误?
  2. 正确的方法是什么?例如在重用 MyClassMethodMyProperty(或 classmethod 时定义 MyClassProperty 的最佳方法是什么?属性)
  1. What am I doing wrong? Why am I getting a object is not callable error?
  2. What's the right way? e.g. what is the best way to define MyClassProperty while re-using MyClassMethod and MyProperty (or classmethod and property)

推荐答案

如果您让 MyProperty 将描述符协议应用于其包装对象,您就可以使您的代码工作:

You can make your code work if you make MyProperty apply the descriptor protocol to its wrapped object:

class MyProperty(object):
    def __init__(self, fget):
        self.fget = fget
    def __get__(self, obj, objtype=None):
        print('IN MyProperty.__get__')
        try:
            return self.fget.__get__(obj, objtype)()
        except AttributeError: # self.fget has no __get__ method
            return self.fget(obj)

现在您的示例代码有效:

Now your example code works:

class A(object):
    @MyProperty
    @MyClassMethod
    def klsproperty(cls):
        return 555

print(A.klsproperty)

输出为:

IN MyProperty.__get__
IN MyClassMethod.__get__
555

这篇关于在python中嵌套描述符/装饰器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆