真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Python3.8中怎么實(shí)現(xiàn)一個(gè)functools.cached_property功能

這篇文章將為大家詳細(xì)講解有關(guān)Python 3.8中怎么實(shí)現(xiàn)一個(gè)functools.cached_property功能,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。

我們一直強(qiáng)調(diào)成都做網(wǎng)站、網(wǎng)站設(shè)計(jì)對(duì)于企業(yè)的重要性,如果您也覺得重要,那么就需要我們慎重對(duì)待,選擇一個(gè)安全靠譜的網(wǎng)站建設(shè)公司,企業(yè)網(wǎng)站我們建議是要么不做,要么就做好,讓網(wǎng)站能真正成為企業(yè)發(fā)展過程中的有力推手。專業(yè)網(wǎng)站建設(shè)公司不一定是大公司,創(chuàng)新互聯(lián)作為專業(yè)的網(wǎng)絡(luò)公司選擇我們就是放心。

bottle.cached_property

Bottle是我最早接觸的Web框架,也是我第一次閱讀的開源項(xiàng)目源碼。最早知道 cached_property 就是通過這個(gè)項(xiàng)目,如果你是一個(gè)Web開發(fā),我不建議你用這個(gè)框架,但是源碼量少,值得一讀。

werkzeug.utils.cached_property

Werkzeug是Flask的依賴,是應(yīng)用 cached_property 最成功的一個(gè)項(xiàng)目。

pip._vendor.distlib.util.cached_property

PIP是Python官方包管理工具。

kombu.utils.objects.cached_property

Kombu是Celery的依賴。

django.utils.functional.cached_property

Django是知名Web框架,你肯定聽過。

甚至有專門的一個(gè)包: pydanny/cached-property。

如果你犯過他們的代碼其實(shí)大同小異,在我的觀點(diǎn)里面這種輪子是完全沒有必要的。Python 3.8給 functools 模塊添加了 cached_property 類,這樣就有了官方的實(shí)現(xiàn)了。

PS: 其實(shí)這個(gè)Issue 2014年就建立了,5年才被Merge!

Python 3.8的cached_property

借著這個(gè)小章節(jié)我們了解下怎么使用以及它的作用(其實(shí)看名字你可能已經(jīng)猜出來):

./python.exe

Python 3.8.0a4+ (heads/master:9ee2c264c3, May 28 2019, 17:44:24)

[Clang 10.0.0 (clang-1000.11.45.5)] on darwin

Type "help", "copyright", "credits" or "license" for more information.

>>> from functools import cached_property

>>> class Foo:

... @cached_property

... def bar(self):

... print('calculate somethings')

... return 42

...

>>> f = Foo()

>>> f.bar

calculate somethings

42

>>> f.bar

42

上面的例子中首先獲得了Foo的實(shí)例f,第一次獲得 f.bar 時(shí)可以看到執(zhí)行了bar方法的邏輯(因?yàn)閳?zhí)行了print語句),之后再獲得 f.bar 的值并不會(huì)在執(zhí)行bar方法,而是用了緩存的屬性的值。

標(biāo)準(zhǔn)庫中的版本還有一種的特點(diǎn),就是加了線程鎖,防止多個(gè)線程一起修改緩存。通過對(duì)比Werkzeug里的實(shí)現(xiàn)幫助大家理解一下:

import time

from threading import Thread

from werkzeug.utils import cached_property

class Foo:

def __init__(self):

self.count = 0

@cached_property

def bar(self):

time.sleep(1) # 模仿耗時(shí)的邏輯,讓多線程啟動(dòng)后能執(zhí)行一會(huì)而不是直接結(jié)束

self.count += 1

return self.count

threads = []

f = Foo()

for x in range(10):

t = Thread(target=lambda: f.bar)

t.start()

threads.append(t)

for t in threads:

t.join()

這個(gè)例子中,bar方法對(duì) self.count 做了自增1的操作,然后返回。但是注意f.bar的訪問是在10個(gè)線程下進(jìn)行的,里面大家猜現(xiàn)在 f.bar 的值是多少?

ipython -i threaded_cached_property.py

Python 3.7.1 (default, Dec 13 2018, 22:28:16)

Type 'copyright', 'credits' or 'license' for more information

IPython 7.5.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: f.bar

Out[1]: 10

結(jié)果是10。也就是10個(gè)線程同時(shí)訪問 f.bar ,每個(gè)線程中訪問時(shí)由于都還沒有緩存,就會(huì)給 f.count 做自增1操作。第三方庫對(duì)于這個(gè)問題可以不關(guān)注,只要你確保在項(xiàng)目中不出現(xiàn)多線程并發(fā)訪問場(chǎng)景即可。但是對(duì)于標(biāo)準(zhǔn)庫來說,需要考慮的更周全。我們把 cached_property 改成從標(biāo)準(zhǔn)庫導(dǎo)入,感受下:

./python.exe

Python 3.8.0a4+ (heads/master:8cd5165ba0, May 27 2019, 22:28:15)

[Clang 10.0.0 (clang-1000.11.45.5)] on darwin

Type "help", "copyright", "credits" or "license" for more information.

>>> import time

>>> from threading import Thread

>>> from functools import cached_property

>>>

>>>

>>> class Foo:

... def __init__(self):

... self.count = 0

... @cached_property

... def bar(self):

... time.sleep(1)

... self.count += 1

... return self.count

...

>>>

>>> threads = []

>>> f = Foo()

>>>

>>> for x in range(10):

... t = Thread(target=lambda: f.bar)

... t.start()

... threads.append(t)

...

>>> for t in threads:

... t.join()

...

>>> f.bar

可以看到,由于加了線程鎖, f.bar 的結(jié)果是正確的1。

cached_property不支持異步

除了 pydanny/cached-property 這個(gè)包以外,其他的包都不支持異步函數(shù):

./python.exe -m asyncio

asyncio REPL 3.8.0a4+ (heads/master:8cd5165ba0, May 27 2019, 22:28:15)

[Clang 10.0.0 (clang-1000.11.45.5)] on darwin

Use "await" directly instead of "asyncio.run()".

Type "help", "copyright", "credits" or "license" for more information.

>>> import asyncio

>>> from functools import cached_property

>>>

>>>

>>> class Foo:

... def __init__(self):

... self.count = 0

... @cached_property

... async def bar(self):

... await asyncio.sleep(1)

... self.count += 1

... return self.count

...

>>> f = Foo()

>>> await f.bar

1

>>> await f.bar

Traceback (most recent call last):

File "/Users/dongwm/cpython/Lib/concurrent/futures/_base.py", line 439, in result

return self.__get_result()

File "/Users/dongwm/cpython/Lib/concurrent/futures/_base.py", line 388, in __get_result

raise self._exception

File "", line 1, in

RuntimeError: cannot reuse already awaited coroutine

pydanny/cached-property的異步支持實(shí)現(xiàn)的很巧妙,我把這部分邏輯抽出來:

try:

import asyncio

except (ImportError, SyntaxError):

asyncio = None

class cached_property:

def __get__(self, obj, cls):

...

if asyncio and asyncio.iscoroutinefunction(self.func):

return self._wrap_in_coroutine(obj)

...

def _wrap_in_coroutine(self, obj):

@asyncio.coroutine

def wrapper():

future = asyncio.ensure_future(self.func(obj))

obj.__dict__[self.func.__name__] = future

return future

return wrapper()

我解析一下這段代碼:

對(duì) import asyncio 的異常處理主要為了處理Python 2和Python3.4之前沒有asyncio的問題

__get__ 里面會(huì)判斷方法是不是協(xié)程函數(shù),如果是會(huì) return self._wrap_in_coroutine(obj)

_wrap_in_coroutine 里面首先會(huì)把方法封裝成一個(gè)Task,并把Task對(duì)象緩存在 obj.__dict__ 里,wrapper通過裝飾器 asyncio.coroutine 包裝最后返回。

為了方便理解,在IPython運(yùn)行一下:

In : f = Foo()

In : f.bar # 由于用了`asyncio.coroutine`裝飾器,這是一個(gè)生成器對(duì)象

Out: .wrapper at 0x10a26f0c0>

In : await f.bar # 第一次獲得f.bar的值,會(huì)sleep 1秒然后返回結(jié)果

Out: 1

In : f.__dict__['bar'] # 這樣就把Task對(duì)象緩存到了f.__dict__里面了,Task狀態(tài)是finished

Out: :4> result=1>

In : f.bar # f.bar已經(jīng)是一個(gè)task了

Out: :4> result=1>

In : await f.bar # 相當(dāng)于 await task

Out: 1可以看到多次await都可以獲得正常結(jié)果。如果一個(gè)Task對(duì)象已經(jīng)是finished狀態(tài),直接返回結(jié)果而不會(huì)重復(fù)執(zhí)行了。

關(guān)于Python 3.8中怎么實(shí)現(xiàn)一個(gè)functools.cached_property功能就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。


本文名稱:Python3.8中怎么實(shí)現(xiàn)一個(gè)functools.cached_property功能
URL鏈接:http://weahome.cn/article/jschoo.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部