Python 3.7 - functools

फंक्शनलबुल - कॉल करने योग्य वस्तुओं पर उच्च-क्रम के कार्य और संचालन




python

फंक्शनलबुल - कॉल करने योग्य वस्तुओं पर उच्च-क्रम के कार्य और संचालन

स्रोत कोड: Lib/functools.py

functools मॉड्यूल उच्च-क्रम के कार्यों के लिए है: ऐसे फ़ंक्शन जो अन्य कार्यों को कार्य करते हैं या वापस करते हैं। सामान्य तौर पर, किसी भी कॉल करने योग्य वस्तु को इस मॉड्यूल के उद्देश्यों के लिए एक फ़ंक्शन के रूप में माना जा सकता है।

functools मॉड्यूल निम्नलिखित कार्यों को परिभाषित करता है:

functools.cmp_to_key(func)

एक पुरानी शैली की तुलना फ़ंक्शन को एक महत्वपूर्ण फ़ंक्शन में बदलना। प्रमुख कार्यों को स्वीकार करने वाले उपकरणों के साथ उपयोग किया जाता है (जैसे sorted() , min() , min() , max() , heapq.nlargest() , heapq.nsmallest() , itertools.groupby() )। यह फ़ंक्शन मुख्य रूप से पायथन 2 से परिवर्तित होने वाले कार्यक्रमों के लिए एक संक्रमण उपकरण के रूप में उपयोग किया जाता है जिसने तुलनात्मक कार्यों के उपयोग का समर्थन किया है।

तुलनात्मक फ़ंक्शन किसी भी कॉल करने योग्य है जो दो तर्कों को स्वीकार करता है, उनकी तुलना करता है, और कम से कम के लिए एक नकारात्मक संख्या, समानता के लिए शून्य या अधिक से अधिक के लिए एक सकारात्मक संख्या देता है। एक कुंजी फ़ंक्शन एक कॉल करने योग्य है जो एक तर्क को स्वीकार करता है और सॉर्ट कुंजी के रूप में उपयोग किए जाने के लिए एक और मान लौटाता है।

उदाहरण:

sorted(iterable, key=cmp_to_key(locale.strcoll))  # locale-aware sort order

सॉर्टिंग उदाहरण और एक संक्षिप्त सॉर्टिंग ट्यूटोरियल के लिए, सॉर्टिंग को कैसे देखें।

संस्करण 3.2 में नया।

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

डेकोरेटर एक फ़ंक्शन को एक मेमोइज़िंग कॉलेबल के साथ लपेटने के लिए जो सबसे हाल ही में कॉल को अधिकतम करता है। यह समय बचा सकता है जब एक महंगी या I / O बाध्य फ़ंक्शन को समय-समय पर समान तर्कों के साथ बुलाया जाता है।

चूंकि किसी शब्दकोश का उपयोग परिणामों को कैश करने के लिए किया जाता है, इसलिए फ़ंक्शन के लिए स्थिति और कीवर्ड तर्क को धोने योग्य होना चाहिए।

विशिष्ट तर्क पैटर्न को अलग कैश प्रविष्टियों के साथ अलग-अलग कॉल माना जा सकता है। उदाहरण के लिए, f(a=1, b=2) और f(b=2, a=1) उनके खोजशब्द तर्क क्रम में भिन्न हैं और उनमें दो अलग-अलग कैश प्रविष्टियाँ हो सकती हैं।

यदि अधिकतम आकार None सेट None , तो LRU सुविधा अक्षम है और कैश बिना बाउंड के बढ़ सकता है। LRU सुविधा सबसे अच्छा प्रदर्शन करती है जब अधिकतम शक्ति एक दो होती है।

यदि टाइप किया गया है, तो यह सही है, अलग-अलग प्रकार के फ़ंक्शन तर्क अलग-अलग कैश किए जाएंगे। उदाहरण के लिए, f(3) और f(3.0) को अलग-अलग परिणामों के साथ अलग-अलग कॉल के रूप में माना जाएगा।

कैश की प्रभावशीलता को मापने में मदद करने के लिए और cache_info() पैरामीटर को ट्यून करने के लिए, लिपटे हुए फ़ंक्शन को cache_info() फ़ंक्शन के साथ इंस्ट्रूमेंट किया जाता है, जो हिट , मिस , मैक्सिफाई और कर्साइज़ दिखाते हुए एक नामित टपल लौटाता है । बहु-थ्रेडेड वातावरण में, हिट और मिस लगभग अनुमानित हैं।

डेकोरेटर कैश साफ़ करने या अमान्य करने के लिए cache_clear() फ़ंक्शन भी प्रदान करता है।

मूल अंतर्निहित फ़ंक्शन __wrapped__ विशेषता के माध्यम से सुलभ है। यह आत्मनिरीक्षण के लिए उपयोगी है, कैश को दरकिनार करने के लिए, या एक अलग कैश के साथ फ़ंक्शन को फिर से तैयार करने के लिए।

एक LRU (कम से कम हाल ही में उपयोग किया गया) कैश तब सबसे अच्छा काम करता है जब सबसे हाल की कॉल आगामी कॉल का सबसे अच्छा भविष्यवाणियाँ होती हैं (उदाहरण के लिए, समाचार सर्वर पर सबसे लोकप्रिय लेख प्रत्येक दिन बदलने के लिए होते हैं)। कैश का आकार सीमा यह आश्वस्त करती है कि कैश लंबे समय तक चलने वाली प्रक्रियाओं जैसे वेब सर्वर पर बाध्य हुए बिना नहीं बढ़ता है।

स्थिर वेब सामग्री के लिए LRU कैश का उदाहरण:

@lru_cache(maxsize=32)
def get_pep(num):
    'Retrieve text of a Python Enhancement Proposal'
    resource = 'http://www.python.org/dev/peps/pep-%04d/' % num
    try:
        with urllib.request.urlopen(resource) as s:
            return s.read()
    except urllib.error.HTTPError:
        return 'Not Found'

>>> for n in 8, 290, 308, 320, 8, 218, 320, 279, 289, 320, 9991:
...     pep = get_pep(n)
...     print(n, len(pep))

>>> get_pep.cache_info()
CacheInfo(hits=3, misses=8, maxsize=32, currsize=8)

एक गतिशील प्रोग्रामिंग तकनीक को लागू करने के लिए कैश का उपयोग करके फाइबोनैचि संख्याओं को कुशलतापूर्वक कंप्यूटिंग करने का उदाहरण:

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

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

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

संस्करण 3.2 में नया।

संस्करण 3.3 में बदला गया : टाइप किया गया विकल्प जोड़ा गया।

@functools.total_ordering

एक या अधिक समृद्ध तुलना क्रम विधियों को परिभाषित करने वाले वर्ग को देखते हुए, यह वर्ग सज्जाकार बाकी की आपूर्ति करता है। यह संभव समृद्ध तुलनात्मक संचालन के सभी को निर्दिष्ट करने में शामिल प्रयास को सरल करता है:

वर्ग को __lt__() , __le__() , __gt__() , या __ge__() एक को परिभाषित करना होगा। इसके अलावा, वर्ग को एक __eq__() विधि की आपूर्ति करनी चाहिए।

उदाहरण के लिए:

@total_ordering
class Student:
    def _is_valid_operand(self, other):
        return (hasattr(other, "lastname") and
                hasattr(other, "firstname"))
    def __eq__(self, other):
        if not self._is_valid_operand(other):
            return NotImplemented
        return ((self.lastname.lower(), self.firstname.lower()) ==
                (other.lastname.lower(), other.firstname.lower()))
    def __lt__(self, other):
        if not self._is_valid_operand(other):
            return NotImplemented
        return ((self.lastname.lower(), self.firstname.lower()) <
                (other.lastname.lower(), other.firstname.lower()))

ध्यान दें

हालांकि यह डेकोरेटर अच्छी तरह से पूरी तरह से ऑर्डर किए गए प्रकारों का व्यवहार करना आसान बनाता है, यह धीमी गति से निष्पादन और व्युत्पन्न तुलना विधियों के लिए अधिक जटिल स्टैक निशान की कीमत पर आता है। यदि प्रदर्शन बेंचमार्किंग इंगित करता है कि यह दिए गए आवेदन के लिए एक अड़चन है, तो इसके बजाय सभी छह समृद्ध तुलना विधियों को लागू करना एक आसान आसान बढ़ावा प्रदान करने की संभावना है।

संस्करण 3.2 में नया।

संस्करण 3.4 में बदला गया: गैर-मान्यताप्राप्त प्रकारों के लिए अंतर्निहित तुलनात्मक फ़ंक्शन से लौटाया गया NotImplement अब समर्थित है।

functools.partial(func, *args, **keywords)

एक नई partial वस्तु लौटाएं, जिसे जब कॉल किया जाएगा तो फंक की तरह व्यवहार किया जाएगा जिसे स्थिति संबंधी तर्कों और कीवर्ड तर्क कीवर्ड के साथ बुलाया जाता है। यदि कॉल के लिए अधिक तर्क दिए जाते हैं, तो उन्हें आर्ग से जोड़ा जाता है। यदि अतिरिक्त कीवर्ड तर्क दिए जाते हैं, तो वे कीवर्ड बढ़ाते और ओवरराइड करते हैं। इसके बराबर:

def partial(func, *args, **keywords):
    def newfunc(*fargs, **fkeywords):
        newkeywords = keywords.copy()
        newkeywords.update(fkeywords)
        return func(*args, *fargs, **newkeywords)
    newfunc.func = func
    newfunc.args = args
    newfunc.keywords = keywords
    return newfunc

partial आंशिक फ़ंक्शन अनुप्रयोग के लिए उपयोग किया जाता है जो एक फ़ंक्शन के तर्कों और / या कीवर्ड के कुछ हिस्से को "फ्रीज" करता है जिसके परिणामस्वरूप एक सरलीकृत हस्ताक्षर के साथ एक नई वस्तु होती है। उदाहरण के लिए, partial का उपयोग एक कॉल करने योग्य बनाने के लिए किया जा सकता है जो int() फ़ंक्शन की तरह व्यवहार करता है जहां आधार तर्क दो को परिभाषित करता है:

>>> from functools import partial
>>> basetwo = partial(int, base=2)
>>> basetwo.__doc__ = 'Convert base 2 string to an int.'
>>> basetwo('10010')
18
class functools.partialmethod(func, *args, **keywords)

एक नया partialmethod डिस्क्रिप्टर partialmethod जो partial तरह व्यवहार करता है सिवाय इसके कि इसे partialmethod करने योग्य होने के बजाय एक विधि परिभाषा के रूप में उपयोग करने के लिए डिज़ाइन किया गया है।

func एक descriptor या एक कॉल करने योग्य होना चाहिए (ऐसी वस्तुएं जो सामान्य कार्यों की तरह दोनों हैं, जिन्हें डिस्क्रिप्टर के रूप में संभाला जाता है)।

जब func एक डिस्क्रिप्टर होता है (जैसे कि एक सामान्य पायथन फ़ंक्शन, classmethod() , classmethod() , staticmethod() या partialmethod का एक और उदाहरण), __get__ को कॉल किया जाता है, जो अंतर्निहित डिस्क्रिप्टर को सौंपा जाता है, और एक उपयुक्त partial ऑब्जेक्ट परिणाम के रूप में लौटाया जाता है ।

जब फंक एक गैर-डिस्क्रिप्टर कॉल करने योग्य होता है, तो एक उपयुक्त बाध्य विधि गतिशील रूप से बनाई जाती है। यह एक सामान्य पायथन फ़ंक्शन की तरह व्यवहार करता है जब एक विधि के रूप में उपयोग किया जाता है: आत्म तर्क को पहले स्थितीय तर्क के रूप में डाला जाएगा, इससे पहले कि partialmethod और partialmethod कंस्ट्रक्टर को आपूर्ति किए गए कीवर्ड

उदाहरण:

>>> class Cell(object):
...     def __init__(self):
...         self._alive = False
...     @property
...     def alive(self):
...         return self._alive
...     def set_state(self, state):
...         self._alive = bool(state)
...     set_alive = partialmethod(set_state, True)
...     set_dead = partialmethod(set_state, False)
...
>>> c = Cell()
>>> c.alive
False
>>> c.set_alive()
>>> c.alive
True

संस्करण 3.4 में नया।

functools.reduce(function, iterable[, initializer])

अनुक्रम के आइटमों के लिए दो तर्कों के फ़ंक्शन को लागू करें, बाएं से दाएं, ताकि अनुक्रम को एक मूल्य पर कम किया जा सके। उदाहरण के लिए, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) गणना ((((1+2)+3)+4)+5) । बाएं तर्क, x , संचित मूल्य है और सही तर्क, y , अनुक्रम से अद्यतन मूल्य है। यदि वैकल्पिक इनिशलाइज़र मौजूद है, तो इसे गणना में अनुक्रम के आइटम से पहले रखा जाता है, और अनुक्रम खाली होने पर डिफ़ॉल्ट के रूप में कार्य करता है। यदि इनिशियलाइज़र नहीं दिया गया है और अनुक्रम में केवल एक आइटम है, तो पहला आइटम वापस आ गया है।

इसके बराबर:

def reduce(function, iterable, initializer=None):
    it = iter(iterable)
    if initializer is None:
        value = next(it)
    else:
        value = initializer
    for element in it:
        value = function(value, element)
    return value
@functools.singledispatch

single-dispatch जेनेरिक फ़ंक्शन में फ़ंक्शन को बदलना।

जेनेरिक फ़ंक्शन को परिभाषित करने के लिए, इसे @singledispatch डेकोरेटर से @singledispatch । ध्यान दें कि प्रेषण पहले तर्क के प्रकार पर होता है, इसके अनुसार अपना फ़ंक्शन बनाएं:

>>> from functools import singledispatch
>>> @singledispatch
... def fun(arg, verbose=False):
...     if verbose:
...         print("Let me just say,", end=" ")
...     print(arg)

फ़ंक्शन में अतिभारित कार्यान्वयन को जोड़ने के लिए, जेनेरिक फ़ंक्शन के register() विशेषता का उपयोग करें। यह एक डेकोरेटर है। प्रकारों के साथ एनोटेट किए गए कार्यों के लिए, डेकोरेटर स्वचालित रूप से पहले तर्क के प्रकार का अनुमान लगाएगा:

>>> @fun.register
... def _(arg: int, verbose=False):
...     if verbose:
...         print("Strength in numbers, eh?", end=" ")
...     print(arg)
...
>>> @fun.register
... def _(arg: list, verbose=False):
...     if verbose:
...         print("Enumerate this:")
...     for i, elem in enumerate(arg):
...         print(i, elem)

कोड के लिए जो प्रकार के एनोटेशन का उपयोग नहीं करता है, उपयुक्त प्रकार के तर्क को डेकोरेटर को स्पष्ट रूप से पारित किया जा सकता है:

>>> @fun.register(complex)
... def _(arg, verbose=False):
...     if verbose:
...         print("Better than complicated.", end=" ")
...     print(arg.real, arg.imag)
...

लैम्ब्डा और पहले से मौजूद कार्यों को पंजीकृत करने में सक्षम करने के लिए, register() विशेषता को कार्यात्मक रूप में उपयोग किया जा सकता है:

>>> def nothing(arg, verbose=False):
...     print("Nothing.")
...
>>> fun.register(type(None), nothing)

register() विशेषता अछूता फ़ंक्शन देता है जो डेकोरेटर स्टैकिंग, अचार बनाने के साथ-साथ स्वतंत्र रूप से प्रत्येक संस्करण के लिए इकाई परीक्षण बनाने में सक्षम बनाता है:

>>> @fun.register(float)
... @fun.register(Decimal)
... def fun_num(arg, verbose=False):
...     if verbose:
...         print("Half of your number:", end=" ")
...     print(arg / 2)
...
>>> fun_num is fun
False

जब कहा जाता है, तो जेनेरिक फ़ंक्शन पहले तर्क के प्रकार पर भेजता है:

>>> fun("Hello, world.")
Hello, world.
>>> fun("test.", verbose=True)
Let me just say, test.
>>> fun(42, verbose=True)
Strength in numbers, eh? 42
>>> fun(['spam', 'spam', 'eggs', 'spam'], verbose=True)
Enumerate this:
0 spam
1 spam
2 eggs
3 spam
>>> fun(None)
Nothing.
>>> fun(1.23)
0.615

जहां एक विशिष्ट प्रकार के लिए कोई पंजीकृत कार्यान्वयन नहीं है, इसके विधि रिज़ॉल्यूशन ऑर्डर का उपयोग अधिक सामान्य कार्यान्वयन खोजने के लिए किया जाता है। @singledispatch साथ सजाया गया मूल फ़ंक्शन आधार object प्रकार के लिए पंजीकृत है, जिसका अर्थ है कि यदि कोई बेहतर कार्यान्वयन नहीं मिला है तो इसका उपयोग किया जाता है।

यह जांचने के लिए कि कौन सा कार्यान्वयन किसी दिए गए प्रकार के लिए जेनेरिक फ़ंक्शन का चयन करेगा, dispatch() उपयोग करें dispatch() विशेषता:

>>> fun.dispatch(float)
<function fun_num at 0x1035a2840>
>>> fun.dispatch(dict)    # note: default implementation
<function fun at 0x103fe0000>

सभी पंजीकृत कार्यान्वयन तक पहुँचने के लिए, केवल-पढ़ने के लिए registry विशेषता का उपयोग करें:

>>> fun.registry.keys()
dict_keys([<class 'NoneType'>, <class 'int'>, <class 'object'>,
          <class 'decimal.Decimal'>, <class 'list'>,
          <class 'float'>])
>>> fun.registry[float]
<function fun_num at 0x1035a2840>
>>> fun.registry[object]
<function fun at 0x103fe0000>

संस्करण 3.4 में नया।

3.7 संस्करण में बदला गया: register() विशेषता प्रकार एनोटेशन का उपयोग करके समर्थन करता है।

functools.update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)

लिपटे फ़ंक्शन की तरह दिखने के लिए एक आवरण फ़ंक्शन को अपडेट करें। वैकल्पिक तर्कों को निर्दिष्ट करने के लिए ट्यूपल्स हैं जो मूल फ़ंक्शन की विशेषताओं को सीधे आवरण फ़ंक्शन पर मिलान विशेषताओं को सौंपा गया है और आवरण फ़ंक्शन के कौन से गुण मूल फ़ंक्शन से संबंधित विशेषताओं के साथ अपडेट किए गए हैं। इन तर्कों के लिए डिफ़ॉल्ट मान मॉड्यूल स्तर के स्थिरांक हैं WRAPPER_ASSIGNMENTS (जो आवरण फ़ंक्शन के __module__ , __name__ , __qualname__ , __annotations__ और __doc__ , दस्तावेज़ीकरण स्ट्रिंग) और WRAPPER_UPDATES (जो आवरण फ़ंक्शन के __dict__ फ़ंक्शन को अपडेट करता है) के लिए __dict__

आत्मनिरीक्षण और अन्य उद्देश्यों के लिए मूल फ़ंक्शन तक पहुंच की अनुमति देने के लिए (जैसे कि कैशिंग डेकोरेटर जैसे कि lru_cache() ), यह फ़ंक्शन स्वचालित रूप से आवरण के लिए __wrapped__ विशेषता को जोड़ता है जो लिपटे जाने वाले फ़ंक्शन को संदर्भित करता है।

इस फ़ंक्शन के लिए मुख्य इच्छित उपयोग decorator फ़ंक्शन में है जो सजाए गए फ़ंक्शन को लपेटता है और आवरण को वापस करता है। यदि आवरण फ़ंक्शन अपडेट नहीं किया जाता है, तो लौटे फ़ंक्शन का मेटाडेटा मूल फ़ंक्शन परिभाषा के बजाय आवरण परिभाषा को प्रतिबिंबित करेगा, जो आमतौर पर सहायक से कम है।

update_wrapper() का उपयोग फ़ंक्शंस के अलावा कॉलबल्स के साथ किया जा सकता है। असाइन किए गए या अपडेट किए गए किसी भी गुण को जो ऑब्जेक्ट के लिपटे होने से गायब है, को अनदेखा किया जाता है (यानी यह फ़ंक्शन उन्हें आवरण फ़ंक्शन पर सेट करने का प्रयास नहीं करेगा)। यदि अभी भी रैपर फ़ंक्शन अद्यतन में नामित किसी भी विशेषता को याद नहीं कर रहा है, तो AttributeError को उठाया जाता है।

संस्करण 3.2 में नया: __wrapped__ विशेषता का स्वचालित जोड़।

संस्करण 3.2 में नया: डिफ़ॉल्ट रूप से __annotations__ विशेषता की प्रतिलिपि बनाना।

वर्जन 3.2 में बदला: मिसिंग एट्रीब्यूट्स अब AttributeError ट्रिगर नहीं है।

संस्करण __wrapped__ में परिवर्तित: __wrapped__ विशेषता अब हमेशा लिपटे फ़ंक्शन को संदर्भित करती है, भले ही वह फ़ंक्शन __wrapped__ विशेषता को परिभाषित करता हो। (देखें bpo-17482 )

@functools.wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)

यह एक आवरण समारोह को परिभाषित करते समय फ़ंक्शन डेकोरेटर के रूप में update_wrapper() को लागू करने के लिए एक सुविधा फ़ंक्शन है। यह partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated) बराबर है। उदाहरण के लिए:

>>> from functools import wraps
>>> def my_decorator(f):
...     @wraps(f)
...     def wrapper(*args, **kwds):
...         print('Calling decorated function')
...         return f(*args, **kwds)
...     return wrapper
...
>>> @my_decorator
... def example():
...     """Docstring"""
...     print('Called example function')
...
>>> example()
Calling decorated function
Called example function
>>> example.__name__
'example'
>>> example.__doc__
'Docstring'

इस डेकोरेटर कारखाने के उपयोग के बिना, उदाहरण फ़ंक्शन का नाम 'wrapper' , और मूल example() का डॉकस्ट्रिंग खो जाता।

आंशिक वस्तुएं

partial ऑब्जेक्ट partial द्वारा बनाई गई कॉल करने योग्य ऑब्जेक्ट हैं। उनके पास केवल तीन विशेषताएँ हैं:

partial.func

एक कॉल करने योग्य वस्तु या कार्य। partial ऑब्जेक्ट को कॉल नए तर्कों और कीवर्ड के साथ func लिए भेजा जाएगा।

partial.args

बाईं ओर स्थित स्थिति संबंधी तर्क जो partial ऑब्जेक्ट कॉल के लिए प्रदान किए गए स्थितीय तर्कों के लिए तैयार किए जाएंगे।

partial.keywords

partial तर्क कहे जाने पर कीवर्ड तर्क दिए जाएंगे।

partial ऑब्जेक्ट function ऑब्जेक्ट की तरह होते हैं, जिसमें वे कॉल करने योग्य, कमजोर रेस्पेन्सेबल होते हैं, और उनमें विशेषता हो सकती है। कुछ महत्वपूर्ण अंतर हैं। उदाहरण के लिए, __name__ और __doc__ विशेषताएँ स्वचालित रूप से नहीं बनाई गई हैं। इसके अलावा, कक्षाओं में परिभाषित partial वस्तुएं स्थिर तरीकों की तरह व्यवहार करती हैं और उदाहरण विशेषता लुक-अप के दौरान बाध्य तरीकों में परिवर्तित नहीं होती हैं।