ফাংশন রিটার্ন মানগুলি কেবল ক্যাশে করার জন্য কি কোনও ডেকরেটর রয়েছে?


157

নিম্নোক্ত বিবেচনা কর:

@property
def name(self):

    if not hasattr(self, '_name'):

        # expensive calculation
        self._name = 1 + 1

    return self._name

আমি নতুন, তবে আমি মনে করি ক্যাচিংটি সাজসজ্জার ক্ষেত্রে তৈরি করা যেতে পারে। কেবল আমি এর মতো একটিও পাইনি;)

পিএস আসল গণনা পরিবর্তনীয় মানগুলির উপর নির্ভর করে না


সেখানে কোনও সজ্জনকারী হতে পারে যার কিছুটা সামর্থ্য রয়েছে তবে আপনি কী চান তা আপনি ভালভাবে নির্দিষ্ট করে নিলেন না। আপনি কী ধরনের ক্যাচিং ব্যাকএন্ড ব্যবহার করছেন? এবং কীভাবে মান কী হবে? আমি আপনার কোড থেকে ধরে নিচ্ছি যে আপনি যা চাইছেন তা কেবল ক্যাশে-পঠনযোগ্য সম্পত্তি।
ডেভিড বার্গার

মেমোজাইজিং অলঙ্করণকারী রয়েছে যা আপনি "ক্যাশিং" বলছেন তা সম্পাদন করে; তারা সাধারণত (যেমন পদ্ধতি হয়ে ওঠে বা না বোঝার উদ্দেশ্যে) ফাংশনগুলিতে কাজ করে যার ফলাফলগুলি তাদের যুক্তিগুলির উপর নির্ভর করে (স্ব-র মতো পরিবর্তিত জিনিসের উপর নয়!) এবং তাই আলাদা মেমো-ডিক্ট রাখে।
অ্যালেক্স মার্তেলেলি

উত্তর:


206

পাইথন ৩.২ থেকে শুরু করে একটি বিল্ট-ইন ডেকরেটার রয়েছে:

@functools.lru_cache(maxsize=100, typed=False)

সর্বাধিক সাম্প্রতিক কলগুলি সঞ্চয় করে এমন একটি মেমোজাইজিং কল দিয়ে একটি ফাংশন মোড়ানোর জন্য ডেকোরেটর। এটি কোনও সময় ব্যয় করতে পারে যখন কোনও ব্যয়বহুল বা I / O বাউন্ড ফাংশন পর্যায়ক্রমে একই যুক্তি দিয়ে ডাকা হয়।

ফিবোনাচি নম্বরগুলি গণনা করার জন্য একটি এলআরইউ ক্যাশের উদাহরণ :

@lru_cache(maxsize=None)
def fib(n):
    if n < 2:
        return n
    return fib(n-1) + fib(n-2)

>>> print([fib(n) for n in range(16)])
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]

>>> print(fib.cache_info())
CacheInfo(hits=28, misses=16, maxsize=None, currsize=16)

আপনি যদি পাইথন ২.x এর সাথে আটকে থাকেন তবে এখানে অন্যান্য সামঞ্জস্যপূর্ণ স্মৃতিগ্রন্থাগারগুলির তালিকা রয়েছে:



ব্যাকপোর্টটি এখন এখানে পাওয়া যাবে: pypi.python.org/pypi/backport.functools_lru_cache
ফ্রেডরিক নর্ড

@gerit তত্ত্বে এটি সাধারণভাবে হ্যাশেবল অবজেক্টের জন্য কাজ করে - যদিও কিছু হ্যাশেবল অবজেক্টগুলি একই জিনিস হলে (যেমন স্পষ্ট __hash __ () ফাংশন ব্যতীত ব্যবহারকারী-সংজ্ঞায়িত অবজেক্ট)।
জোনাথন

1
@ জোনাথন এটি কাজ করে তবে ভুলভাবে। যদি আমি কোনও হ্যাশেবল, পারস্পরিক পরিবর্তনযোগ্য আর্গুমেন্টটি পাস করি এবং ফাংশনের প্রথম কলের পরে অবজেক্টের মান পরিবর্তন করি তবে দ্বিতীয় কলটি মূল, অবজেক্ট নয়, পরিবর্তিত ফিরিয়ে দেবে। এটি ব্যবহারকারীরা যা চান তা প্রায় নয়। পরিবর্তনীয় যুক্তিগুলির জন্য এটির জন্য কাজ করার জন্য এটির lru_cacheফলাফলটি যা ঘটছে তার একটি অনুলিপি তৈরি করা দরকার এবং functools.lru_cacheবাস্তবায়নের ক্ষেত্রে এ জাতীয় কোনও অনুলিপি তৈরি করা হচ্ছে না । এটি করার ফলে কোনও বড় অবজেক্টের ক্যাশে ব্যবহার করার সময় হার্ড-টু-ফাইন্ড মেমোরি সমস্যা তৈরি করাও ঝুঁকিপূর্ণ ছিল।
জারিত

@gerrit ব্যাপারে এখানে নিম্নলিখিত মন: stackoverflow.com/questions/44583381/... ? আমি সম্পূর্ণরূপে আপনার উদাহরণ অনুসরণ না।
জোনাথন

28

দেখে মনে হচ্ছে আপনি সাধারণ উদ্দেশ্যমূলক স্মৃতিচারণকারীকে জিজ্ঞাসা করছেন না (যেমন, আপনি যে সাধারণ ক্ষেত্রে বিভিন্ন যুক্তির মানগুলির জন্য ফেরত মানগুলি ক্যাশে করতে চান সেখানে আগ্রহী নন)। এটি হল, আপনি এটি পেতে চাই:

x = obj.name  # expensive
y = obj.name  # cheap

যখন একটি সাধারণ-উদ্দেশ্য স্মৃতিচারণকারী আপনাকে এটি দেবে:

x = obj.name()  # expensive
y = obj.name()  # cheap

আমি জমা দিচ্ছি যে মেথড-কল সিনট্যাক্স আরও ভাল স্টাইল, কারণ এটি ব্যয়বহুল গণনার সম্ভাবনাটি প্রস্তাব করে যখন সম্পত্তি সিনট্যাক্সটি দ্রুত অনুসন্ধানের পরামর্শ দেয়।

[আপডেট: ক্লাস-ভিত্তিক মেমোয়াইজেশন ডেকরেটারের সাথে আমি এখানে লিঙ্ক করেছি এবং আগে উদ্ধৃত করেছি পদ্ধতিগুলির জন্য কাজ করে না। আমি এটিকে একটি ডেকরেটর ফাংশন দিয়ে প্রতিস্থাপন করেছি]] আপনি যদি সাধারণ-উদ্দেশ্যে স্মৃতিচারণকারী ডেকরেটর ব্যবহার করতে ইচ্ছুক হন, তবে এখানে একটি সাধারণ চিত্র রয়েছে:

def memoize(function):
  memo = {}
  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)

ক্যাশে আকারের সীমা সহ অন্য একটি মেমোয়াইজেশন শোভাকর এখানে পাওয়া যাবে


সমস্ত উত্তরে উল্লিখিত সাজসজ্জারগুলির কোনওই পদ্ধতিতে কাজ করে না! সম্ভবত তারা ক্লাস-ভিত্তিক because শুধু একজনেরই কি পাস হয়? অন্যরা ঠিকঠাক কাজ করে তবে ক্রিয়াকলাপগুলিতে মানগুলি সংরক্ষণ করা শিথিল।
টোবিয়াস

2
আমি মনে করি যদি আরগগুলি হ্যাশযোগ্য না হয় তবে আপনি কোনও সমস্যার মধ্যে পড়তে পারেন।
অজানা

1
@ অজানা হ্যাঁ, আমি এখানে প্রথম উদ্ধৃতকারীটি উদ্ধৃতযোগ্য প্রকারের মধ্যে সীমাবদ্ধ। অ্যাক্টিভেটে থাকা (ক্যাশে আকারের সীমা সহ) যুক্তিগুলিকে একটি (হ্যাশেবল) স্ট্রিংয়ে তুলেছে যা অবশ্যই আরও ব্যয়বহুল তবে আরও সাধারণ।
নাথান কিচেন

ক্লাস-ভিত্তিক সাজসজ্জার সীমাবদ্ধতাগুলি নির্দেশ করার জন্য @ অ্যান্টিটি ধন্যবাদ। আমি আমার উত্তরটি সংশোধন করেছি একটি ডেকরেটার ফাংশন প্রদর্শন করার জন্য, যা পদ্ধতিগুলির জন্য কাজ করে (আমি আসলে এটি পরীক্ষা করেছি)।
নাথান কিচেন

1
@ সিমিনজি ডেকরেটারটি কেবল একবার ডাকা হয়, এবং এটি যে মোড়ানো ফাংশনটি দেয় তা একই ধরণের সমস্ত বিভিন্ন কলের জন্য ব্যবহৃত হয় fibonacci। এই ফাংশন সর্বদা একই memoঅভিধান ব্যবহার করে ।
নাথান কিচেন

22
class memorize(dict):
    def __init__(self, func):
        self.func = func

    def __call__(self, *args):
        return self[args]

    def __missing__(self, key):
        result = self[key] = self.func(*key)
        return result

নমুনা ব্যবহার:

>>> @memorize
... def foo(a, b):
...     return a * b
>>> foo(2, 4)
8
>>> foo
{(2, 4): 8}
>>> foo('hi', 3)
'hihihi'
>>> foo
{(2, 4): 8, ('hi', 3): 'hihihi'}

স্ট্রেঞ্জ! কিভাবে কাজ করে? আমি দেখেছি এমন অন্যান্য সাজসজ্জার মতো মনে হয় না।
পাসক্যালভিকুটেন

1
যদি কেউ কীওয়ার্ড আর্গুমেন্টগুলি ব্যবহার করে, যেমন foo (3, b = 5)
কেডে

1
সমাধানের সমস্যাটি হ'ল এটির কোনও স্মৃতি সীমা নেই। নামযুক্ত যুক্তি হিসাবে, আপনি কেবল এগুলিকে __ কল__ এবং __ অনুপস্থিত__ * * ন্যাংকের মতো যুক্ত করতে পারেন
লিওনিড মেদনিকভ ২

16

পাইথন 3.8 functools.cached_propertyসাজসজ্জা

https://docs.python.org/dev/library/functools.html#functools.cached_property

cached_propertyওয়ার্কজেগের কাছ থেকে এখানে উল্লেখ করা হয়েছিল: https://stackoverflow.com/a/5295190/895245 তবে একটি অনুমিত উত্পন্ন সংস্করণটি 3.8 এ একীভূত হবে, যা দুর্দান্ত।

এই সাজসজ্জারকে ক্যাশে হিসাবে দেখা যেতে পারে @property, বা @functools.lru_cacheআপনার কোনও যুক্তি না থাকলে তার জন্য ক্লিনার হিসাবে দেখা যেতে পারে ।

দস্তাবেজগুলি বলেছেন:

@functools.cached_property(func)

শ্রেণীর একটি পদ্ধতির এমন কোনও সম্পত্তিতে রূপান্তর করুন যার মান একবার গণনা করা হয় এবং তারপরে উদাহরণের জীবনের জন্য সাধারণ বৈশিষ্ট্য হিসাবে ক্যাশে হয়। ক্যাশে সংযোজন সহ সম্পত্তি হিসাবে () অনুরূপ। উদাহরণস্বরূপ ব্যয়বহুল গণনার বৈশিষ্ট্যগুলির জন্য দরকারী যা অন্যথায় কার্যকরভাবে অপরিবর্তনীয়।

উদাহরণ:

class DataSet:
    def __init__(self, sequence_of_numbers):
        self._data = sequence_of_numbers

    @cached_property
    def stdev(self):
        return statistics.stdev(self._data)

    @cached_property
    def variance(self):
        return statistics.variance(self._data)

সংস্করণে নতুন 3.8।

দ্রষ্টব্য এই সাজসজ্জারটির প্রয়োজন প্রতিটি প্রতিরূপে ডিক বৈশিষ্ট্যটি একটি পরিবর্তনীয় ম্যাপিং। এই উপায়ে এটি যেমন metaclasses কিছু ধরনের, সঙ্গে কাজ করে না (যেহেতু হবে অভি টাইপ দৃষ্টান্ত উপর বৈশিষ্ট্যাবলী read-only বর্গ নামস্থান জন্য প্রক্সিগুলির), এবং যারা নির্দিষ্ট স্লট অন্তর্ভুক্ত না করেই অভি সংজ্ঞায়িত স্লট এক হিসাবে (যেমন শ্রেণীর যেমন কোনও ডিক অ্যাট্রিবিউট সরবরাহ করবেন না )।


10

ওয়ার্কজেগের একটি cached_propertyসজ্জা রয়েছে ( ডক্স , উত্স )


হ্যাঁ. সাধারণ স্মৃতিচারণের ক্ষেত্রে পৃথক করার পক্ষে এটি উপযুক্ত, কারণ শ্রেণিটি যদি অযোগ্য না হয় তবে স্ট্যান্ডার্ড মেমোয়েজেশন কাজ করে না।
জেমসন কুইন


9

আমি ফাংশন প্রতিক্রিয়াগুলি ক্যাশে এই সাধারণ ডেকোরেটর ক্লাসটি কোড করেছিলাম। আমি আমার প্রকল্পগুলির জন্য এটি খুব দরকারী বলে মনে করি:

from datetime import datetime, timedelta 

class cached(object):
    def __init__(self, *args, **kwargs):
        self.cached_function_responses = {}
        self.default_max_age = kwargs.get("default_cache_max_age", timedelta(seconds=0))

    def __call__(self, func):
        def inner(*args, **kwargs):
            max_age = kwargs.get('max_age', self.default_max_age)
            if not max_age or func not in self.cached_function_responses or (datetime.now() - self.cached_function_responses[func]['fetch_time'] > max_age):
                if 'max_age' in kwargs: del kwargs['max_age']
                res = func(*args, **kwargs)
                self.cached_function_responses[func] = {'data': res, 'fetch_time': datetime.now()}
            return self.cached_function_responses[func]['data']
        return inner

ব্যবহার সোজা:

import time

@cached
def myfunc(a):
    print "in func"
    return (a, datetime.now())

@cached(default_max_age = timedelta(seconds=6))
def cacheable_test(a):
    print "in cacheable test: "
    return (a, datetime.now())


print cacheable_test(1,max_age=timedelta(seconds=5))
print cacheable_test(2,max_age=timedelta(seconds=5))
time.sleep(7)
print cacheable_test(3,max_age=timedelta(seconds=5))

1
আপনার প্রথমটি @cachedঅনুপস্থিত parent অন্যথায় এটা শুধুমাত্র ফিরে আসবে cachedস্থানে বস্তুর myfuncএবং যখন বলা যেমন myfunc()তারপর innerসবসময় একটি ফিরতি মান হিসাবে ফেরত পাঠানো হবে
মার্কুস Meskanen

6

অস্বীকৃতি: আমি Kids.cache এর লেখক ।

আপনার যাচাই করা উচিত kids.cache, এটি @cacheঅলঙ্করণ 2 এবং অজগর 3 এ কাজ করে এমন একটি সাজসজ্জা সরবরাহ করে No কোনও নির্ভরতা নেই, কোডের ~ 100 লাইন। এটি ব্যবহার করা খুব সহজ ward উদাহরণস্বরূপ, আপনার কোডটি মাথায় রেখে আপনি এটি ব্যবহার করতে পারেন:

pip install kids.cache

তারপর

from kids.cache import cache
...
class MyClass(object):
    ...
    @cache            # <-- That's all you need to do
    @property
    def name(self):
        return 1 + 1  # supposedly expensive calculation

অথবা আপনি (একই ফলাফল) @cacheপরে সজ্জা লাগাতে পারেন @property

কোনও সম্পত্তিতে ক্যাশে ব্যবহার করার ক্ষেত্রে অলস মূল্যায়ন বলা হয় , kids.cacheআরও অনেক কিছু করা যায় (এটি কোনও যুক্তি, বৈশিষ্ট্য, যে কোনও ধরণের পদ্ধতি এবং এমনকি শ্রেণিগুলির সাথে কাজ করে ...)। উন্নত ব্যবহারকারীদের জন্য, kids.cacheসমর্থন cachetoolsযা পাইথন 2 এবং পাইথন 3 (এলআরইউ, এলএফইউ, টিটিএল, আরআর ক্যাশে) তে অভিনব ক্যাশে স্টোর সরবরাহ করে।

গুরুত্বপূর্ণ দ্রষ্টব্য : এর ডিফল্ট ক্যাশে স্টোরটি kids.cacheএকটি স্ট্যান্ডার্ড ডিক, যা দীর্ঘসময় ধরে চলমান প্রোগ্রামের জন্য বিভিন্ন ধরণের প্রশ্নের সাথে সুপারিশ করা হয় না কারণ এটি ক্রমবর্ধমান ক্যাচিং স্টোরকে নিয়ে যায়। এই ব্যবহারের জন্য আপনি উদাহরণস্বরূপ ব্যবহার করে অন্যান্য ক্যাশে স্টোরগুলি প্লাগইন করতে পারেন ( @cache(use=cachetools.LRUCache(maxsize=2))আপনার ফাংশন / সম্পত্তি / শ্রেণী / পদ্ধতি সাজানোর জন্য ...)


এই মডিউলটির ফলে পাইথন 2 ~ 0.9s (দেখুন: পেস্টবিন . com/raw/aA1ZBE9Z ) এ ধীরে ধীরে আমদানির সময় আসবে বলে মনে হচ্ছে । আমি সন্দেহ করি যে এটি এই লাইনের কারণে github.com/0k/kids.cache/blob/master/src/kids/__init__.py#L3 (সিএফ সেটআপটোলেস এন্ট্রি পয়েন্ট) রয়েছে। আমি এটির জন্য একটি সমস্যা তৈরি করছি।
এট রিগ

উপরের github.com/0k/kids.cache/issues/9 এর জন্য এখানে একটি সমস্যা রয়েছে
এট রিগ

এটি স্মৃতি ফাঁস হতে পারে।
টিমোথি জাং

@vaab একটি দৃষ্টান্ত তৈরি cএর MyClass, এবং সঙ্গে এটি পরিদর্শন objgraph.show_backrefs([c], max_depth=10), সেখানে বর্গ বস্তু থেকে একটি সুত্র চেইন হয় MyClassথেকে c। এর অর্থ, cমুক্তি পাওয়ার আগে কখনও মুক্তি দেওয়া হত না MyClass
তীমথিয় জাং

@TimothyZhang আপনাকে আমন্ত্রণ করুন এবং আপনার উদ্বেগ যোগ করা হয় স্বাগত জানাই github.com/0k/kids.cache/issues/10 । স্ট্যাকওভারফ্লো এটি সম্পর্কে যথাযথ আলোচনার জন্য সঠিক জায়গা নয়। এবং আরও ব্যাখ্যা প্রয়োজন। আপনার প্রতিক্রিয়ার জন্য ধন্যবাদ।
vaab


4

এখানে ফাস্টকাশে রয়েছে , "পাইথন 3 ফান্টাকুলস.আরলু_ক্যাচের সি বাস্তবায়ন standard স্ট্যান্ডার্ড লাইব্রেরির তুলনায় 10-30x গতিবেগ সরবরাহ করে" "

নির্বাচিত উত্তর হিসাবে একই , কেবল ভিন্ন আমদানি:

from fastcache import lru_cache
@lru_cache(maxsize=128, typed=False)
def f(a, b):
    pass

এছাড়াও, এটি অ্যানাকোন্ডায় ইনস্টল করা হয়েছে , ফান্টুলগুলি থেকে আলাদা যা ইনস্টল করা দরকার


1
functoolsস্ট্যান্ডার্ড লাইব্রেরির অংশ, আপনার পোস্ট করা লিংকটি এলোমেলো গিট কাঁটাচামচ বা অন্য কিছু ...
সিজেড

3

পাইথন উইকিতে মেমোয়েজ ডেকরেটারের আরও একটি উদাহরণ রয়েছে :

http://wiki.python.org/moin/PythonDecoratorLibrary#Memoize

সেই উদাহরণটি কিছুটা স্মার্ট, কারণ পরামিতিগুলি পরিবর্তনযোগ্য হলে এটি ফলাফলগুলিকে ক্যাশে করবে না। (কোডটি দেখুন, এটি খুব সহজ এবং আকর্ষণীয়!)


3

আপনি যদি জ্যাঙ্গো ফ্রেমওয়ার্ক ব্যবহার করছেন, এটির ব্যবহারের মতামত বা এপিআই এর প্রতিক্রিয়া ক্যাশে করার মতো সম্পত্তি @cache_page(time)রয়েছে এবং অন্যান্য বিকল্পগুলিও থাকতে পারে।

উদাহরণ:

@cache_page(60 * 15, cache="special_cache")
def my_view(request):
    ...

আরও বিশদ এখানে পাওয়া যাবে


2

বরাবর Memoize উদাহরণ আমি নিম্নলিখিত পাইথন প্যাকেজ পাওয়া যায়নি:

  • ক্যাশেপি ; এটি টিটিএল এবং \ বা ক্যাশেড ফাংশনগুলির জন্য কলগুলির সংখ্যা সেট আপ করতে দেয়; এছাড়াও, কেউ এনক্রিপ্ট করা ফাইল-ভিত্তিক ক্যাশে ব্যবহার করতে পারেন ...
  • percache

1

আমি দৃ something়তার জন্য আচার ব্যবহার করে এবং শর্ট প্রায়-অবশ্যই-অনন্য আইডিগুলির জন্য sha1 ব্যবহার করে এর মতো কিছু বাস্তবায়ন করেছি। মূলত ক্যাশে ফাংশনটির কোড এবং একটি sha1 পেতে আর্গুমেন্টের হিস্টটি হ্যাশ করে তারপরে নামের সাথে সেই শা 1 দিয়ে একটি ফাইল সন্ধান করে। যদি এটি বিদ্যমান থাকে তবে এটি এটি খুলল এবং ফলাফলটি ফিরিয়ে দিল; যদি তা না হয় তবে এটি ফাংশনটিতে কল করে এবং ফলাফলটি সংরক্ষণ করে (বিকল্পভাবে কেবল এটি সংরক্ষণ করতে যদি এটি প্রক্রিয়া করতে নির্দিষ্ট সময় নেয় তবে)।

এটি বলেছিল, আমি দিব্যি আমি একটি বিদ্যমান মডিউল পেয়েছিলাম যা এটি করেছে এবং নিজেকে এখানে খুঁজে পেয়েছিলাম সেই মডিউলটি সন্ধান করার চেষ্টা করছি ... আমি যে নিকটতম সন্ধান করতে পারি এটি হ'ল এটি সঠিক, যা সঠিক সম্পর্কে দেখায়: http: //chase-seibert.github। IO / ব্লগ / 2011/11/23 / pythondjango-ডিস্ক-ভিত্তিক-ক্যাশে-decorator.html

আমি কেবল এটিই দেখতে পাচ্ছি যে এটি বড় ইনপুটগুলির পক্ষে ভাল কাজ করবে না কারণ এটি হ্যাশ করা হয়েছে (আরগ), যা দৈত্য অ্যারেগুলির জন্য অনন্য নয়।

ভাল লাগবে যদি কোনও অনন্য_হ্যাশ () প্রোটোকল থাকে যা ক্লাসে এর সামগ্রীগুলির একটি সুরক্ষিত হ্যাশ দেয়। আমি মূলত আমি যে ধরণের যত্ন নিয়েছিলাম সেগুলির জন্য ম্যানুয়ালি এটি প্রয়োগ করেছিলাম।



1

আপনি যদি জ্যাঙ্গো ব্যবহার করছেন এবং ভিউগুলি ক্যাশে করতে চান তবে নিখিল কুমারের উত্তর দেখুন


তবে আপনি যদি কোনও ফাংশনের ফলাফল ক্যাশে করতে চান তবে আপনি জ্যাঙ্গো-ক্যাশে- ব্যবহারগুলি ব্যবহার করতে পারেন ।

এটি জাজানো ক্যাশে পুনরায় ব্যবহার করে এবং cachedডেকরেটর ব্যবহার করা সহজ করে :

from cache_utils.decorators import cached

@cached(60)
def foo(x, y=0):
    print 'foo is called'
    return x+y

1

@lru_cache ডিফল্ট ফাংশন মানগুলির সাথে নিখুঁত নয়

আমার memশোভাকর:

import inspect


def get_default_args(f):
    signature = inspect.signature(f)
    return {
        k: v.default
        for k, v in signature.parameters.items()
        if v.default is not inspect.Parameter.empty
    }


def full_kwargs(f, kwargs):
    res = dict(get_default_args(f))
    res.update(kwargs)
    return res


def mem(func):
    cache = dict()

    def wrapper(*args, **kwargs):
        kwargs = full_kwargs(func, kwargs)
        key = list(args)
        key.extend(kwargs.values())
        key = hash(tuple(key))
        if key in cache:
            return cache[key]
        else:
            res = func(*args, **kwargs)
            cache[key] = res
            return res
    return wrapper

এবং পরীক্ষার জন্য কোড:

from time import sleep


@mem
def count(a, *x, z=10):
    sleep(2)
    x = list(x)
    x.append(z)
    x.append(a)
    return sum(x)


def main():
    print(count(1,2,3,4,5))
    print(count(1,2,3,4,5))
    print(count(1,2,3,4,5, z=6))
    print(count(1,2,3,4,5, z=6))
    print(count(1))
    print(count(1, z=10))


if __name__ == '__main__':
    main()

ফলাফল - ঘুমের সাথে মাত্র 3 বার

তবে @lru_cacheএটি 4 বার হবে কারণ এটি:

print(count(1))
print(count(1, z=10))

দুবার গণনা করা হবে (ডিফল্টগুলির সাথে খারাপ কাজ করা)

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.