Trong câu hỏi ban đầu, bạn đã hỏi "Tại sao bạn muốn chuyển định nghĩa cho phương thức thông qua phương pháp khác?" Sau đó, trong một bình luận, bạn hỏi "Tại sao bạn không sửa đổi mã nguồn thực tế của phương thức?" Tôi thực sự nghĩ đó là một câu hỏi rất hay, và một câu hỏi khó trả lời mà không cần vẫy tay, bởi vì những người trang trí chỉ trở nên thực sự hữu ích khi mã của bạn đạt đến một mức độ phức tạp nhất định. Tuy nhiên, tôi nghĩ rằng điểm trang trí sẽ trở nên rõ ràng hơn nếu bạn xem xét hai chức năng sau:
def add_x_to_sequence(x, seq):
result = []
for i in seq:
result.append(i + x)
return result
def subtract_x_from_sequence(x, seq):
result = []
for i in seq:
result.append(i - x)
return result
Bây giờ, hai chức năng ví dụ có một số sai sót - trong thực tế đời sống, ví dụ, bạn muốn có lẽ chỉ viết lại chúng như là sự hiểu biết danh sách - nhưng chúng ta hãy bỏ qua những sai sót hiển nhiên cho thời điểm này, và giả vờ rằng chúng ta phải viết chúng theo cách này, như là for
vòng lặp qua chuỗi. Bây giờ chúng ta đối mặt với vấn đề hai chức năng của chúng tôi làm gần như điều tương tự, chỉ khác nhau tại một thời điểm chính. Điều đó có nghĩa là chúng ta đang lặp lại chính mình ở đây! Và đó là một vấn đề. Bây giờ chúng ta phải duy trì nhiều dòng mã hơn, để lại nhiều chỗ cho các lỗi xuất hiện, và nhiều chỗ cho các lỗi ẩn sau khi chúng xuất hiện.
Một cách tiếp cận cổ điển cho vấn đề này có thể là để tạo ra một chức năng mà mất một chức năng, và áp dụng nó trên một chuỗi, như thế này:
def my_map(func, x, seq):
result = []
for i in seq:
result.append(func(i, x))
return result
Bây giờ tất cả chúng ta phải làm là xác định funcs cụ thể để chuyển tới my_map
(đây thực sự chỉ là phiên bản chuyên dụng của chức năng tích hợp sẵn trong map
).
def sub(a, b):
return a - b
def add(a, b):
return a + b
Và chúng ta có thể sử dụng chúng như thế này:
added = my_map(sub, x, seq)
Nhưng phương pháp này có vấn đề của nó. Đó là một chút khó đọc hơn các chức năng độc lập ban đầu của chúng tôi, ví dụ; và mỗi lần chúng tôi muốn thêm hoặc trừ x
từ danh sách các mục, chúng tôi phải chỉ định hàm và giá trị làm đối số. Nếu chúng tôi làm điều này rất nhiều, chúng tôi muốn có một tên hàm duy nhất luôn đề cập đến cùng một hành động - điều đó sẽ cải thiện khả năng đọc và làm cho việc hiểu những gì đang xảy ra trong mã của chúng tôi trở nên dễ dàng hơn. Chúng tôi thể quấn trên trong khác chức năng ...
def add_x_to_sequence(x, seq):
return my_map(add, x, seq)
Nhưng bây giờ chúng tôi đang lặp lại mình một lần nữa!Và chúng tôi cũng đang tạo ra một sự gia tăng các chức năng, làm lộn xộn không gian tên của chúng ta.
Trang trí cung cấp cách thoát khỏi những vấn đề này. Thay vì chuyển hàm sang hàm khác mỗi lần, chúng tôi có thể chuyển hàm đó một lần. Đầu tiên chúng ta định nghĩa một hàm wrapper:
def vectorize(func):
def wrapper(x, seq):
result = []
for i in seq:
result.append(func(i, x))
return result
return wrapper
Bây giờ tất cả chúng ta phải làm là xác định một chức năng và vượt qua nó để ở trên, gói nó:
def add_x_to_sequence(a, b):
return a + b
add_x_to_sequence = vectorize(add_x_to_sequence)
Hoặc, sử dụng cú pháp trang trí:
@vectorize
def add_x_to_sequence(a, b):
return a + b
Bây giờ chúng tôi có thể viết nhiều hàm khác nhau vectorize
d và for
logic cho tất cả chúng xảy ra chỉ trong một pl át chủ. Bây giờ chúng tôi không phải sửa chữa hoặc tối ưu hóa nhiều chức năng khác nhau một cách riêng biệt; tất cả các lỗi liên quan đến vòng lặp của chúng tôi và tối ưu hóa liên quan đến vòng lặp xảy ra ở cùng một nơi; và chúng tôi vẫn nhận được tất cả các lợi ích dễ đọc của các chức năng được xác định đặc biệt.
Cảm ơn bạn rất nhiều vì sự giúp đỡ của bạn! Tôi đánh giá cao nó rõ ràng như thế nào. –