Cài đặt thuộc tính lazy cho class trong Python
Python
43
White

kiennt viết ngày 27/05/2015

Thuộc tính lazy là gì?

Trước hết hãy xét tình huống sau:

Hệ thống backend của bạn có một User model. Mỗi một user được định danh bằng một access_token - là môt unique private string.
Khi client gửi request tới backend, client phải gửi kèm theo access_token.
Giờ nhiệm vụ của bạn là cần implement một APIRequest class, nhận đầu vào là một dictionary (gồm GET params and POST data của HTTP request). Trong APIRequest, bạn cần viết một hàm để xác định xem user nào đang thực hiện request.

Sau đây là một cách implement đơn giản

from app.models import User


class APIRequest(object):
    def __init__(self, data):
        self.data = data
        self.access_token = data.get("access_token")

    @property
    def user(self):
        user = User.find_user_by_access_token(self.access_token)
        return user

Trong đó, User.find_user_by_access_token sẽ thực hiện một query trong Database đề tìm ra user với access_token được truyền vào.

Sau khi implement hàm user xong, bạn nhận thấy, bạn muốn sử dụng hàm user này rất nhiều lần khi xử lý request của user. Nhưng mỗi lần gọi hàm user, việc gọi tới database là rất tốn chi phí, thế nên bạn sẽ muốn cache kết quả này lại.

Do đó, bạn chỉnh sửa lại hàm user như sau

    @property
    def user(self):
        if not hasattr(self, "_user"):
             self._user = User.find_user_by_access_token(self.access_token)
        return self._user

Bằng việc cached lại giá trị của user vào thuộc tính self._user, bạn sẽ chỉ cần query vào Database đúng lần đầu khi bạn gọi hàm APIRequest.user.

Thuộc tính user của APIRequest trong trường hợp này được gọi là lazy property (lazy nghĩa chỉ là chạy khi được gọi, và chỉ chạy đúng 1 lần)

Implement lazy property

Lazy property khá hữu dụng trong nhiều trường hợp. Tuy nhiên, việc lặp đi lặp lại cách implement khá là nhàm chán.

Bạn tưởng tượng, với mỗi một lazy property, chúng ta đều phải code những đoạn code như sau:

        if not hasattr(self,  "some_value"):
             self._some_value = do_something()
        return self._some_value

Bằng decorator, tôi sẽ implement một lazy property như sau

# file libs/decorators.py

def lazy(func):
    attr_name = "_lazy_%s" % func.__name__

    @property
    def wrapper(self):
        if not hasattr(self, attr_name):
            setattr(self, attr_name, func(self))
        return getattr(self, attr_name)

    @wrapper.setter
    def wrapper(self, value):
        setattr(self, attr_name, value)

    return wrapper

Với cách này, mỗi khi muốn sử dụng lazy property, tôi chỉ cần

from libs.decorators import lazy


class APIRequest(object):
     @lazy
     def user(self):
         return User.find_user_by_access_token(self.access_token)

Decorator rất là hữu dụng khi làm việc với Python.
Ngoài lazy property, decorator còn có nhiều ứng dụng khác.

Nếu muốn tìm hiểu thêm về các user cases của decorator, các bạn có thể tham khảo

  1. cách thư viện celery implement task decorators
  2. cách flask implement các decorators routes
Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

kiennt

30 bài viết.
288 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
93 18
Mọi chuyện bắt đầu từ nắm 2013 trong quá trình xây dựng chức năng login với Facebook, tôi đã tìm ra một cách để tấn công vào các hệ thống login với...
kiennt viết hơn 2 năm trước
93 18
White
64 4
Trong tuần vừa rồi, mình có đọc chương 7 cuốn sách (Link). Bài viết này nhằm mục đích giúp mình tổng hợp lại những kiến thức đã học được về chương ...
kiennt viết 6 tháng trước
64 4
White
29 5
1. Đặt vấn đề Một trong các vấn đề của một hệ thống backend là bài toán điều phối request tới các nguồn dữ liệu. Xét bài toán với một hệ thống bl...
kiennt viết 2 năm trước
29 5
Bài viết liên quan
White
1 0
Mở đầu Như đã nói ở bài trước, mình đang nghiên cứu về Spark nên cần log lại một số thứ để dành sau này dùng đến :smile: Đối tượng hướng đến vẫn ...
Phạm Quốc Thắng viết hơn 2 năm trước
1 0
White
5 3
Observer pattern (python example) 1. Observer là gì : Theo như (Link) Observer Pattern là : A software design pattern in which an object, calle...
Khôi Trọng Nguyễn viết 2 năm trước
5 3
White
0 0
Web Framework Flask định nghĩa route bằng annotations kiểu như @route('/users/add', methods='GET']) def user_add(): pass Lợi thế của cách là...
studybot viết 3 năm trước
0 0
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
30 bài viết.
288 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!