Tải bản đầy đủ (.docx) (11 trang)

Decorator function xử lý ảnh

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (69.92 KB, 11 trang )

DECORATOR FUNCTION
Decorator functon, môt trong nhưng khai niêm phưc tap nhât va hưu dung nhât
trong lâp trinh Python. Nơi dung:


Decorator trong Python la gi va tac dung



Cach định nghĩa cac decorator



Ví du



Viết code tốt hơn bằng decorator

Giới thiệu
1 @decorator
2 def functon_to_decorate():
3

pass

Tiền tố @. Cac decorator đặc biệt hưu ích trong việc giư code không bị lặp lại, va
chúng lam điều đó nhưng đồng thời cũng cải thiện khả năng đọc của code vi
decorator chỉ la cac ham Python.

01 def x_plus_2(x):


02

return x + 2

03
04 print(x_plus_2(2))

# 2 + 2 ==4

05 def x_squared(x):
06

return x * x

07 print(x_squared(3))

# 3 ^ 2 == 9

08
09 # Let's compose the two functons for x=2


10
11
12 print(x_squared(x_plus_2(2)))

# (2 + 2) ^ 2 == 16

13 print(x_squared(x_plus_2(3)))


# (3 + 2) ^ 2 == 25

14 print(x_squared(x_plus_2(4)))

# (4 + 2) ^ 2 == 36

15
16
Tao ra một ham khac, ham x_plus_2_squared
1

x_squared(x_plus_2) # TypeError: unsupported operand type(s) for *:
'functon' and 'functon'

Không thể tổ hợp cac ham bằng cach nay bởi vi cả hai ham đều nhận cac con số
như la cac đối số:
1
2

# Let's now create a proper functon compositon without actually applying the
functon
x_plus_2_squared = lambda x: x_squared(x_plus_2(x))

3
4
5
6

print(x_plus_2_squared(2)) # (2 + 2) ^ 2 == 16
print(x_plus_2_squared(3)) # (3 + 2) ^ 2 == 25

print(x_plus_2_squared(4)) # (4 + 2) ^ 2 == 36

Định nghĩa lai cach ham x_squared lam việc:
1.

Châp nhận một ham như một đối số

2.

Trả về một ham khac

Đăt tên tên ham có thể tai tổ hợp của x_squared đơn giản la squared.


1 def squared(func):
2

return lambda x: func(x) * func(x)

3
4 print(squared(x_plus_2)(2)) # (2 + 2) ^ 2 == 16
5 print(squared(x_plus_2)(3)) # (3 + 2) ^ 2 == 25
6 print(squared(x_plus_2)(4)) # (4 + 2) ^ 2 == 36
Bây giờ có thể sử dung nó với bât kỳ ham nao khac. Dưới đây la một số ví du:
1 def x_plus_3(x):
2

return x + 3

3

4 def x_tmes_2(x):
5

return x * 2

6
7 print(squared(x_plus_3)(2)) # (2 + 3) ^ 2 == 25
8 print(squared(x_tmes_2)(2)) # (2 * 2) ^ 2 == 16
Có thể nói rằng ham squared decorate cac ham x_plus_2, x_plus_3 va x_tmes_2.
1
2

x_plus_2 = squared(x_plus_2) # We decorated x_plus_2 with squared
print(x_plus_2(2))
(2 + 2) ^ 2

01 def x_plus_2(x):
02
03

return x + 2

# x_plus_2 now returns the decorated squared result:


04 x_plus_2 = squared(x_plus_2)
05
06 # ^ This is completely equivalent with:
07
08 @squared

09 def x_plus_2(x):
10

return x + 2

Ký hiệu @ la một hinh thưc cú phap dễ đọc:
01
02
03

@squared
def x_tmes_3(x):
return 3 * x

04
05
06

print(x_tmes_3(2)) # (3 * 2) ^ 2 = 36.
# It might be a bit confusing, but by decoratng it with squared, x_tmes_3
became in fact (3 * x) * (3 * x)

07
08
09
10

@squared
def x_minus_1(x):
return x - 1


11
12

print(x_minus_1(3)) # (3 - 1) ^ 2 = 4

Xây dựng Decorator


Một decorator la một ham nhận một ham như la một đối số va trả về một ham
khac, định nghĩa decorator:
1 def decorator(functon_to_decorate):
2

# ...

3

return decorated_functon

Có thể định nghĩa cac ham bên trong cac ham khac. Trong hầu hết cac trường
hợp, decorated_functon sẽ được định nghĩa bên trong decorator.
1
2
3
4

def decorator(functon_to_decorate):
def decorated_functon(*args, **kwargs):
# ... Since we decorate `functon_to_decorate`, we should use it

somewhere inside here
return decorated_functon

01 import pytz
02 from datetme import datetme
03
04 def to_utc(functon_to_decorate):
05

def decorated_functon():

06

# Get the result of functon_to_decorate and transform the result to UTC

07

return functon_to_decorate().astmezone(pytz.utc)

08

return decorated_functon

09
10 @to_utc
11 def package_pickup_tme():


12
13

14

""" This can come from a database or from an API """
tz = pytz.tmezone('US/Pacific')
return tz.localize(datetme(2017, 8, 2, 12, 30, 0, 0))

15
16
17
18
19
20

@to_utc
def package_delivery_tme():
""" This can come from a database or from an API """
tz = pytz.tmezone('US/Eastern')
return tz.localize(datetme(2017, 8, 2, 12, 30, 0, 0)) # What a coincidence,
same tme different tmezone!

21
22
23

print("PICKUP: ", package_pickup_tme())

# '2017-08-02 19:30:00+00:00'

print("DELIVERY: ", package_delivery_tme()) # '2017-08-02 16:30:00+00:00'


Ví dụ Thực tế
Một trường hợp sử dung rât phổ biến va rât kinh điển khac đối với decorator la
lưu cache kết quả của một ham:
01 import tme
02
03 def cached(functon_to_decorate):
04

_cache = {} # Where we keep the results

05

def decorated_functon(*args):

06

start_tme = tme.tme()

07

print('_cache:', _cache)

08

if args not in _cache:


_cache[args] = functon_to_decorate(*args) # Perform the computaton
and store it in cache
09

10
11

print('Compute tme: %ss' % round(tme.tme() - start_tme, 2))
return _cache[args]
return decorated_functon

12
13
14
15
16
17

@cached
def complex_computaton(x, y):
print('Processing ...')
tme.sleep(2)
return x + y

18
19

print(complex_computaton(1, 2)) # 3, Performing the expensive operaton

20

print(complex_computaton(1, 2)) # 3, SKIP performing the expensive
21 operaton
22 print(complex_computaton(4, 5)) # 9, Performing the expensive operaton

23 print(complex_computaton(4, 5)) # 9, SKIP performing the expensive
operaton
24
print(complex_computaton(1, 2)) # 3, SKIP performing the expensive
operaton
Nếu ban nhin sơ qua code, ban có thể thây khó chịu. Decorator khơng thể sử dung
lai
được!
Nếu
chúng
ta
decorate
một
ham
khac
(gọi
la another_complex_computaton) va gọi nó với cac tham số tương tự thi chúng ta
sẽ nhận được cac kết quả được cache từ ham complex_computaton. Điều nay sẽ
khơng xảy ra. Decorator có thể sử dung lai va đây la lý do:


@cached
1 def another_complex_computaton(x, y):
2

print('Processing ...')

3

tme.sleep(2)


4

return x * y

5
6 print(another_complex_computaton(1, 2)) # 2, Performing the expensive
operaton
7
print(another_complex_computaton(1, 2)) # 2, SKIP performing the expensive
8
operaton
9
print(another_complex_computaton(1, 2)) # 2, SKIP performing the expensive
operaton
Ham chached được gọi một lần cho mỗi ham ma nó decorate, do đó, một
biến _cache khac được khởi tao mỗi lần va tồn tai trong ngư cảnh đó. Hãy thử
điều đó:
1 print(complex_computaton(10, 20))

# -> 30

2 print(another_complex_computaton(10, 20)) # -> 200
Decorator trong Thực tế
Decorator ma chúng ta vừa mớ viết, như ban có thể nhận thây, rât hưu ích. Nó
hưu ích đến nỗi một phiên bản phưc tap va manh mẽ hơn đã tồn tai trong mơ
đun functools têu chuẩn. Nó được đặt tên la lru_cache. LRU la viết tắt của Least
Recently Used, một ky thuât cahe.
01 from functools import lru_cache
02

03 @lru_cache()


04 def complex_computaton(x, y):
05

print('Processing ...')

06

tme.sleep(2)

07

return x + y

08
09 print(complex_computaton(1, 2)) # Processing ... 3
10 print(complex_computaton(1, 2)) # 3
11 print(complex_computaton(2, 3)) # Processing ... 5
12 print(complex_computaton(1, 2)) # 3
13 print(complex_computaton(2, 3)) # 5
Một trong nhưng trường hợp sử dung decorator la trong framework Flask. Nó thi
gọn gang, đó la đoan code điều đầu tên ban nhin thây trên trang web Flask. Đây
la đoan code đó:
01 from flask import Flask
02
03 app = Flask(__name__)
04
05 @app.route("/")

06 def hello():
07

return "Hello World!"

08
09 if __name__ == "__main__":
10

app.run()


Decorator app.route gan ham hello lam trinh xử lý yêu cầu cho tuyến "/". Thật sự
đơn giản.
Một cach sử dung decorator gọn gang khac la bên trong Django. Thông thường,
cac ưng dung web có hai kiểu trang:
1.

cac trang ban có thể xem ma không cần chưng thực (trang chủ, trang
landing, bai blog, đăng nhập, đăng ký)

2.

cac trang ban cần phải được chưng thực để xem (cai đặt tểu sử, hộp thư
đến, bảng điều khiển)

Nếu ban thử xem một kiểu trang thư hai, ban thường sẽ được chuyển hướng đến
một trang đăng nhập. Dưới đây la cach thực hiện điều đó trong Django:
01 from django.http import HttpResponse
02 from django.contrib.auth.decorators import login_required

03
04 # Public Pages
05
06 def home(request):
07

return HttpResponse("<b>Home</b>")

08
09 def landing(request):
10

return HttpResponse("<b>Landing</b>")

11
12 # Authentcated Pages
13
14 @login_required(login_url='/login')
15 def dashboard(request):
16

return HttpResponse("<b>Dashboard</b>")


17
18 @login_required(login_url='/login')
19 def profile_settings(request):
20

return HttpResponse("<b>Profile Settings</b>")


Quan sat xem cac chế độ view riêng tư gọn gang như thế nao được đanh dâu
bằng login_required. Khi xem qua code, nó rât rõ rang đối với người đọc ma cac
trang yêu cầu người dùng đăng nhập va nhưng trang khơng u cầu.
Phần tóm tắt
Tơi hy vọng ban đã có một buổi học thú vị về decorator bởi vi chúng đai diện cho
một tính năng rât gọn gang trong Python. Dưới đây la một số điều cần nhớ:


Sử dung va thiết kế decorator đúng cach có thể lam cho code của ban trở
nên tốt hơn, sach sẽ hơn va đẹp hơn.



Sử dung decorator có thể giúp ban DRY code—di chuyển cac code giống
nhau từ bên trong cac ham vao decorator.



Khi ban sử dung cac decorator nhiều hơn, ban sẽ thây nhưng cach tốt hơn,
phưc tap hơn để sử dung chúng.



×