मैंने अभी पायथन शुरू किया है और मुझे पता नहीं है कि संस्मरण क्या है और इसका उपयोग कैसे करना है। इसके अलावा, क्या मेरे पास एक सरलीकृत उदाहरण हो सकता है?
मैंने अभी पायथन शुरू किया है और मुझे पता नहीं है कि संस्मरण क्या है और इसका उपयोग कैसे करना है। इसके अलावा, क्या मेरे पास एक सरलीकृत उदाहरण हो सकता है?
जवाबों:
मेमोइज़ेशन प्रभावी रूप से याद करने के लिए संदर्भित करता है ("ज्ञापन" → "मेमोरंडम" → याद किया जाना) विधि इनपुट्स के आधार पर विधि कॉल के परिणाम और फिर परिणाम की गणना करने के बजाय याद किए गए परिणाम को वापस करना। आप इसे विधि परिणामों के लिए कैश के रूप में सोच सकते हैं। अधिक जानकारी के लिए, परिचय एल्गोरिथ्म (3e), कॉर्मेन एट अल में परिभाषा के लिए पृष्ठ 387 देखें ।
पायथन में संस्मरण का उपयोग करते हुए तथ्यात्मक गणना के लिए एक सरल उदाहरण कुछ इस तरह होगा:
factorial_memo = {}
def factorial(k):
if k < 2: return 1
if k not in factorial_memo:
factorial_memo[k] = k * factorial(k-1)
return factorial_memo[k]
आप अधिक जटिल हो सकते हैं और संस्मरण प्रक्रिया को एक कक्षा में सम्मिलित कर सकते हैं:
class Memoize:
def __init__(self, f):
self.f = f
self.memo = {}
def __call__(self, *args):
if not args in self.memo:
self.memo[args] = self.f(*args)
#Warning: You may wish to do a deepcopy here if returning objects
return self.memo[args]
फिर:
def factorial(k):
if k < 2: return 1
return k * factorial(k - 1)
factorial = Memoize(factorial)
पायथन 2.4 में " डेकोरेटर्स " के रूप में जाना जाने वाला एक फीचर जोड़ा गया था, जो आपको बस उसी चीज को पूरा करने के लिए निम्नलिखित लिखने की अनुमति देता है:
@Memoize
def factorial(k):
if k < 2: return 1
return k * factorial(k - 1)
अजगर डेकोरेटर लाइब्रेरी एक ऐसी ही डेकोरेटर कहा जाता है memoized
थोड़ा की तुलना में अधिक मजबूत है कि Memoize
वर्ग यहाँ दिखाया गया है।
factorial_memo
, क्योंकि factorial
अंदर def factorial
अभी भी पुराने को अनम्मोइज़ कहा जाता है factorial
।
if k not in factorial_memo:
, जो इससे बेहतर पढ़ता है if not k in factorial_memo:
।
args
एक तुक है। def some_function(*args)
बनाता है एक tuple args।
पायथन 3.2 के लिए नया है functools.lru_cache
। डिफ़ॉल्ट रूप से, यह केवल 128 सबसे हाल ही में उपयोग की गई कॉल को कैश करता है , लेकिन आप यह इंगित maxsize
करने के None
लिए सेट कर सकते हैं कि कैश कभी समाप्त नहीं होना चाहिए:
import functools
@functools.lru_cache(maxsize=None)
def fib(num):
if num < 2:
return num
else:
return fib(num-1) + fib(num-2)
यह फ़ंक्शन अपने आप में बहुत धीमा है, कोशिश करें fib(36)
और आपको लगभग दस सेकंड इंतजार करना होगा।
lru_cache
एनोटेशन जोड़ना यह सुनिश्चित करता है कि यदि फ़ंक्शन को हाल ही में किसी विशेष मान के लिए बुलाया गया है, तो वह उस मान को फिर से नहीं जमा करेगा, लेकिन पिछले परिणाम का उपयोग करें। इस मामले में, यह एक जबरदस्त गति सुधार की ओर जाता है, जबकि कोड को कैशिंग के विवरण के साथ नहीं जोड़ा गया है।
fib
कॉल करने पर, मेमोएशन होने से पहले बेस केस को रिकवर करना होगा। तो, आपका व्यवहार उम्मीद के मुताबिक है।
अन्य उत्तर कवर करते हैं कि यह काफी अच्छा है। मैं ऐसा नहीं दोहरा रहा हूं। बस कुछ बिंदु जो आपके लिए उपयोगी हो सकते हैं।
आमतौर पर, मेमॉज़ेशन एक ऑपरेशन है जिसे आप किसी भी फ़ंक्शन पर लागू कर सकते हैं जो कुछ (महंगी) गणना करता है और एक मूल्य देता है। इस वजह से, इसे अक्सर डेकोरेटर के रूप में लागू किया जाता है । कार्यान्वयन सीधा है और यह कुछ इस तरह होगा
memoised_function = memoise(actual_function)
या एक डेकोरेटर के रूप में व्यक्त किया गया
@memoise
def actual_function(arg1, arg2):
#body
संस्मरण महंगा गणना के परिणामों को बनाए रख रहा है और लगातार पुनर्गणना करने के बजाय कैश्ड परिणाम लौटा रहा है।
यहाँ एक उदाहरण है:
def doSomeExpensiveCalculation(self, input):
if input not in self.cache:
<do expensive calculation>
self.cache[input] = result
return self.cache[input]
ज्ञापन पर विकिपीडिया प्रविष्टि में अधिक पूर्ण विवरण पाया जा सकता है ।
if input not in self.cache
और तब से अप्रचलित है ... जल्दी 2.x श्रृंखला में, यदि 2.0 नहीं। कभी भी सही नहीं था। IIRC)self.cache[input]
has_key
self.cache(index)
hasattr
जो हाथ से शिल्प करना चाहते हैं, उनके लिए अंतर्निहित फ़ंक्शन को नहीं भूलना चाहिए। इस तरह आप फ़ंक्शन परिभाषा के अंदर मेम कैश रख सकते हैं (जैसा कि एक वैश्विक विरोध)।
def fact(n):
if not hasattr(fact, 'mem'):
fact.mem = {1: 1}
if not n in fact.mem:
fact.mem[n] = n * fact(n - 1)
return fact.mem[n]
मैंने इसे बेहद उपयोगी पाया है
def memoize(function):
from functools import wraps
memo = {}
@wraps(function)
def wrapper(*args):
if args in memo:
return memo[args]
else:
rv = function(*args)
memo[args] = rv
return rv
return wrapper
@memoize
def fibonacci(n):
if n < 2: return n
return fibonacci(n - 1) + fibonacci(n - 2)
fibonacci(25)
functools.wraps
।
memo
ताकि मेमोरी फ़्री हो जाए?
संस्मरण मूल रूप से पुनरावर्ती एल्गोरिदम के साथ किए गए पिछले परिचालनों के परिणामों को सहेज रहा है ताकि यदि बाद में उसी गणना की आवश्यकता हो तो पुनरावर्ती वृक्ष को पार किया जा सके।
देख http://scriptbucket.wordpress.com/2012/12/11/introduction-to-memoization/
पायथन में फिबोनाची संस्मरण उदाहरण:
fibcache = {}
def fib(num):
if num in fibcache:
return fibcache[num]
else:
fibcache[num] = num if num < 2 else fib(num-1) + fib(num-2)
return fibcache[num]
संस्मरण डेटा संरचनाओं में कार्यों का रूपांतरण है। आमतौर पर कोई चाहता है कि रूपांतरण अचानक और आलसी (किसी दिए गए डोमेन तत्व की मांग पर - या "कुंजी") हो। आलसी कार्यात्मक भाषाओं में, यह आलसी रूपांतरण स्वचालित रूप से हो सकता है, और इस प्रकार संस्मरण बिना (स्पष्ट) दुष्प्रभावों के लागू किया जा सकता है।
वैसे मुझे पहले भाग का उत्तर पहले देना चाहिए: संस्मरण क्या है?
यह समय के लिए स्मृति का व्यापार करने की एक विधि है। गुणन तालिका के बारे में सोचो ।
पायथन में डिफॉल्ट वैल्यू के रूप में म्यूटेबल ऑब्जेक्ट का उपयोग करना आमतौर पर बुरा माना जाता है। लेकिन अगर इसका इस्तेमाल समझदारी से किया जाए, तो यह वास्तव में लागू करने के लिए उपयोगी हो सकता है memoization
।
यहां http://docs.python.org/2/faq/design.html#why-are-default-values-sared-between-objects से अनुकूलित एक उदाहरण दिया गया है
dict
फ़ंक्शन परिभाषा में एक परिवर्तनशील का उपयोग करके , मध्यवर्ती गणना किए गए परिणामों को कैश किया जा सकता है (जैसे गणना के factorial(10)
बाद गणना करते समय factorial(9)
, हम सभी मध्यवर्ती परिणामों का पुन: उपयोग कर सकते हैं)
def factorial(n, _cache={1:1}):
try:
return _cache[n]
except IndexError:
_cache[n] = factorial(n-1)*n
return _cache[n]
यहाँ एक समाधान है जो सूची या तानाशाही प्रकार के तर्कों के साथ काम करेगा बिना:
def memoize(fn):
"""returns a memoized version of any function that can be called
with the same list of arguments.
Usage: foo = memoize(foo)"""
def handle_item(x):
if isinstance(x, dict):
return make_tuple(sorted(x.items()))
elif hasattr(x, '__iter__'):
return make_tuple(x)
else:
return x
def make_tuple(L):
return tuple(handle_item(x) for x in L)
def foo(*args, **kwargs):
items_cache = make_tuple(sorted(kwargs.items()))
args_cache = make_tuple(args)
if (args_cache, items_cache) not in foo.past_calls:
foo.past_calls[(args_cache, items_cache)] = fn(*args,**kwargs)
return foo.past_calls[(args_cache, items_cache)]
foo.past_calls = {}
foo.__name__ = 'memoized_' + fn.__name__
return foo
ध्यान दें कि इस दृष्टिकोण को अपने स्वयं के हैश फ़ंक्शन को handle_item में एक विशेष मामले के रूप में लागू करके किसी भी वस्तु के लिए स्वाभाविक रूप से बढ़ाया जा सकता है। उदाहरण के लिए, इस दृष्टिकोण को एक इनपुट तर्क के रूप में सेट करने वाले फ़ंक्शन के लिए काम करने के लिए, आप handle_item में जोड़ सकते हैं:
if is_instance(x, set):
return make_tuple(sorted(list(x)))
list
से एक तर्क [1, 2, 3]
को एक अलग set
तर्क के रूप में माना जा सकता है {1, 2, 3}
। इसके अलावा, सेट डिक्शनरी की तरह अनियंत्रित होते हैं, इसलिए उन्हें भी होना चाहिए sorted()
। यह भी ध्यान दें कि एक पुनरावर्ती डेटा संरचना तर्क एक अनंत लूप का कारण होगा।
list
s और set
s एक ही चीज़ में "tupleized" हैं और इसलिए एक दूसरे से अप्रभेद्य बन जाते हैं। sets
आपके नवीनतम अपडेट में वर्णित समर्थन को जोड़ने के लिए उदाहरण कोड से मुझे डर नहीं है। इसे आसानी से अलग-अलग पास करके [1,2,3]
और {1,2,3}
"मेमॉइज़" डी टेस्ट फ़ंक्शन के तर्क के रूप में देखा जा सकता है और यह देखने के लिए कि क्या इसे दो बार कहा जाता है, जैसा कि होना चाहिए, या नहीं।
list
और dict
क्योंकि यह संभव एक के लिए list
उस में बिल्कुल एक ही बात यह है कि फोन करने से हुई है करने के लिए make_tuple(sorted(x.items()))
एक शब्दकोश के लिए। दोनों मामलों के लिए एक सरल समाधान यह होगा कि type()
उत्पन्न हुए मूल्य में मूल्य को शामिल किया जाए । मैं विशेष रूप से set
एस को संभालने के लिए और भी सरल तरीके के बारे में सोच सकता हूं , लेकिन यह सामान्य नहीं करता है।
समाधान है कि आदेश की स्वतंत्र रूप से दोनों स्थितीय और कीवर्ड तर्क, जिसमें कीवर्ड आर्ग (का उपयोग करते हुए पारित किए गए के साथ काम करता है inspect.getargspec ):
import inspect
import functools
def memoize(fn):
cache = fn.cache = {}
@functools.wraps(fn)
def memoizer(*args, **kwargs):
kwargs.update(dict(zip(inspect.getargspec(fn).args, args)))
key = tuple(kwargs.get(k, None) for k in inspect.getargspec(fn).args)
if key not in cache:
cache[key] = fn(**kwargs)
return cache[key]
return memoizer
इसी तरह का सवाल: पायथन में संस्मरण के लिए समतुल्य वर्गास फ़ंक्शन कॉल की पहचान करना
cache = {}
def fib(n):
if n <= 1:
return n
else:
if n not in cache:
cache[n] = fib(n-1) + fib(n-2)
return cache[n]
if n not in cache
इसके बजाय बस का उपयोग कर सकते हैं । उपयोग cache.keys
करने से अजगर 2
बस पहले से उपलब्ध कराए गए उत्तरों को जोड़ना चाहता था, पायथन डेकोरेटर लाइब्रेरी में कुछ सरल अभी तक उपयोगी कार्यान्वयन हैं जो इसके विपरीत "अस्वास्थ्यकर प्रकार" को भी याद कर सकते हैं functools.lru_cache
।