Functools-पायथन में उच्च-क्रम के कार्यों की शक्ति

स्रोत नोड: 1865357

इस लेख के एक भाग के रूप में प्रकाशित किया गया था डेटा साइंस ब्लॉगथॉन

परिचय

आपके कोड को साफ़ और सरल बनाए रखने में मदद करने के लिए पायथन स्टैंडर्ड लाइब्रेरी में कई बेहतरीन मॉड्यूल हैं और यह कार्यात्मक है निश्चित रूप से इनमें से एक

कैशिंग

आइए मॉड्यूल functools के कुछ सबसे सरल लेकिन शक्तिशाली कार्यों से शुरुआत करें। आइए कैशिंग फ़ंक्शंस (साथ ही डेकोरेटर) से शुरू करें - lru_cache,cache और cached_property. उनमें से पहला - lru_cache कार्यों के निष्पादन के अंतिम परिणामों का कैश प्रदान करता है, या दूसरे शब्दों में, उनके कार्य के परिणाम को याद रखता है:

from functools import lru_cache
import requests @lru_cache(maxsize=32)
def get_with_cache(url): try: r = requests.get(url) return r.text except: return "Not Found" for url in ["https://google.com/", "https://reddit.com/", "https://google.com/", "https://google.com/"]: get_with_cache(url) print(get_with_cache.cache_info())
# CacheInfo(hits=2, misses=4, maxsize=32, currsize=4)
print(get_with_cache.cache_parameters())
# {'maxsize': 32, 'typed': False}

इस उदाहरण में, हम GET अनुरोध करते हैं और डेकोरेटर का उपयोग करके उनके परिणामों (32 परिणामों तक) को कैश करते हैं @lru_cache. यह देखने के लिए कि क्या कैशिंग वास्तव में काम करती है, आप एक विधि का उपयोग करके फ़ंक्शन कैश जानकारी की जांच कर सकते हैं cache_infoजो कैश हिट और हिट की संख्या दर्शाता है। एक डेकोरेटर तरीके भी प्रदान करता है clear_cacheऔर cache_parametersक्रमशः कैश्ड परिणामों और परीक्षण मापदंडों को रद्द करने के लिए।

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

functools में कैशिंग के लिए एक अन्य डेकोरेटर एक फ़ंक्शन है जिसे सिंपली कहा जाता है cache. यह एक साधारण आवरण है lru_cacheयह तर्क max_size को छोड़ देता है, इसे कम कर देता है, और पुराने मानों को नहीं हटाता है।

एक अन्य डेकोरेटर जिसका उपयोग आप कैशिंग के लिए कर सकते हैं वह है cached_property. जैसा कि नाम से पता चलता है, इसका उपयोग क्लास विशेषताओं के परिणामों को कैश करने के लिए किया जाता है। यदि आपके पास ऐसी संपत्ति है जिसकी गणना करना महंगा है, लेकिन वह वैसी ही रहती है तो यह मैकेनिक बहुत उपयोगी है।

from functools import cached_property class Page: @cached_property def render(self, value): # Do something with supplied value... # Long computation that renders HTML page... return html

यह सरल उदाहरण दिखाता है. जैसा कि इस्तेमाल किया जा सकता है, कैश्ड प्रॉपर्टी, उदाहरण के लिए, एक रेंडर किए गए HTML पेज को कैश करने के लिए जिसे उपयोगकर्ता को बार-बार दिखाने की आवश्यकता होती है। कुछ डेटाबेस प्रश्नों या लंबी गणित गणनाओं के लिए भी ऐसा ही किया जा सकता है।

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

मैं उपरोक्त सभी डेकोरेटर्स के बारे में एक चेतावनी के साथ इस अनुभाग को समाप्त करना चाहता हूं - यदि आपके फ़ंक्शन के कुछ दुष्प्रभाव हैं या यह हर बार कॉल किए जाने पर परिवर्तनशील ऑब्जेक्ट बनाता है तो उनका उपयोग न करें क्योंकि ये स्पष्ट रूप से वे फ़ंक्शन नहीं हैं जिन्हें आप कैश करना चाहते हैं .

तुलना और आदेश

आप शायद पहले से ही जानते हैं कि आप पायथन में तुलना ऑपरेटरों को लागू कर सकते हैं जैसे कि <, >=or ==, साथ में lt, gtor eq. हालाँकि, इनमें से प्रत्येक का एहसास करना काफी निराशाजनक हो सकता है eq, lt, le, gtor ge. सौभाग्य से, functools में एक डेकोरेटर है @total_orderingइससे हमें मदद मिल सकती है, क्योंकि हमें बस इसे लागू करने की जरूरत है eqशेष विधियों में से एक, और शेष डेकोरेटर स्वचालित रूप से उत्पन्न हो जाएगा।

from functools import total_ordering @total_ordering
class Number: def __init__(self, value): self.value = value def __lt__(self, other): return self.value Number(3))
# True
print(Number(1) = Number(15))
# True
print(Number(10) <= Number(2))
# False

इस तरह, हम केवल eq और हाथ से लेफ्टिनेंट होने के बावजूद, सभी विस्तारित तुलना परिचालनों को कार्यान्वित कर सकते हैं। सबसे स्पष्ट लाभ सुविधा है, जो यह है कि आपको इन सभी अतिरिक्त जादुई तरीकों को लिखना नहीं पड़ता है, लेकिन कोड की मात्रा को कम करना और इसकी बेहतर पठनीयता को कम करना संभवतः अधिक महत्वपूर्ण है।

अधिभार

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

आंशिक

हम सभी विभिन्न बाहरी पुस्तकालयों या रूपरेखाओं के साथ काम करते हैं, जिनमें से कई फ़ंक्शन और इंटरफ़ेस प्रदान करते हैं जिनके लिए हमें कॉलबैक पास करने की आवश्यकता होती है, जैसे कि अतुल्यकालिक संचालन या घटनाओं को सुनना। यह कोई नई बात नहीं है, लेकिन क्या होगा अगर हमें कॉलबैक के साथ कुछ तर्क भी पारित करने पड़ें। यह वह जगह है जहां यह उपयोगी functools में आता है.partial. इस्तेमाल किया जा सकता है partialसरलीकृत फ़ंक्शन हस्ताक्षर के साथ एक नई वस्तु बनाकर किसी फ़ंक्शन के कुछ (या सभी) तर्कों को फ़्रीज़ करना। अस्पष्ट? आइए कुछ व्यावहारिक उदाहरण देखें:

def output_result(result, log=None): if log is not None: log.debug(f"Result is: {result}") def concat(a, b): return a + b import logging
from multiprocessing import Pool
from functools import partial logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger("default") p = Pool()
p.apply_async(concat, ("Hello ", "World"), callback=partial(output_result, log=logger))
p.close()
p.join()

उपरोक्त कोड दिखाता है कि आप इसका उपयोग कैसे कर सकते हैं partialएक फ़ंक्शन पास करने के लिए ( output_result) एक तर्क के साथ ( log=logger) कॉलबैक के रूप में। इस मामले में, हम मल्टीप्रोसेसिंग.apply_async का उपयोग करेंगे, जो एसिंक्रोनस रूप से फ़ंक्शन के परिणाम की गणना करता है ( concat) और कॉलबैक का परिणाम लौटाता है। तथापि, apply_asyncयह हमेशा परिणाम को पहले तर्क के रूप में पारित करेगा, और यदि हम कोई अतिरिक्त तर्क शामिल करना चाहते हैं, जैसा कि लॉग = लॉगर के मामले में है, तो हमें आंशिक का उपयोग करने की आवश्यकता है।

हमने काफी उन्नत उपयोग के मामले पर विचार किया है, और एक सरल उदाहरण एक फ़ंक्शन का सामान्य निर्माण होगा जो stdout के बजाय stderr में लिखता है:

import sys
from functools import partial print_stderr = partial(print, file=sys.stderr)
print_stderr("This goes to standard error output")

इस सरल ट्रिक से, हमने एक नया कॉल करने योग्य फ़ंक्शन बनाया जो हमेशा पास होगा file=sys.stderrआउटपुट के लिए एक नामित तर्क के रूप में, जो हमें अपने कोड को सरल बनाने की अनुमति देता है और हर बार नामित तर्क का मान निर्दिष्ट करने की आवश्यकता नहीं होती है।

और एक आखिरी अच्छा उदाहरण. हम इसका उपयोग कर सकते हैं partialएक अल्पज्ञात फ़ंक्शन के संयोजन में iterकॉल करने योग्य ऑब्जेक्ट को पास करके एक पुनरावर्तक बनाना और sentinelin iter, जिसे इस प्रकार लागू किया जा सकता है:

from functools import partial RECORD_SIZE = 64 # Read binary file...
with open("file.data", "rb") as file: records = iter(partial(file.read, RECORD_SIZE), b'') for r in records: # Do something with the record...

आमतौर पर, किसी फ़ाइल को पढ़ते समय, हम पंक्तियों पर पुनरावृति करना चाहते हैं, लेकिन बाइनरी डेटा के मामले में, हमें एक निश्चित आकार के रिकॉर्ड पर पुनरावृति करने की आवश्यकता हो सकती है। आप कॉल करने योग्य ऑब्जेक्ट का उपयोग करके ऐसा कर सकते हैं partialजो डेटा के निर्दिष्ट हिस्से को पढ़ता है और उसे पास करता है iterएक पुनरावर्तक बनाने के लिए. यह पुनरावर्तक तब तक रीड फ़ंक्शन को कॉल करता है जब तक कि यह फ़ाइल के अंत तक नहीं पहुंच जाता, हमेशा केवल निर्दिष्ट खंड आकार लेता है ( RECORD_SIZE). अंत में, जब फ़ाइल का अंत पहुँच जाता है, तो मान sentinel(बी ") वापस आ जाता है और पुनरावृत्ति रुक ​​जाती है।

सज्जाकार

हम पहले ही पिछले अनुभागों में कुछ डेकोरेटर्स के बारे में बात कर चुके हैं, लेकिन अधिक डेकोरेटर बनाने के लिए डेकोरेटर्स के बारे में नहीं। ऐसा ही एक डेकोरेटर है functools.wraps. यह समझने के लिए कि आपको इसकी आवश्यकता क्यों है, आइए एक उदाहरण देखें:

def decorator(func): def actual_func(*args, **kwargs): """Inner function within decorator, which does the actual work""" print(f"Before Calling {func.__name__}") func(*args, **kwargs) print(f"After Calling {func.__name__}") return actual_func @decorator
def greet(name): """Says hello to somebody""" print(f"Hello, {name}!") greet("Martin")
# Before Calling greet
# Hello, Martin!
# After Calling greet

यह उदाहरण दिखाता है कि एक साधारण डेकोरेटर को कैसे कार्यान्वित किया जा सकता है। हम एक फ़ंक्शन लपेटते हैं जो एक विशिष्ट कार्य करता है ( actual_func) एक बाहरी डेकोरेटर के साथ, और यह स्वयं एक डेकोरेटर बन जाता है, जिसे बाद में अन्य कार्यों पर लागू किया जा सकता है, उदाहरण के लिए, जैसा कि मामले में है greet. जब आप फ़ंक्शन को कॉल करते हैं, greet आप देखेंगे कि यह दोनों संदेशों को प्रिंट करता है actual_funcऔर अपने दम पर. ठीक लग रहा है, है ना? लेकिन अगर हम ऐसा करें तो क्या होगा:

print(greet.__name__)
# actual_func
print(greet.__doc__)
# Inner function within decorator, which does the actual work

जब हम डेकोरेटेड फ़ंक्शन का नाम और दस्तावेज़ कहते हैं, तो हमें पता चलता है कि उन्हें डेकोरेटर फ़ंक्शन के मानों से बदल दिया गया है। यह बुरा है क्योंकि जब हम किसी डेकोरेटर का उपयोग करते हैं तो हम अपने सभी फ़ंक्शन नामों और दस्तावेज़ों को फिर से नहीं लिख सकते हैं। इस समस्या का समाधान कैसे किया जा सकता है? बेशक, functools के साथ.wraps:

from functools import wraps def decorator(func): @wraps(func) def actual_func(*args, **kwargs): """Inner function within decorator, which does the actual work""" print(f"Before Calling {func.__name__}") func(*args, **kwargs) print(f"After Calling {func.__name__}") return actual_func @decorator
def greet(name): """Says hello to somebody""" print(f"Hello, {name}!") print(greet.__name__)
# greet
print(greet.__doc__)
# Says hello to somebody

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

कम करना

मॉड्यूल functools में अंतिम लेकिन महत्वपूर्ण बात यह कम करना है। शायद अन्य भाषाओं से आप इसे इस रूप में जानते होंगे fold(हास्केल)। यह फ़ंक्शन एक पुनरावर्तनीय लेता है और इसके सभी मानों को एक में जोड़ता (जोड़ता) है। इसके लिए कई एप्लिकेशन हैं, उदाहरण के लिए:

from functools import reduce
import operator def product(iterable): return reduce(operator.mul, iterable, 1) def factorial(n): return reduce(operator.mul, range(1, n)) def sum(numbers): # Use `sum` function from standard library instead return reduce(operator.add, numbers, 1) def reverse(iterable): return reduce(lambda x, y: y+x, iterable) print(product([1, 2, 3]))
# 6
print(factorial(5))
# 24
print(sum([2, 6, 8, 3]))
# 20
print(reverse("hello"))
# olleh

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

और अगर आपको यह याद है reduce अक्सर हर चीज को एक पंक्ति में छोटा कर देता है, इसके साथ इसे पूरी तरह से जोड़ा जा सकता है partial:

product = partial(reduce, operator.mul) print(product([1, 2, 3]))
# 6

और अंत में, यदि आपको केवल अंतिम "संक्षिप्त" परिणाम से अधिक की आवश्यकता है, तो आप इसका उपयोग कर सकते हैं accumulate- एक और महान मॉड्यूल से itertools. अधिकतम की गणना करने के लिए, इसका उपयोग निम्नानुसार किया जा सकता है:

from itertools import accumulate data = [3, 4, 1, 3, 5, 6, 9, 0, 1] print(list(accumulate(data, max)))
# [3, 4, 4, 4, 5, 6, 9, 9, 9]

निष्कर्ष

जैसा कि आप फ़ंक्शंस देख सकते हैं, ऐसे कई उपयोगी फ़ंक्शंस और डेकोरेटर हैं जो आपके जीवन को आसान बना सकते हैं, लेकिन यह केवल हिमशैल का टिप है। जैसा कि मैंने शुरुआत में कहा था, पायथन मानक लाइब्रेरी में कई फ़ंक्शन हैं जो आपको बेहतर कोड लिखने में मदद करते हैं, इसलिए हमारे द्वारा यहां कवर किए गए फ़ंक्शन के अलावा, आप अन्य मॉड्यूल पर भी ध्यान दे सकते हैं, जैसे operatoror itertool. किसी भी प्रश्न के लिए, आप मेरे कमेंट बॉक्स पर क्लिक कर सकते हैं। मैं आपके इनपुट को हल करने की पूरी कोशिश करूंगा और आशा करता हूं कि आपको वांछित आउटपुट दे सकूं। आप मुझसे लिंक्डइन पर भी संपर्क कर सकते हैं:-

https://www.linkedin.com/in/shivani-sharma-aba6141b6/

इस लेख में दिखाया गया मीडिया एनालिटिक्स विद्या के स्वामित्व में नहीं है और लेखक के विवेक पर उपयोग किया जाता है।

स्रोत: https://www.analyticsvidya.com/blog/2021/08/functools-the-power-of-higher-order-functions-in-python/

समय टिकट:

से अधिक एनालिटिक्स विधा