answer 39 Thay vào đó, bạn có thể sử dụng một @property trên
metaclass : class MyMetaClass(type):
@property
def my_data(cls):
if getattr(cls, '_MY_DATA', None) is None:
my_data = ... # costly database call
cls._MY_DATA = my_data
return cls._MY_DATA
class MyClass(metaclass=MyMetaClass):
# ...
Điều này tạo ra my_data một thuộc tính trên lớp, do đó, cuộc gọi cơ sở dữ liệu đắt tiền bị hoãn lại cho đến khi bạn cố gắng truy cập MyClass.my_data . Kết quả của lệnh gọi cơ sở dữ liệu được lưu vào bộ nhớ đệm bằng cách lưu trữ nó trong MyClass._MY_DATA , lệnh gọi chỉ được thực hiện một lần cho lớp. Đối với Python 2, hãy sử dụng class MyClass(object): và
thêm một __metaclass__ = MyMetaClass thuộc tính trong nội dung định nghĩa lớp để đính kèm siêu kính. Bản giới thiệu: >>> class MyMetaClass(type):
... @property
... def my_data(cls):
... if getattr(cls, '_MY_DATA', None) is None:
... print("costly database call executing")
... my_data = 'bar'
... cls._MY_DATA = my_data
... return cls._MY_DATA
...
>>> class MyClass(metaclass=MyMetaClass):
... pass
...
>>> MyClass.my_data
costly database call executing
'bar'
>>> MyClass.my_data
'bar'
Điều này hoạt động vì một bộ mô tả dữ liệu giống như property được tra cứu trên kiểu mẹ của một đối tượng; cho các lớp type và type có thể được mở rộng bằng cách sử dụng kính đo. 39 hữu ích 5 bình luận chia sẻ answer 11 Câu trả lời này chỉ dành cho thuộc tính / phương thức cá thể điển hình , không dành cho thuộc tính lớp / classmethod , hoặc staticmethod . Đối với Python 3.8+, làm thế nào về việc sử dụng trình
cached_property trang trí? Nó ghi nhớ. from functools import cached_property
class MyClass:
@cached_property
def my_lazy_attr(self):
print("Initializing and caching attribute, once per class instance.")
return 7**7**8
Đối với Python 3.2+, làm thế nào về việc sử dụng cả hai property và lru_cache decorator?
Bản ghi nhớ thứ hai. from functools import lru_cache
class MyClass:
@property
@lru_cache()
def my_lazy_attr(self):
print("Initializing and caching attribute, once per class instance.")
return 7**7**8
Tín dụng: câu trả lời của Maxime R. 11 hữu ích 0 bình luận chia sẻ answer 6 Một cách tiếp cận khác để làm cho mã sạch hơn là viết một hàm trình bao bọc thực hiện logic mong muốn: def memoize(f):
def wrapped(*args, **kwargs):
if hasattr(wrapped, '_cached_val'):
return wrapped._cached_val
result = f(*args, **kwargs)
wrapped._cached_val = result
return result
return wrapped
Bạn có thể sử dụng nó như sau: @memoize
def expensive_function():
print "Computing expensive function..."
import time
time.sleep(1)
return 400
print expensive_function()
print expensive_function()
print expensive_function()
Kết quả đầu
ra: Computing expensive function...
400
400
400
Bây giờ, classmethod của bạn sẽ trông như sau, ví dụ: class MyClass(object):
@classmethod
@memoize
def retrieve_data(cls):
print "Computing data"
import time
time.sleep(1) #costly DB call
my_data = 40
return my_data
print MyClass.retrieve_data()
print MyClass.retrieve_data()
print MyClass.retrieve_data()
Đầu ra: Computing data
40
40
40
Lưu ý rằng điều này sẽ chỉ lưu vào bộ nhớ cache một giá trị cho bất kỳ tập hợp đối số nào của hàm, vì vậy nếu bạn muốn tính các giá trị khác nhau tùy thuộc vào giá trị đầu vào, bạn sẽ phải thực hiện memoize phức tạp hơn một chút. 6 hữu ích 0 bình luận chia sẻ answer 0 Hãy xem xét Dickens gói có thể cài đặt bằng pip có sẵn cho Python 3.5+. Nó có một descriptors gói cung cấp các trình trang trí cachedproperty và có
liên quan cachedclassproperty , việc sử dụng chúng được hiển thị trong ví dụ bên dưới. Nó dường như hoạt động như mong đợi. from descriptors import cachedproperty, classproperty, cachedclassproperty
class MyClass:
FOO = 'A'
def __init__(self):
self.bar = 'B'
@cachedproperty
def my_cached_instance_attr(self):
print('Initializing and caching attribute, once per class instance.')
return self.bar * 2
@cachedclassproperty
def my_cached_class_attr(cls):
print('Initializing and caching attribute, once per class.')
return cls.FOO * 3
@classproperty
def my_class_property(cls):
print('Calculating attribute without caching.')
return cls.FOO + 'C'
0 hữu ích 0 bình luận
chia sẻ answer 0 Ring cung cấp lru_cache giao diện giống nhưng hoạt động với bất kỳ loại mô tả nào hỗ trợ:
https://ring-cache.readthedocs.io/en/latest/quickstart.html#method-classmethod-staticmethod
class Page(object):
(...)
@ring.lru()
@classmethod
def class_content(cls):
return cls.base_content
@ring.lru()
@staticmethod
def example_dot_com():
return requests.get('http://example.com').content
Xem các liên kết để biết thêm chi tiết. 0 hữu ích 0 bình luận chia sẻ |