2012-05-23 32 views
15

Có thể trang trí một hàm có điều kiện không. Ví dụ: tôi muốn trang trí chức năng foo() với chức năng hẹn giờ (timeit) chỉ thực hiện_performance_analysis là True (xem mã psuedo bên dưới).làm thế nào để làm một trang trí có điều kiện trong python 2.6

if doing_performance_analysis: 
    @timeit 
    def foo(): 
    """ 
    do something, timeit function will return the time it takes 
    """ 
    time.sleep(2) 
else: 
    def foo(): 
    time.sleep(2) 

Trả lời

20

Trang trí đơn giản gọi là trả lại thay thế, tùy chọn cùng chức năng, trình bao bọc hoặc một thứ gì đó hoàn toàn khác. Như vậy, bạn có thể tạo ra một trang trí có điều kiện:

class conditional_decorator(object): 
    def __init__(self, dec, condition): 
     self.decorator = dec 
     self.condition = condition 

    def __call__(self, func): 
     if not self.condition: 
      # Return the function unchanged, not decorated. 
      return func 
     return self.decorator(func) 

Bây giờ bạn có thể sử dụng nó như thế này:

@conditional_decorator(timeit, doing_performance_analysis) 
def foo(): 
    time.sleep(2) 
+0

Cảm ơn! Phần bình luận không định dạng, vì vậy tôi đã thêm mã mẫu vào thư trả lời gốc của bạn. Bạn có thể giải thích tại sao hàm thời gian không được gọi? – cfpete

+0

Trình trang trí được áp dụng tại thời điểm nhập, vì vậy các biến mẫu không được tư vấn tại thời điểm đó. Bạn sẽ phải viết một người trang trí khác cho điều đó, một người tự kiểm tra khi được gọi. Ngoài phạm vi cho định dạng Q và nhận xét này. :-) –

+0

Làm cách nào để sử dụng nó nếu tôi muốn sử dụng phương pháp này dựa trên lớp học, tức là các chế độ xem dựa trên Lớp Django. Ở đó chúng ta phải sử dụng 'method_decorator'. Làm thế nào để làm cho mã này tương thích với điều đó? – PythonEnthusiast

4

Làm thế nào về:

def foo(): 
    ... 

if doing_performance_analysis: 
    foo = timeit(foo) 

Tôi tưởng tượng bạn thậm chí có thể quấn này vào một trang trí rằng sẽ mất một lá cờ boolean và trang trí khác, và sẽ chỉ được áp dụng sau này nếu cờ được thiết lập để True :

def cond_decorator(flag, dec): 
    def decorate(fn): 
     return dec(fn) if flag else fn 
    return decorate 

@cond_decorator(doing_performance_analysis, timeit) 
def foo(): 
    ... 
9

Trình trang trí chỉ đơn giản là một chức năng được áp dụng cho một chức năng khác. Bạn có thể áp dụng nó theo cách thủ công:

def foo(): 
    # whatever 
    time.sleep(2) 

if doing_performance_analysis: 
    foo = timeit(foo) 
0

câu trả lời Blckknght là tuyệt vời nếu bạn muốn làm việc kiểm tra mỗi khi bạn gọi hàm, nhưng nếu bạn có một thiết lập mà bạn có thể đọc một lần và không bao giờ thay đổi, bạn có thể không muốn kiểm tra cài đặt mỗi khi chức năng trang trí được gọi. Trong một số trình nền tảng hiệu suất cao của chúng tôi tại nơi làm việc, tôi đã viết một trình trang trí kiểm tra tệp cài đặt một lần khi tệp python được tải lần đầu tiên và quyết định xem nó có nên bọc nó hay không.

Đây là một mẫu

def timed(f): 
    def wrapper(*args, **kwargs): 
     start = datetime.datetime.utcnow() 
     return_value = f(*args, **kwargs) 
     end = datetime.datetime.utcnow() 
     duration = end - start 

     log_function_call(module=f.__module__, function=f.__name__, start=__start__, end=__end__, duration=duration.total_seconds()) 
    if config.get('RUN_TIMED_FUNCTIONS'): 
     return wrapper 
    return f 

Giả sử log_function_call mà các bản ghi cuộc gọi của bạn đến một cơ sở dữ liệu, logfile, hoặc bất cứ điều gì và config.get đó ('RUN_TIMED_FUNCTIONS') kiểm tra cấu hình toàn cầu của bạn, sau đó thêm các trang trí @timed với một hàm sẽ kiểm tra một lần khi tải để xem liệu bạn có đang định thời gian trên máy chủ, môi trường, v.v. và nếu không thì nó sẽ không thay đổi việc thực thi hàm trên sản xuất hoặc các môi trường khác mà bạn quan tâm đến hiệu năng.

0
use_decorator = False 

class myDecorator(object): 
    def __init__(self, f): 
      self.f = f 

    def __call__(self): 
      print "Decorated running..." 
      print "Entering", self.f.__name__ 
      self.f() 
      print "Exited", self.f.__name__ 


def null(a): 
    return a 


if use_decorator == False : 
    myDecorator = null 


@myDecorator 
def CoreFunction(): 
    print "Core Function running" 

CoreFunction() 
Các vấn đề liên quan