Tôi đang cố gắng để hiểu, vá khỉ là gì hay vá khỉ là gì?
Đó có phải là một cái gì đó như phương thức / toán tử quá tải hoặc ủy thác?
Nó có bất cứ điều gì phổ biến với những điều này?
Tôi đang cố gắng để hiểu, vá khỉ là gì hay vá khỉ là gì?
Đó có phải là một cái gì đó như phương thức / toán tử quá tải hoặc ủy thác?
Nó có bất cứ điều gì phổ biến với những điều này?
Câu trả lời:
Không, nó không giống bất kỳ thứ gì trong số đó. Nó chỉ đơn giản là sự thay thế động của các thuộc tính trong thời gian chạy.
Ví dụ, hãy xem xét một lớp có một phương thức get_data
. Phương thức này thực hiện tra cứu bên ngoài (ví dụ trên cơ sở dữ liệu hoặc API web) và nhiều phương thức khác trong lớp gọi nó. Tuy nhiên, trong một thử nghiệm đơn vị, bạn không muốn phụ thuộc vào nguồn dữ liệu ngoài - vì vậy bạn tự động thay thế get_data
phương thức bằng một sơ khai trả về một số dữ liệu cố định.
Vì các lớp Python có thể thay đổi và các phương thức chỉ là thuộc tính của lớp, nên bạn có thể làm điều này bao nhiêu tùy thích - và trên thực tế, bạn thậm chí có thể thay thế các lớp và hàm trong một mô-đun theo cùng một cách.
Nhưng, như một nhà bình luận đã chỉ ra, hãy thận trọng khi bắt chước:
Nếu bất cứ điều gì khác ngoài logic kiểm tra của bạn get_data
cũng gọi, nó cũng sẽ gọi thay thế bản vá con khỉ của bạn chứ không phải là bản gốc - có thể là tốt hoặc xấu. Chỉ cần cẩn thận.
Nếu một số biến hoặc thuộc tính tồn tại cũng trỏ đến get_data
hàm khi bạn thay thế nó, bí danh này sẽ không thay đổi ý nghĩa của nó và sẽ tiếp tục trỏ đến bản gốc get_data
. (Tại sao? Python chỉ sắp xếp lại tên get_data
trong lớp của bạn với một số đối tượng hàm khác; các ràng buộc tên khác hoàn toàn không bị ảnh hưởng.)
pointing to the original get_data function
gì với ? Bạn có nghĩa là khi bạn lưu trữ một chức năng bên trong một biến nếu ai đó thay đổi chức năng đó, biến đó sẽ tiếp tục trỏ đến cái cũ?
get_data
, bạn đặt lại tên get_data
thành hàm giả. Nếu một số tên khác ở đâu đó trong chương trình bị ràng buộc với chức năng trước đây được biết đến như là get_data
, thì sẽ không có gì thay đổi đối với tên khác đó.
MonkeyPatch là một đoạn mã Python mở rộng hoặc sửa đổi mã khác khi chạy (thường là khi khởi động).
Một ví dụ đơn giản trông như thế này:
from SomeOtherProduct.SomeModule import SomeClass
def speak(self):
return "ook ook eee eee eee!"
SomeClass.speak = speak
Nguồn: trang MonkeyPatch trên wiki Zope.
Một bản vá khỉ là gì?
Nói một cách đơn giản, vá khỉ đang thực hiện các thay đổi cho một mô-đun hoặc lớp trong khi chương trình đang chạy.
Có một ví dụ về vá khỉ trong tài liệu của Pandas:
import pandas as pd
def just_foo_cols(self):
"""Get a list of column names containing the string 'foo'
"""
return [x for x in self.columns if 'foo' in x]
pd.DataFrame.just_foo_cols = just_foo_cols # monkey-patch the DataFrame class
df = pd.DataFrame([list(range(4))], columns=["A","foo","foozball","bar"])
df.just_foo_cols()
del pd.DataFrame.just_foo_cols # you can also remove the new method
Để phá vỡ điều này, đầu tiên chúng tôi nhập mô-đun của chúng tôi:
import pandas as pd
Tiếp theo, chúng ta tạo một định nghĩa phương thức, tồn tại không ràng buộc và miễn phí ngoài phạm vi của bất kỳ định nghĩa lớp nào (vì sự phân biệt khá vô nghĩa giữa một hàm và một phương thức không liên kết, Python 3 không sử dụng phương thức không liên kết):
def just_foo_cols(self):
"""Get a list of column names containing the string 'foo'
"""
return [x for x in self.columns if 'foo' in x]
Tiếp theo, chúng ta chỉ cần đính kèm phương thức đó vào lớp mà chúng ta muốn sử dụng nó trên:
pd.DataFrame.just_foo_cols = just_foo_cols # monkey-patch the DataFrame class
Và sau đó chúng ta có thể sử dụng phương thức trên một thể hiện của lớp và xóa phương thức khi chúng ta hoàn thành:
df = pd.DataFrame([list(range(4))], columns=["A","foo","foozball","bar"])
df.just_foo_cols()
del pd.DataFrame.just_foo_cols # you can also remove the new method
Nếu bạn đang sử dụng tính năng xáo trộn tên (thuộc tính tiền tố với dấu gạch dưới kép, làm thay đổi tên và tôi không khuyến nghị), bạn sẽ phải đặt tên theo cách thủ công nếu bạn thực hiện việc này. Vì tôi không khuyên bạn nên xáo trộn tên, tôi sẽ không trình bày nó ở đây.
Làm thế nào chúng ta có thể sử dụng kiến thức này, ví dụ, trong thử nghiệm?
Giả sử chúng ta cần mô phỏng cuộc gọi truy xuất dữ liệu đến nguồn dữ liệu bên ngoài dẫn đến lỗi, vì chúng tôi muốn đảm bảo hành vi chính xác trong trường hợp đó. Chúng ta có thể khỉ vá cấu trúc dữ liệu để đảm bảo hành vi này. (Vì vậy, sử dụng tên phương thức tương tự như được đề xuất bởi Daniel Roseman :)
import datasource
def get_data(self):
'''monkey patch datasource.Structure with this to simulate error'''
raise datasource.DataRetrievalError
datasource.Structure.get_data = get_data
Và khi chúng tôi kiểm tra hành vi đó dựa trên phương pháp này gây ra lỗi, nếu được thực hiện đúng, chúng tôi sẽ nhận được hành vi đó trong kết quả kiểm tra.
Chỉ cần thực hiện các thao tác trên sẽ thay đổi Structure
đối tượng trong vòng đời của quy trình, vì vậy bạn sẽ muốn sử dụng các thiết lập và phân tích trong các trường hợp không mong muốn của mình để tránh làm điều đó, ví dụ:
def setUp(self):
# retain a pointer to the actual real method:
self.real_get_data = datasource.Structure.get_data
# monkey patch it:
datasource.Structure.get_data = get_data
def tearDown(self):
# give the real method back to the Structure object:
datasource.Structure.get_data = self.real_get_data
(Trong khi ở trên là tốt, nó có lẽ là một ý tưởng tốt hơn để sử dụng mock
thư viện để vá các mã. mock
'S patch
trang trí sẽ ít lỗi hơn so với thực hiện ở trên, mà sẽ đòi hỏi nhiều dòng mã và do đó nhiều cơ hội để giới thiệu lỗi Tôi vẫn chưa xem lại mã mock
nhưng tôi tưởng tượng nó sử dụng phương pháp vá khỉ theo cách tương tự.)
Theo Wikipedia :
Trong Python, thuật ngữ khỉ chỉ dùng để sửa đổi động của một lớp hoặc mô-đun khi chạy, được thúc đẩy bởi ý định vá mã bên thứ ba hiện tại như một cách khắc phục lỗi hoặc tính năng không hoạt động như bạn mong muốn.
Đầu tiên: vá khỉ là một hack ác (theo ý kiến của tôi).
Nó thường được sử dụng để thay thế một phương thức ở cấp độ mô-đun hoặc lớp bằng cách thực hiện tùy chỉnh.
Usecase phổ biến nhất là thêm một cách giải quyết cho một lỗi trong mô-đun hoặc lớp khi bạn không thể thay thế mã gốc. Trong trường hợp này, bạn thay thế mã "sai" thông qua việc vá khỉ bằng cách triển khai bên trong mô-đun / gói của riêng bạn.
Khỉ vá chỉ có thể được thực hiện trong các ngôn ngữ động, trong đó python là một ví dụ tốt. Thay đổi một phương thức trong thời gian chạy thay vì cập nhật định nghĩa đối tượng là một ví dụ, tương tự, việc thêm các thuộc tính (cho dù phương thức hoặc biến) trong thời gian chạy được coi là vá khỉ. Chúng thường được thực hiện khi làm việc với các mô-đun mà bạn không có nguồn, sao cho các định nghĩa đối tượng không thể dễ dàng thay đổi.
Điều này được coi là xấu vì nó có nghĩa là định nghĩa của một đối tượng không mô tả hoàn toàn hoặc chính xác cách nó thực sự hoạt động.
Khỉ vá là mở lại các lớp hoặc phương thức hiện có trong lớp khi chạy và thay đổi hành vi, nên sử dụng một cách thận trọng, hoặc bạn chỉ nên sử dụng nó khi bạn thực sự cần.
Vì Python là ngôn ngữ lập trình động, Các lớp có thể thay đổi để bạn có thể mở lại chúng và sửa đổi hoặc thậm chí thay thế chúng.
Khỉ vá là gì? Khỉ vá là một kỹ thuật được sử dụng để tự động cập nhật hành vi của một đoạn mã trong thời gian chạy.
Tại sao nên dùng khỉ vá? Nó cho phép chúng ta sửa đổi hoặc mở rộng hành vi của các thư viện, mô-đun, lớp hoặc phương thức trong thời gian chạy mà không thực sự sửa đổi mã nguồn
Kết luận Khỉ vá là một kỹ thuật tuyệt vời và bây giờ chúng ta đã học cách làm điều đó trong Python. Tuy nhiên, như chúng ta đã thảo luận, nó có nhược điểm riêng và nên được sử dụng cẩn thận.
Để biết thêm thông tin Vui lòng tham khảo [1]: https://medium.com/@nagillavenkatesh1234/monkey-patching-in-python-explained-with-examples-25eed0aea505
Monkey patching is a technique to add, modify, or suppress the default behavior of a piece of code at runtime without changing its original source code.