【问题标题】:How to distinguish between function and a method in decorator如何区分装饰器中的函数和方法
【发布时间】:2015-10-06 01:54:14
【问题描述】:

我正在尝试编写装饰器来完成不同的工作,具体取决于它是装饰方法还是函数。

我尝试过这样的事情:

def dec(f):
    def wrapper(*v, **kv):
        if '__class__' in dir(f):
            text = "Its a method"
        else:
            text = "Its a function"
        print(text)
        return f(*v, **kv)
    return wrapper


class A:

    @dec
    def f(self):
        pass

@dec
def f():
    pass

a = A()

a.f()
f()

返回:

Its a method
Its a method

但这不起作用,因为所有函数也都有__class__ 属性:) 我也尝试在 A.f 上执行inspect.ismethod,但 A.f 就像函数一样被对待,但在 A 命名空间中,它当然返回 false。如果我们完成了inspect.ismmethod(a.f),它将返回True,其中aA 的实例,但我等不及要实例了。

【问题讨论】:

  • 在装修时,你所拥有的只是一个功能。只有当查找名称是一个绑定到实例的函数并且你得到一个方法。
  • 换句话说,您可以将任何旧函数粘贴到一个类上,它将作为一个方法工作。在类加载时,类定义中没有任何内容使函数成为方法。
  • 函数上的__class__ 属性与您在其上定义的自定义类无关。
  • 因此,您无法检测到您是否在包装函数或方法。你为什么需要这个?您唯一可以确定的是,方法将有一个实例作为第一个参数传入。是的,这意味着您可以手动获取任何函数并传入实例,而您无法检测到差异。
  • 查看this答案

标签: python python-3.x


【解决方案1】:

正如 Martijn 在他的 cmets 中已经解释的那样,在类语句的主体中定义并不会使函数成为方法 - 方法对象是在查找时创建的,正如 here 所解释的那样 - 所以你正在装饰的是并且将会总是(几乎是下面的cf)是一个函数。 FWIW,Python 的“方法”只是函数、类和(最终)实例的薄包装。

除了函数之外,你可能会得到其他东西的唯一情况是类方法和静态方法(在这种情况下,你会得到一个 classmethodstaticmethod 对象),即使那样,它也取决于装饰器的顺序.

如果您想在装饰器中获取方法的当前实例(或类),您知道它将始终是第一个位置参数 - 但这可能没有太大帮助...长话短说,您必须明确告诉您的装饰器是否应该将函数视为普通函数或方法,或者用自定义描述符装饰它,在这种情况下,您将知道该函数是否已被查找为方法。 .. 一个简单的实现可能如下所示:

class MyDecorator(object):
    def __init__(self, func, instance=None):
        self.func = func
        self.instance = instance

    def __call__(self, *args, **kw):
        if self.instance:
            print "is method - instance : %s" % self.instance
            args = (self.instance,) + args
        else:
            print "is_function"

        return self.func(*args, **kw)

    def __get__(self, instance, cls):
        return type(self)(self.func, instance)

【讨论】:

  • 谢谢你,非常感谢 Martijn :)
猜你喜欢
  • 2011-06-06
  • 2016-07-04
  • 1970-01-01
  • 1970-01-01
  • 2021-04-16
  • 2014-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多