2012-03-24 50 views
5

Tôi đang tạo một số đối tượng từ tệp (trình xác thực từ tệp xsd mẫu, để vẽ cùng các tệp xsd khác, vì nó xảy ra) và tôi muốn tạo lại các đối tượng khi tệp trên đĩa thay đổi.Bộ nhớ cache tập tin Python

tôi có thể tạo ra một cái gì đó như:

def getobj(fname, cache = {}): 
    try: 
     obj, lastloaded = cache[fname] 
     if lastloaded < last_time_written(fname): 
      # same stuff as in except clause 
    except KeyError: 
     obj = create_from_file(fname) 
     cache[fname] = (obj, currenttime) 

    return obj 

Tuy nhiên, tôi muốn sử dụng của người khác kiểm tra mã nếu nó tồn tại. Có một thư viện hiện có làm một cái gì đó như thế này?

Cập nhật: Tôi đang sử dụng trăn 2.7.1.

+0

Lưu ý rằng thay vì lặp lại các mã trong 'khoản except' bên 'tuyên bố if' của bạn, bạn có thể chỉ' nâng KeyError()' để thay thế. – Amber

+2

Đối số mặc định có thể thay đổi tốt! – katrielalex

+0

@katrielalex Cảm ơn bạn! – Marcin

Trả lời

3

Mã của bạn (bao gồm cả logic bộ nhớ cache) có vẻ ổn.

Cân nhắc di chuyển bộ nhớ cache bên ngoài định nghĩa hàm. Điều đó sẽ làm cho nó có thể thêm các chức năng khác để xóa hoặc kiểm tra bộ nhớ cache.

Nếu bạn muốn xem mã tương tự, hãy xem mã nguồn cho mô-đun filecmp: http://hg.python.org/cpython/file/2.7/Lib/filecmp.py Phần thú vị là cách sử dụng stat module để xác định xem tệp đã thay đổi hay chưa. Đây là chữ ký chức năng:

def _sig(st): 
    return (stat.S_IFMT(st.st_mode), 
      st.st_size, 
      st.st_mtime) 
1

Trừ khi có một lý do cụ thể để sử dụng nó như là đối số tôi sẽ sử dụng bộ nhớ cache như một đối tượng toàn cầu

+0

Hợp lệ, nó là một hành động hay thay đổi trong khi soạn thảo trong cửa sổ SO. – Marcin

+1

tốt, một lý do là cho hiệu suất. toàn bộ mục đích của bộ nhớ cache là để cải thiện hiệu suất và tra cứu biến cục bộ (bao gồm các đối số mặc định) nhanh hơn bởi một số tiền khiêm tốn so với tra cứu toàn cầu. Điều đó nói lên rằng, mô hình này là một cách tuyệt vời để du hành các thế hệ tương lai chưa quen thuộc với ngôn ngữ này, và như bạn nói, toàn cầu * nên * được ưa thích hơn cho nhân chứng khi hiệu năng không phải là * tối đa * tầm quan trọng . – SingleNegationElimination

+1

@TokenMacGuy thành ngữ thông thường là 'def foo (cache = cache):' để sao chép các biến toàn cục vào phạm vi cục bộ. – katrielalex

1

Ba suy nghĩ.

  1. Sử dụng try... except... else cho luồng điều khiển neater.

  2. Thời gian sửa đổi tệp nổi tiếng không ổn định - đặc biệt, chúng không nhất thiết phải tương ứng với thời gian gần đây nhất mà tệp đã được sửa đổi!

  3. Python 3 chứa trình trang trí bộ nhớ đệm: functools.lru_cache. Đây là nguồn.

    def lru_cache(maxsize=100): 
        """Least-recently-used cache decorator. 
    
        If *maxsize* is set to None, the LRU features are disabled and the cache 
        can grow without bound. 
    
        Arguments to the cached function must be hashable. 
    
        View the cache statistics named tuple (hits, misses, maxsize, currsize) with 
        f.cache_info(). Clear the cache and statistics with f.cache_clear(). 
        Access the underlying function with f.__wrapped__. 
    
        See: http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used 
    
        """ 
        # Users should only access the lru_cache through its public API: 
        #  cache_info, cache_clear, and f.__wrapped__ 
        # The internals of the lru_cache are encapsulated for thread safety and 
        # to allow the implementation to change (including a possible C version). 
    
        def decorating_function(user_function, 
           tuple=tuple, sorted=sorted, len=len, KeyError=KeyError): 
    
         hits = misses = 0 
         kwd_mark = (object(),)   # separates positional and keyword args 
         lock = Lock()     # needed because ordereddicts aren't threadsafe 
    
         if maxsize is None: 
          cache = dict()    # simple cache without ordering or size limit 
    
          @wraps(user_function) 
          def wrapper(*args, **kwds): 
           nonlocal hits, misses 
           key = args 
           if kwds: 
            key += kwd_mark + tuple(sorted(kwds.items())) 
           try: 
            result = cache[key] 
            hits += 1 
           except KeyError: 
            result = user_function(*args, **kwds) 
            cache[key] = result 
            misses += 1 
           return result 
         else: 
          cache = OrderedDict()  # ordered least recent to most recent 
          cache_popitem = cache.popitem 
          cache_renew = cache.move_to_end 
    
          @wraps(user_function) 
          def wrapper(*args, **kwds): 
           nonlocal hits, misses 
           key = args 
           if kwds: 
            key += kwd_mark + tuple(sorted(kwds.items())) 
           try: 
            with lock: 
             result = cache[key] 
             cache_renew(key)  # record recent use of this key 
             hits += 1 
           except KeyError: 
            result = user_function(*args, **kwds) 
            with lock: 
             cache[key] = result  # record recent use of this key 
             misses += 1 
             if len(cache) > maxsize: 
              cache_popitem(0) # purge least recently used cache entry 
           return result 
    
         def cache_info(): 
          """Report cache statistics""" 
          with lock: 
           return _CacheInfo(hits, misses, maxsize, len(cache)) 
    
         def cache_clear(): 
          """Clear the cache and cache statistics""" 
          nonlocal hits, misses 
          with lock: 
           cache.clear() 
           hits = misses = 0 
    
         wrapper.cache_info = cache_info 
         wrapper.cache_clear = cache_clear 
         return wrapper 
    
        return decorating_function 
    
+0

Tôi không bao giờ biết về mệnh đề 'else'. Cảm ơn vì điều đó (và tất cả điều này). – Marcin

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