2013-10-21 14 views
8

Tôi đã cố gắng tìm hiểu trang trí Python và tôi đã cố gắng để viết một chương trình tương đương với này một:Python trang trí - __call__ trong lớp

class myDecorator(object): 
    def __init__(self, f): 
     print ("inside myDecorator.__init__()") 
     f() # Prove that function definition has completed 

    def __call__(self): 
     print ("inside myDecorator.__call__()") 

@myDecorator 
def aFunction(): 
    print ("inside aFunction()") 

print ("Finished decorating aFunction()") 

aFunction() 

Vấn đề là tôi không hiểu thế nào là phương pháp __call__ của lớp là được gọi bằng cách gọi số aFunction() cuối cùng.

aFunction() được thay thế bằng myDecorator.__call__(aFunction). Bạn có thể giúp tôi được không? Làm thế nào sẽ là một chương trình tương đương mà không có trang trí?

Cảm ơn!

Trả lời

8

Kết quả của mã của bạn là

inside myDecorator.__init__() 
inside aFunction() 
Finished decorating aFunction() 
inside myDecorator.__call__() 

Đầu tiên, bạn có biết, những gì @ trang trí cú pháp này nghĩa là gì?

@decorator 
def function(a): 
    pass 

chỉ là một cách khác để nói:

def function(a): 
    pass 
function = decorator(function) 

Vì vậy, trong trường hợp của bạn

@myDecorator 
def aFunction(): 
    print ("inside aFunction()") 

chỉ có nghĩa

def aFunction(): 
    print ("inside aFunction()") 
aFunction = myDecorator(aFunction) 

Lúc đầu, Bạn về cơ bản tạo ra một mới Ví dụ của lớp myDecorator, gọi đó là hàm tạo (__init__) và truyền cho nó một đối tượng hàm aFunction. Sau đó, nó thực hiện chức năng in và cho trước.Ngoài ra, lưu ý rằng điều này đang xảy ra trong khi chức năng được trình thông dịch tải, không phải khi nó được thực hiện, vì vậy trong trường hợp bạn nhập một cái gì đó từ tệp này, nó sẽ thực hiện sau đó, không sử dụng hoặc gọi.

Sau đó, thực hiện aFunction(), khi một chức năng vẫn đang tham chiếu đến cá thể myDecorator, làm cho nó gọi phương thức __call__ của myDecorator, thực thi. Lưu ý rằng f() có nghĩa là f.__call__(f) trong trường hợp này, như phương pháp __call__ được sử dụng để bật và ghi đè hành vi gọi của đối tượng mặc định (trong đơn giản, bất kỳ đối tượng nào đều có thể gọi khi phương thức được xác định là __call__).

Nếu bạn muốn thực hiện một chức năng khi nó được gọi, sau đó bạn nên gán nó cho biến mẫu trong __init__ và gọi nó trong __call__ của myDecorator.

1

afunction đang được thay thế bằng một phiên bản của lớp myDecorator. Lớp này có phương thức __call__, do đó, thể hiện có thể được gọi là hàm. Vì vậy, giả sử chữ ký của nó là tương thích (thường là một trang trí trả về một cái gì đó sử dụng *args**kwargs), ví dụ có thể được sử dụng như là một thay thế cho các chức năng ban đầu.

Thông thường, phương thức __call__ sẽ gọi hàm được bao bọc. Thực hiện nó trong __init__ thường không chính xác; __init__ nên lưu trữ tham chiếu đến hàm được bao bọc dưới dạng thuộc tính đối tượng, để __call__ có thể gọi nó.

1

Đó là toàn bộ mục đích của trình trang trí: để thay thế (hoặc, thường xuyên hơn, bọc) một hàm có hàm trả về bởi trình trang trí. Trong trường hợp của bạn, aFunction đang được thay thế bằng một phiên bản myDecorator, vì vậy khi bạn gọi aFunction() bạn thực sự đang gọi trường hợp đó: và bằng Python, gọi một cá thể lớp gọi phương thức __call__ của nó.

Xác định một chức năng trang trí là chính xác tương đương như sau:

def aFunction(): 
    print("inside aFunction()") 
aFunction = myDecorator(aFunction) 

Thông thường, tất nhiên, các gói chức năng sẽ gọi hàm ban đầu sau khi làm bất cứ điều gì nó làm.

1

Dưới đây là cách khắc phục:

class myDecorator(object): 
    def __init__(self, f): 
     print ("inside myDecorator.__init__()") 
     self.f = f #Store the function being wrapped 

    def __call__(self): 
     print ("inside myDecorator.__call__()") 
     self.f() # Call the wrapped function 
+0

để chấp nhận hàm của args sử dụng def __call __ (self, * args, ** kwargs): và chuyển chúng thành f – theannouncer

Các vấn đề liên quan