__Gọi__ Trăn

Python đưa ra rất nhiều phương thức tích hợp có thể giúp chúng ta ghi đè hầu hết mọi thao tác với các đối tượng. Một trong những phương pháp đó là phương pháp __call__

Nếu chúng ta định nghĩa một phương thức __call__ thì nó cho phép chúng ta sử dụng thể hiện như một hàm

class Demo:
    def __init__[self]:
    	print['instantiated a class']

    def __call__[self]:
    	print['instance is called']
        
a = Demo[]
# instantiated a class


a[]
# instance is called

Trong ví dụ trên, chúng ta có thể gọi thể hiện của lớp Demo và sau đó sử dụng nó như một lời gọi hàm

Những lợi thế của việc sử dụng __call__ là gì?

  • Rất nhiều thư viện sử dụng phương pháp __call__ để triển khai giao diện rõ ràng cho API
  • Sử dụng __call__ cũng giúp bạn tận dụng tốt nhất cả hai thế giới nơi bạn đang sử dụng lợi thế OOP trong khi sử dụng cú pháp gọi hàm đơn giản
  • Có một câu trả lời tuyệt vời về StackOverflow được đề cập bên dưới làm nổi bật hầu hết các trường hợp sử dụng

Ví dụ thực tế về phương thức đặc biệt của Python __call__

Tôi biết rằng phương thức __call__ trong một lớp được kích hoạt khi thể hiện của một lớp được gọi. Tuy nhiên, tôi không biết khi nào tôi có thể sử dụng phương thức đặc biệt này, bởi vì người ta có thể chỉ cần tạo một phương thức mới và

Tên phương thức có dấu gạch dưới kép là tiền tố và hậu tố là các phương thức dành riêng cho mục đích sử dụng cụ thể trong Python. Ví dụ: phương thức __init__ được sử dụng cho hàm tạo đối tượng hoặc phương thức __call__ để tạo đối tượng có thể gọi được. Chúng tôi gọi các phương thức này là phương thức dunder, trong đó dunder đề cập đến Double Under [Dấu gạch dưới]. Những phương pháp dunder này còn được gọi là phương pháp ma thuật - Tuy nhiên, không có gì kỳ diệu liên quan đến chúng. Có nhiều nhà phát triển trong cộng đồng Python không thích từ 'ma thuật', vì nó mang lại cảm giác rằng việc sử dụng phương pháp này không được khuyến khích, nhưng thực tế lại hoàn toàn mâu thuẫn.

Hiểu chức năng có thể gọi

Đối tượng trong Python được gọi là có thể gọi được khi đối tượng đó được xác định trong hàm __call__[]. Hàm tương tự có thể được định nghĩa là x[arg 1, arg 2,…], viết tắt của x. __call__[arg1, arg2,…]

Ghi chú. Phương thức callable[] trả về giá trị Boolean cho biết đối tượng có thể gọi được hay không. Hàm này trả về True nếu đối tượng có thể gọi được; . Hơn nữa, cũng có khả năng hàm này có thể trả về True ngay cả khi đối tượng không thể gọi được. Tuy nhiên, nếu phương thức này trả về Sai, thì đối tượng không thể gọi được

Hơn nữa, một lớp Python luôn có thể gọi được. Do đó, chúng ta luôn có thể sử dụng hàm callable[] với một đối tượng của lớp chứ không phải chính lớp đó

Chúng ta hãy xem xét ví dụ sau để hiểu hành vi của hàm callable[] trong Python

Thí dụ

đầu ra

Employee Class is callable =  True
Employee object is callable =  False

Giải trình

Trong ví dụ trên, chúng ta đã định nghĩa một câu lệnh if trong đó nếu đối tượng m có thể gọi được, thì đối tượng đó được gọi dưới dạng một hàm không có đối số, chỉ có đối số, với hàm __call__[], với các đối số thuộc các loại khác nhau và có đối số . Kết quả là các đối tượng cần thiết đã được gọi thành công

Trước hết, bạn không bao giờ cần đến __call__ và đó thường không phải là giải pháp tốt nhất. Tuy nhiên, nó làm cho mã dễ đọc hơn nhiều trong một số ngữ cảnh. Đó là một giải pháp thay thế Pythonic độc đáo cho một số kỹ thuật lập trình chức năng và nó mang lại siêu năng lực cho việc tham số hóa

Mục tiêu của chúng tôi là tạo ra hai chức năng.

Employee Class is callable =  True
Employee object is callable =  False
1 và
Employee Class is callable =  True
Employee object is callable =  False
2;

# Functional programming style - just using functions, no classesdef send_welcome_message[send, user]:
message = f'Hey, {user.name}. You\'re my buddy.'
send[user, message]
# This implementation is pretty easy, no config
def send_via_stdout[user, message]:
print[f'[message to {user.name}]: {message}']
def send_welcome_message_via_stdout[user]:
send_welcome_message[send_via_stdout, user]
# This one needs a database connection to work
def send_via_db_with_connection[connection, user, message]:
cursor = connection.cursor[]
query = make_insert_message_query[user, message]
cur.execute[query]
# Create a send function using a db connection
def make_db_send_fn[conn]:
return lambda u, m: send_via_db_with_connection[conn, u, m]

# Somewhere in our app...
conn = db_client.connect["dbname='my_db' user='me' password='pw'"]
send_via_db = make_db_send_fn[conn]
def send_welcome_message_via_db[user]:
send_welcome_message[send_via_db, user]
# now we can use send_welcome_message_via_db and
# send_welcome_message_via_stdout interchangeably

Đây là một ví dụ mà __call__ sẽ giúp. Có nhiều mức tham số hóa tùy thuộc vào việc chúng ta chọn phiên bản cơ sở dữ liệu hay thiết bị xuất chuẩn. Mã phong cách lập trình chức năng hoàn toàn ổn, nhưng __call__ làm cho nó dễ đọc hơn rất nhiều

# OOP style, with __call__class Sender:
def send[self, user, message]:
raise NotImplementedError
def __call__[self, user, message]:
self.send[user, message]
class StdoutSender[Sender]:
def send[self, user, message]:
print[f'[message to {user.name}]: {message}']
class DatabaseSender[Sender]:
# inject the connection at runtime
def __init__[self, connection]:
self.connection = connection
def send[self, user, message]:
cursor = self.connection.cursor[]
query = make_insert_message_query[user, message]
cur.execute[query]
class UserMessageController:
# inject a Sender or a send function
def __init__[self, send]:
self.send = send
def send_welcome_message[self, user]:
message = f'Hey, {user.name}. You\'re my buddy.'
self.send[user, message]
send_via_stdout = StdoutSender[]conn = db_client.connect["dbname='my_db' user='me' password='pw'"]
send_via_db = DatabaseSender[conn]
stdout_controller = UserMessageController[send_via_stdout]
db_controller = UserMessageController[send_via_db]
# Now we can use our controllers interchangeably
# to send welcome messages
Tại sao __call__ dễ đọc hơn?

Cả phiên bản FP và OOP đều sử dụng bao đóng theo một cách nào đó. Các ứng dụng một phần là đóng cửa. Đối tượng là bao đóng. Tuy nhiên, phiên bản OOP tận dụng cú pháp Python

Employee Class is callable =  True
Employee object is callable =  False
5 và __call__ để làm cho các bao đóng này rõ ràng và thuận tiện hơn

Chúng ta có thể trao đổi các tham số chức năng để kế thừa và ứng dụng một phần cho các nhà xây dựng. Đó là một sự đánh đổi khôn ngoan trong Python, nhưng không phải trong tất cả các ngôn ngữ. Giải pháp FP có thể tốt hơn cho các ngôn ngữ có kiểu tốt hơn và các tiện ích của FP, như TypeScript. Tuy nhiên, Python có khả năng OOP tốt hơn nhiều và cộng đồng OOP tuyệt vời, vì vậy hãy tận dụng chúng

Khi nào tôi nên sử dụng __call__?

Hãy thận trọng khi nghĩ đến việc sử dụng __call__. Các chức năng hầu như luôn đơn giản hơn và thường dễ dàng hơn. Bạn có nguy cơ làm phức tạp mã của mình khi chọn sử dụng __call__

__ phương thức __ trong Python là gì?

__enter__ và __exit__ được sử dụng với khối 'with' trong python. __call__ method được sử dụng để sử dụng đối tượng làm phương thức . Phương thức __iter__ được sử dụng để tạo các đối tượng trình tạo bằng cách sử dụng đối tượng.

__ chứa __ trong Python là gì?

Chuỗi Python __contains__[] là một phương thức thể hiện và trả về giá trị boolean Đúng hoặc Sai tùy thuộc vào việc đối tượng chuỗi có chứa đối tượng chuỗi đã chỉ định hay không. Note that the Python string contains[] method is case sensitive.

Sự khác biệt giữa _ và __ trong Python là gì?

Dấu gạch dưới hàng đầu kép __var. Kích hoạt xáo trộn tên khi được sử dụng trong ngữ cảnh lớp. Được thực thi bởi trình thông dịch Python. Dấu gạch dưới đơn ở cuối var_. Được sử dụng theo quy ước để tránh xung đột đặt tên với các từ khóa Python. Dấu gạch dưới kép ở cuối __var__. Chỉ ra các phương thức đặc biệt được xác định bởi ngôn ngữ Python

__ phương thức trong Python được gọi là gì?

Các phương thức ma thuật trong Python là các phương thức đặc biệt bắt đầu và kết thúc bằng dấu gạch dưới kép. Chúng còn được gọi là phương pháp dunder .

Chủ Đề