Python中的descriptor中的一点疑问

在我的印象中,类中的函数是可以有两种调用方式的,如下:

class B:
    def func(self):
        return 10

b = B()
b.func()
B.func(b)   

    于是,在之前研究descriptor的时候,我就有了几点困惑

    我将代码更换成了如下两个版本

版本1

import time


class LazyProperty(object):
    def __init__(self, func):
        self.func = func

    def __get__(self, instance, owner):
        if instance is None:
            return self
        else:
            value = owner.func(instance)
            setattr(instance, self.func.__name__, value)
            return value


class A:
    @LazyProperty
    def func(self):
        time.sleep(1)
        return 10

a = A()
print(a.func)

    这个版本出现的错误是:TypeError: 'LazyProperty' object is not callable。

    为什么会出现这个问题呢?

    由于instance不为None,所以会调用owner.func(instance)。

    也就是会调用A.func(a),但是呢A.func并不是一个函数,而是一个LazyProperty的实例。

    并且这个实例没有实现__call__方法,是不能像函数一样调用的。    

版本2    

import time


class LazyProperty(object):
    def __init__(self, func):
        self.func = func

    def __get__(self, instance, owner):
        value = owner.func(instance)
        setattr(instance, self.func.__name__, value)
        return value


class A:
    @LazyProperty
    def func(self):
        time.sleep(1)
        return 10

a = A()
print(a.func)

    表面上一看,这个应该和上个版本出现一样的问题。

    但是并不是和之前出现的是一样的错误。

    这次出现的错误是:RecursionError: maximum recursion depth exceeded

    这个是为什么呢?

    还记得我之前说的函数的调用是分为三步的吗?

    定义不用说了,现在就谈谈后面两步。

    owner.func(instance)

    在上面代码中的含义是不是A.func(a)?

    后面两步中的第一步就是找到这个A.func对象。

    记不记得A中的func其实是一个descriptor,并不是一个函数对象。

    所以A.func会返回什么呢?

    会返回descriptor中的__get__()返回的对象

    但是这个这个__get__()函数中的第一步是什么?

    对的,你没看错,还是这个owner.func(instance)。

    所以,还会继续寻找owner.func这个对象。

    有么有发现这是一个坑,会无限跳转下去?

    于是就有了错误,RecursionError: maximum recursion depth exceeded。

   终结,想要获取value值,不能通过别的方式。

    其实,还有一个问题,那就是为什么可以通过self.func(instance)来实现呢?

    想要调用类中的一个函数不是只有开头说的两个方式的吗?

    错了,错了。

    还是有第三种方式的。

    那就是在类中就调用,这个就和作用域一样了。

    在一个类中是可以直接调用其函数的。

    func = LazyProperty(func)

    其实可以换一种理解方式.

    lazyProperty = LazyProperty(func)

    要获取A.lazyProperty,就要通过__get__函数。

    然而,这个lazyProperty是不是在类A的内部。

    是不是就可以直接调用类A中定义的func方法。

    于是就是lazyProperty.func(instance),得出了所想要的结果了呢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值