2010-07-31 35 views
10

Có phải là "thực hành tốt" để tạo một lớp học như lớp dưới đây có thể xử lý quá trình ghi nhớ cho bạn không? Lợi ích của việc ghi nhớ rất tuyệt vời (trong một số trường hợp, như thế này, nó giảm từ 501003 xuống 1507 cuộc gọi hàm và từ 1.409 đến 0.006 giây của CPU trên máy tính của tôi) có vẻ như một lớp như thế này sẽ hữu ích.Trình xử lý ghi nhớ

Tuy nhiên, tôi chỉ đọc các nhận xét tiêu cực về cách sử dụng eval(). Việc sử dụng nó có thể tha thứ được không, do sự linh hoạt mà cách tiếp cận này cung cấp?

Điều này có thể tự động lưu bất kỳ giá trị trả lại nào với chi phí làm mất các tác dụng phụ. Cảm ơn.

import cProfile 

class Memoizer(object): 
    """A handler for saving function results.""" 
    def __init__(self): 
     self.memos = dict() 
    def memo(self, string): 
     if string in self.memos: 
      return self.memos[string] 
     else: 
      self.memos[string] = eval(string) 
      self.memo(string) 

def factorial(n): 
    assert type(n) == int 
    if n == 1: 
     return 1 
    else: 
     return n * factorial(n-1) 

# find the factorial of num 
num = 500 
# this many times 
times = 1000 

def factorialTwice(): 
    factorial(num) 
    for x in xrange(0, times): 
     factorial(num) 
    return factorial(num) 

def memoizedFactorial(): 
    handler = Memoizer() 
    for x in xrange(0, times): 
     handler.memo("factorial(%d)" % num) 
    return handler.memo("factorial(%d)" % num) 


cProfile.run('factorialTwice()') 

cProfile.run('memoizedFactorial()') 
+0

Bạn đang nói về "trình trang trí Python" và ghi nhớ là một cách sử dụng tuyệt vời cho chúng. Và nó không yêu cầu evals (mà là một phần xấu xa, bạn đã nghe chính xác). – msw

Trả lời

13

Bạn có thể ghi nhớ mà không cần phải sử dụng đến eval.

A (rất cơ bản) memoizer:

def memoized(f): 
    cache={} 
    def ret(*args): 
     if args in cache: 
      return cache[args] 
     else: 
      answer=f(*args) 
      cache[args]=answer 
      return answer 
    return ret 

@memoized 
def fibonacci(n): 
    if n==0 or n==1: 
     return 1 
    else: 
     return fibonacci(n-1)+fibonacci(n-2) 

print fibonacci(100) 
5

evalđược thường misspelt như evil chủ yếu là do ý tưởng thực hiện "chuỗi" trong thời gian chạy là đầy cân nhắc an ninh. Bạn đã thoát đủ mã chưa? Dấu ngoặc kép? Và một loạt các cơn đau đầu khó chịu khác. Trình xử lý memoise của bạn hoạt động nhưng nó thực sự không phải là cách làm việc của Python. Cách tiếp cận của MAK là nhiều hơn Pythonic. Hãy thử một vài thí nghiệm.

Tôi đã chỉnh sửa cả hai phiên bản và làm cho chúng chạy một lần với 100 làm đầu vào. Tôi cũng đã chuyển ra bản sao của Memoizer. Đây là kết quả.

>>> timeit.timeit(memoizedFactorial,number=1000) 
0.08526921272277832h 
>>> timeit.timeit(foo0.mfactorial,number=1000) 
0.000804901123046875 

Ngoài ra, phiên bản của bạn cần có một hàm bao quanh hàm được ghi nhớ phải được viết bằng một chuỗi. Đó là xấu xí. Giải pháp của MAK là sạch vì "quá trình memoisation" được đóng gói trong một chức năng riêng biệt có thể được áp dụng thuận tiện cho bất kỳ chức năng đắt tiền trong một thời trang không phô trương. Đây không phải là rất Pythonic. Tôi có một số chi tiết về cách viết trang trí như vậy trong hướng dẫn Python của tôi tại http://nibrahim.net.in/self-defence/ trong trường hợp bạn quan tâm.

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