यदि आप एक शुरुआती हैं, तो भी अपने पायथन कोड को कैसे अनुकूलित करेंयदि आप एक शुरुआती हैं, तो भी अपने पायथन कोड को कैसे अनुकूलित करें
लेखक द्वारा छवि | इदेओग्राम

हम ईमानदार हो। जब आप पायथन सीख रहे हैं, तो आप शायद प्रदर्शन के बारे में नहीं सोच रहे हैं। आप बस काम करने के लिए अपना कोड प्राप्त करने की कोशिश कर रहे हैं! लेकिन यहाँ बात है: अपने पायथन कोड को तेजी से बनाना आपको रात भर एक विशेषज्ञ प्रोग्रामर बनने की आवश्यकता नहीं है।

कुछ सरल तकनीकों के साथ जो मैं आज आपको दिखाऊंगा, आप अपने कोड की गति और मेमोरी उपयोग में काफी सुधार कर सकते हैं।

इस लेख में, हम एक साथ पांच व्यावहारिक शुरुआती-अनुकूल अनुकूलन तकनीकों के माध्यम से चलेंगे। हर एक के लिए, मैं आपको “पहले” कोड (जिस तरह से कई शुरुआती इसे लिखता है), “कोड के बाद” कोड (अनुकूलित संस्करण) को दिखाऊंगा, और यह समझाएं कि सुधार क्यों काम करता है और यह कितनी तेजी से मिलता है।

🔗 GitHub पर कोड के लिए लिंक

1। सूची की समझ के साथ छोरों को बदलें

आइए कुछ ऐसा शुरू करें जो आप शायद हर समय करते हैं: मौजूदा लोगों को बदलकर नई सूची बनाना। अधिकांश शुरुआती लूप के लिए पहुंचते हैं, लेकिन पायथन के पास ऐसा करने के लिए बहुत तेज रास्ता है।

अनुकूलन से पहले

यहां बताया गया है कि अधिकांश शुरुआती संख्याओं की एक सूची को कैसे वर्ग करेंगे:

import time

def square_numbers_loop(numbers):
    result = [] 
    for num in numbers: 
        result.append(num ** 2) 
    return result

# Let's test this with 1000000 numbers to see the performance
test_numbers = list(range(1000000))

start_time = time.time()
squared_loop = square_numbers_loop(test_numbers)
loop_time = time.time() - start_time
print(f"Loop time: {loop_time:.4f} seconds")

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

अनुकूलन के बाद

अब एक सूची समझ का उपयोग करके इसे फिर से लिखें:

def square_numbers_comprehension(numbers):
    return [num ** 2 for num in numbers]  # Create the entire list in one line

start_time = time.time()
squared_comprehension = square_numbers_comprehension(test_numbers)
comprehension_time = time.time() - start_time
print(f"Comprehension time: {comprehension_time:.4f} seconds")
print(f"Improvement: {loop_time / comprehension_time:.2f}x faster")

यह सिंगल लाइन [num ** 2 for num in numbers] हमारे लूप के रूप में बिल्कुल वही बात करता है, लेकिन यह पायथन को बता रहा है “एक सूची बनाएं जहां प्रत्येक तत्व संख्याओं में संबंधित तत्व का वर्ग है।”

आउटपुट:

Loop time: 0.0840 seconds
Comprehension time: 0.0736 seconds
Improvement: 1.14x faster

प्रदर्शन सुधार: सूची की समझ आम तौर पर समान छोरों की तुलना में 30-50% तेज होती है। जब आप बहुत बड़े iterables के साथ काम करते हैं तो सुधार अधिक ध्यान देने योग्य होता है।

यह काम क्यों करता है? सूची की समझ को हुड के नीचे सी में लागू किया जाता है, इसलिए वे बहुत सारे ओवरहेड से बचते हैं जो पायथन लूप्स के साथ आता है, वेरिएबल लुकअप और फ़ंक्शन कॉल जैसी चीजें जो पर्दे के पीछे होती हैं।

2। नौकरी के लिए सही डेटा संरचना चुनें

यह बहुत बड़ा है, और यह कुछ ऐसा है जो आपके कोड को केवल एक छोटे से बदलाव के साथ सैकड़ों बार तेजी से बना सकता है। कुंजी यह समझ रही है कि सूची बनाम सेट बनाम शब्दकोशों का उपयोग कब करना है।

अनुकूलन से पहले

मान लीजिए कि आप दो सूचियों के बीच सामान्य तत्वों को ढूंढना चाहते हैं। यहाँ सहज दृष्टिकोण है:

def find_common_elements_list(list1, list2):
    common = []
    for item in list1:  # Go through each item in the first list
        if item in list2:  # Check if it exists in the second list
            common.append(item)  # If yes, add it to our common list
    return common

# Test with reasonably large lists
large_list1 = list(range(10000))     
large_list2 = list(range(5000, 15000))

start_time = time.time()
common_list = find_common_elements_list(large_list1, large_list2)
list_time = time.time() - start_time
print(f"List approach time: {list_time:.4f} seconds")

यह कोड पहली सूची के माध्यम से लूप करता है, और प्रत्येक आइटम के लिए, यह जांचता है कि क्या वह आइटम दूसरी सूची में मौजूद है, IF आइटम का उपयोग करके list2। समस्या? जब आप आइटम में करते हैं list2पायथन को पूरी दूसरी सूची के माध्यम से खोज करनी होती है जब तक कि वह आइटम नहीं ढूंढता। यह धीमा है!

अनुकूलन के बाद

यहाँ एक ही तर्क है, लेकिन तेज लुकअप के लिए एक सेट का उपयोग करना:

def find_common_elements_set(list1, list2):
    set2 = set(list2)  # Convert list to a set (one-time cost)
    return [item for item in list1 if item in set2]  # Check membership in set

start_time = time.time()
common_set = find_common_elements_set(large_list1, large_list2)
set_time = time.time() - start_time
print(f"Set approach time: {set_time:.4f} seconds")
print(f"Improvement: {list_time / set_time:.2f}x faster")

सबसे पहले, हम सूची को एक सेट में परिवर्तित करते हैं। फिर, अगर आइटम में जाँच करने के बजाय list2हम जांच करते हैं कि क्या आइटम में है set2। यह छोटा परिवर्तन सदस्यता परीक्षण को लगभग तात्कालिक बनाता है।

आउटपुट:

List approach time: 0.8478 seconds
Set approach time: 0.0010 seconds
Improvement: 863.53x faster

प्रदर्शन सुधार: यह बड़े डेटासेट के लिए 100x तेजी से आदेश का हो सकता है।

यह काम क्यों करता है? सेट हुड के नीचे हैश टेबल का उपयोग करते हैं। जब आप जांचते हैं कि कोई आइटम एक सेट में है, तो पायथन हर तत्व के माध्यम से खोज नहीं करता है; यह हैश का उपयोग सीधे कूदने के लिए करता है जहां आइटम होना चाहिए। यह हर पृष्ठ को पढ़ने के बजाय एक पुस्तक का सूचकांक होने जैसा है कि आप क्या चाहते हैं।

3। जब भी संभव हो पायथन के अंतर्निहित कार्यों का उपयोग करें

पायथन अंतर्निहित कार्यों के टन के साथ आता है जो भारी अनुकूलित हैं। इससे पहले कि आप कुछ करने के लिए अपना लूप या कस्टम फ़ंक्शन लिखें, जांचें कि क्या पायथन के पास पहले से ही इसके लिए एक फ़ंक्शन है।

अनुकूलन से पहले

यहां बताया गया है कि यदि आप बिल्ट-इन के बारे में नहीं जानते हैं, तो आप एक सूची की अधिकतम गणना कैसे कर सकते हैं:

def calculate_sum_manual(numbers):
    total = 0
    for num in numbers:  
        total += num     
    return total

def find_max_manual(numbers):
    max_val = numbers[0] 
    for num in numbers[1:]: 
        if num > max_val:    
            max_val = num   
    return max_val

test_numbers = list(range(1000000))  

start_time = time.time()
manual_sum = calculate_sum_manual(test_numbers)
manual_max = find_max_manual(test_numbers)
manual_time = time.time() - start_time
print(f"Manual approach time: {manual_time:.4f} seconds")

sum फ़ंक्शन कुल 0 के साथ शुरू होता है, फिर प्रत्येक संख्या को उस कुल में जोड़ता है। max फ़ंक्शन पहले नंबर को मानने से शुरू होता है, अधिकतम है, फिर यह देखने के लिए हर दूसरे नंबर की तुलना करता है कि क्या यह बड़ा है।

अनुकूलन के बाद

यहाँ एक ही बात पायथन के अंतर्निहित कार्यों का उपयोग कर रही है:

start_time = time.time()
builtin_sum = sum(test_numbers)    
builtin_max = max(test_numbers)    
builtin_time = time.time() - start_time
print(f"Built-in approach time: {builtin_time:.4f} seconds")
print(f"Improvement: {manual_time / builtin_time:.2f}x faster")

इतना ही! sum() सूची में सभी संख्याओं का कुल देता है, और max() सबसे बड़ी संख्या लौटाता है। एक ही परिणाम, बहुत तेजी से।

आउटपुट:

Manual approach time: 0.0805 seconds
Built-in approach time: 0.0413 seconds
Improvement: 1.95x faster

प्रदर्शन सुधार: अंतर्निहित कार्य आमतौर पर मैनुअल कार्यान्वयन की तुलना में तेज होते हैं।

यह काम क्यों करता है? पायथन के अंतर्निहित कार्यों को सी में लिखा गया है और भारी अनुकूलित किया गया है।

4। जुड़ने के साथ प्रदर्शन करने वाला पुतला स्ट्रिंग संचालन

स्ट्रिंग कॉन्टेनेशन कुछ ऐसा है जो हर प्रोग्रामर करता है, लेकिन ज्यादातर शुरुआती इसे इस तरह से करते हैं कि स्ट्रिंग्स को लंबे समय तक धीमा हो जाता है।

अनुकूलन से पहले

यहां बताया गया है कि आप + ऑपरेटर के साथ consatenating द्वारा CSV स्ट्रिंग का निर्माण कैसे कर सकते हैं:

def create_csv_plus(data):
    result = ""  # Start with an empty string
    for row in data:  # Go through each row of data
        for i, item in enumerate(row):  # Go through each item in the row
            result += str(item)  # Add the item to our result string
            if i < len(row) - 1:  # If it's not the last item
                result += ","     # Add a comma
        result += "\n"  # Add a newline after each row
    return result

# Test data: 1000 rows with 10 columns each
test_data = [[f"item_{i}_{j}" for j in range(10)] for i in range(1000)]

start_time = time.time()
csv_plus = create_csv_plus(test_data)
plus_time = time.time() - start_time
print(f"String concatenation time: {plus_time:.4f} seconds")

यह कोड हमारे CSV स्ट्रिंग पीस को पीस द्वारा बनाता है। प्रत्येक पंक्ति के लिए, यह प्रत्येक आइटम के माध्यम से जाता है, इसे एक स्ट्रिंग में परिवर्तित करता है, और इसे हमारे परिणाम में जोड़ता है। यह पंक्तियों के बीच वस्तुओं और न्यूलिन के बीच अल्पविराम जोड़ता है।

अनुकूलन के बाद

यहाँ एक ही कोड का उपयोग करके एक ही कोड है:

def create_csv_join(data):
    # For each row, join the items with commas, then join all rows with newlines
    return "\n".join(",".join(str(item) for item in row) for row in data)

start_time = time.time()
csv_join = create_csv_join(test_data)
join_time = time.time() - start_time
print(f"Join method time: {join_time:.4f} seconds")
print(f"Improvement: {plus_time / join_time:.2f}x faster")

यह सिंगल लाइन बहुत कुछ करती है! आंतरिक भाग ",".join(str(item) for item in row) प्रत्येक पंक्ति लेता है और सभी वस्तुओं को अल्पविराम के साथ जोड़ता है। बाहरी भाग "\n".join(...) उन सभी कॉम-अलग पंक्तियों को लेता है और उन्हें न्यूलिन के साथ शामिल करता है।

आउटपुट:

String concatenation time: 0.0043 seconds
Join method time: 0.0022 seconds
Improvement: 1.94x faster

प्रदर्शन सुधार: स्ट्रिंग जॉइनिंग बड़े स्ट्रिंग्स के लिए कॉन्टेनेशन की तुलना में बहुत तेज है।

यह काम क्यों करता है? जब आप स्ट्रिंग्स को समेटने के लिए += का उपयोग करते हैं, तो पायथन हर बार एक नई स्ट्रिंग ऑब्जेक्ट बनाता है क्योंकि स्ट्रिंग्स अपरिवर्तनीय होते हैं। बड़े तार के साथ, यह अविश्वसनीय रूप से बेकार हो जाता है। join विधि यह बताती है कि इसे कितनी मेमोरी की आवश्यकता है और एक बार स्ट्रिंग का निर्माण करता है।

5। स्मृति-कुशल प्रसंस्करण के लिए जनरेटर का उपयोग करें

कभी -कभी आपको अपने सभी डेटा को एक बार में मेमोरी में स्टोर करने की आवश्यकता नहीं होती है। जनरेटर आपको डेटा ऑन-डिमांड बनाने देता है, जो बड़े पैमाने पर मेमोरी को बचा सकता है।

अनुकूलन से पहले

यहां बताया गया है कि आप किसी सूची में सब कुछ संग्रहीत करके एक बड़े डेटासेट को कैसे संसाधित कर सकते हैं:

import sys

def process_large_dataset_list(n):
    processed_data = []  
    for i in range(n):
        # Simulate some data processing
        processed_value = i ** 2 + i * 3 + 42
        processed_data.append(processed_value)  # Store each processed value
    return processed_data

# Test with 100,000 items
n = 100000
list_result = process_large_dataset_list(n)
list_memory = sys.getsizeof(list_result)
print(f"List memory usage: {list_memory:,} bytes")

यह फ़ंक्शन 0 से N-1 तक संख्याओं को संसाधित करता है, हर एक पर कुछ गणना लागू करता है (इसे स्क्वायर करना, 3 से गुणा करना, और ४२ जोड़ना), और सभी परिणामों को एक सूची में संग्रहीत करता है। समस्या यह है कि हम सभी 100,000 संसाधित मूल्यों को एक ही बार में स्मृति में रख रहे हैं।

अनुकूलन के बाद

यहाँ एक जनरेटर का उपयोग करके एक ही प्रसंस्करण है:

def process_large_dataset_generator(n):
    for i in range(n):
        # Simulate some data processing
        processed_value = i ** 2 + i * 3 + 42
        yield processed_value  # Yield each value instead of storing it

# Create the generator (this doesn't process anything yet!)
gen_result = process_large_dataset_generator(n)
gen_memory = sys.getsizeof(gen_result)
print(f"Generator memory usage: {gen_memory:,} bytes")
print(f"Memory improvement: {list_memory / gen_memory:.0f}x less memory")

# Now we can process items one at a time
total = 0
for value in process_large_dataset_generator(n):
    total += value
    # Each value is processed on-demand and can be garbage collected

मुख्य अंतर है yield के बजाय appendyield कीवर्ड इसे एक जनरेटर फ़ंक्शन बनाता है – यह एक बार में एक बार में एक बार में एक बार में मान पैदा करता है।

आउटपुट:

List memory usage: 800,984 bytes
Generator memory usage: 224 bytes
Memory improvement: 3576x less memory

प्रदर्शन सुधार: जनरेटर बड़े डेटासेट के लिए “बहुत कम” कम मेमोरी का उपयोग कर सकते हैं।

यह काम क्यों करता है? जनरेटर आलसी मूल्यांकन का उपयोग करते हैं, वे केवल मूल्यों की गणना करते हैं जब आप उनसे पूछते हैं। जनरेटर ऑब्जेक्ट स्वयं छोटा है; यह सिर्फ याद करता है कि यह गणना में कहां है।

निष्कर्ष

पायथन कोड का अनुकूलन करने के लिए डराना नहीं है। जैसा कि हमने देखा है, आप सामान्य प्रोग्रामिंग कार्यों में कैसे पहुंचते हैं, इसमें छोटे परिवर्तन गति और मेमोरी उपयोग दोनों में नाटकीय सुधार हो सकते हैं। कुंजी प्रत्येक नौकरी के लिए सही उपकरण चुनने के लिए एक अंतर्ज्ञान विकसित कर रही है।

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

Bala priya c भारत का एक डेवलपर और तकनीकी लेखक है। वह गणित, प्रोग्रामिंग, डेटा साइंस और कंटेंट क्रिएशन के चौराहे पर काम करना पसंद करती है। उनकी रुचि और विशेषज्ञता के क्षेत्रों में DevOps, डेटा विज्ञान और प्राकृतिक भाषा प्रसंस्करण शामिल हैं। वह पढ़ने, लिखने, कोडिंग और कॉफी का आनंद लेती है! वर्तमान में, वह ट्यूटोरियल, हाउ-टू गाइड, ओपिनियन पीस, और बहुत कुछ लिखकर डेवलपर समुदाय के साथ अपने ज्ञान को सीखने और साझा करने पर काम कर रही है। बाला भी आकर्षक संसाधन ओवरव्यू और कोडिंग ट्यूटोरियल बनाता है।





स्रोत लिंक