Python中的descriptor中的一點疑問

2021-08-21 11:21:50 字數 2440 閱讀 8567

在我的印象中,類中的函式是可以有兩種呼叫方式的,如下:

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),得出了所想要的結果了呢!

python中 python中的 與

這一部分首先要理解python記憶體機制,python中萬物皆物件。對於不可變物件,改變了原來的值,其別名 變數名 繫結到了新值上面,id肯定會改變 對於可變物件,操作改變了值,id肯定會變,而 是本地操作,其值原地修改 對於 號操作,可變物件和不可變物件呼叫的都是 add 操作 對於 號操作,可變...

python中的物件 Python中的變數 物件

由於沒時間系統學習下python 只能見乙個問題 乙個問題了 一 初級 物件 關於python中的資料型別,今天重新認識了下。參考 首先,python中,物件才有型別,變數是沒有型別的,它只是物件的 引用 其次,python中物件被分為兩類 可更改物件和不可更改物件 包括numbers,string...

python中的引數傳遞 python中的引數傳遞

begin 前面在介紹python的六大資料型別的時候提到根據資料可變和不可變進行的資料型別分類 python3 的六個標準資料型別中 不可變資料 3 個 number 數字 string 字串 tuple 元組 可變資料 3 個 list 列表 dictionary 字典 set 集合 pytho...