अनपैकिंग का मतलब है किसी कलेक्शन, जैसे list, tuple या dict, के एलिमेंट को इटरेशन की मदद से निकालना।
इस तरह निकाली गई वैल्यू को उसी स्टेटमेंट में वेरिएबलो को असाइन किया जा सकता है।
इसका एक बहुत आम उदाहरण for item in list है, जिसमें इटरेशन के दौरान item बारी-बारी से हर list एलिमेंट की वैल्यू ले लेता है।
एकाधिक असाइनमेंट वह सुविधा है जिसमें एक ही स्टेटमेंट में कई वेरिएबलो को अनपैक की गई वैल्यू असाइन की जा सकती हैं।
इससे कोड ज़्यादा संक्षिप्त और पढ़ने में आसान हो जाता है। इसके लिए असाइन किए जाने वाले वेरिएबलो को कॉमा से अलग किया जाता है, जैसे first, second, third = (1,2,3) या for index, item in enumerate(iterable)।
खास ऑपरेटर * और ** अक्सर अनपैकिंग में इस्तेमाल होते हैं।
* की मदद से कई lists/tuples को अनपैक करके एक नए साझा list/tuple में डालकर एक ही list/tuple बनाया जा सकता है।
** की मदद से कई डिक्शनरी को अनपैक करके एक नए साझा dict में डालकर एक ही डिक्शनरी बनाई जा सकती है।
जब * ऑपरेटर का उपयोग किसी कलेक्शन के बिना किया जाता है, तो यह कई वैल्यू को पैक करके एक list बना देता है।
एकाधिक असाइनमेंट में इसका इस्तेमाल अक्सर उन सभी "बचे हुए" एलिमेंट को एक ही वेरिएबल में डालने के लिए किया जाता है जिनके लिए अलग असाइनमेंट नहीं हैं।
Python में ऐसे फंक्शन बनाते या इस्तेमाल करते समय, जो किसी भी संख्या में पोज़िशनल या कीवर्ड आर्गुमेंट ले सकते हैं, इसी अनपैकिंग/पैकिंग व्यवहार का फायदा उठाना आम बात है।
आप अक्सर देखेंगे कि ऐसे "खास" पैरामीटर def some_function(*args, **kwargs) की तरह परिभाषित किए जाते हैं और "खास" आर्गुमेंट some_function(*some_tuple, **some_dict) की तरह इस्तेमाल होते हैं।
*<variable_name> और **<variable_name> को * और ** से भ्रमित नहीं करना चाहिए। जहाँ * और ** क्रमशः गुणा और घातांक के लिए इस्तेमाल होते हैं, वहीं *<variable_name> और **<variable_name> पैकिंग और अनपैकिंग ऑपरेटर के रूप में इस्तेमाल होते हैं।
एकाधिक असाइनमेंट में असाइनमेंट ऑपरेटर (=) के बाईं ओर लिखे वेरिएबलो की संख्या दाईं ओर की वैल्यू की संख्या से मेल खानी चाहिए।
वैल्यू को अलग करने के लिए कॉमा , लगाइए:
>>> a, b = 1, 2
>>> a
1
अगर किसी एकाधिक असाइनमेंट में दी गई वैल्यू के लिए वेरिएबलो की संख्या गलत हो, तो एक ValueError फेंकी जाती है:
>>> x, y, z = 1, 2
ValueError: too many values to unpack (expected 3, got 2)
एकाधिक असाइनमेंट किसी एक डेटा टाइप तक सीमित नहीं है:
>>> x, y, z = 1, "Hello", True
>>> x
1
>>> y
'Hello'
>>> z
True
एकाधिक असाइनमेंट की मदद से lists के एलिमेंट आपस में बदले जा सकते हैं।
यह तरीका सॉर्टिंग एल्गोरिदम में काफी आम है।
उदाहरण के लिए:
>>> numbers = [1, 2]
>>> numbers[0], numbers[1] = numbers[1], numbers[0]
>>> numbers
[2, 1]
चूँकि tuples अपरिवर्तनीय होते हैं, इसलिए आप किसी tuple के एलिमेंट आपस में नहीं बदल सकते।
नीचे दिए उदाहरणों में lists इस्तेमाल हुए हैं, लेकिन यही बातें tuples पर भी लागू होती हैं।
Python में किसी list/tuple/dict के एलिमेंट को अलग-अलग वेरिएबलो में अनपैक करना संभव है।
चूँकि lists/tuples में वैल्यू एक तय क्रम में होती हैं, इसलिए उन्हें उसी क्रम में वेरिएबलो में अनपैक किया जाता है:
>>> fruits = ["apple", "banana", "cherry"]
>>> x, y, z = fruits
>>> x
"apple"
अगर कुछ वैल्यू की ज़रूरत नहीं है, तो उन्हें _ से चिह्नित कर सकते हैं:
>>> fruits = ["apple", "banana", "cherry"]
>>> _, _, z = fruits
>>> z
"cherry"
किसी list या tuple के अंदर मौजूद list/tuple से वैल्यू अनपैक करके असाइन करना (जिसे नेस्टेड लिस्ट/टपल भी कहते हैं) उसी तरह काम करता है जैसे सामान्य अनपैकिंग करती है, लेकिन इसमें अक्सर वैल्यू का संदर्भ या स्थान साफ़ करने के लिए क्वालिफायर लगाने पड़ते हैं:
>>> fruits_vegetables = [["apple", "banana"], ["carrot", "potato"]]
>>> [[a, b], [c, d]] = fruits_vegetables
>>> a
"apple"
>>> d
"potato"
आप किसी नेस्टेड list/tuple के सिर्फ एक हिस्से को भी गहराई से अनपैक कर सकते हैं:
>>> fruits_vegetables = [["apple", "banana"], ["carrot", "potato"]]
>>> [a, [c, d]] = fruits_vegetables
>>> a
["apple", "banana"]
>>> c
"carrot"
अगर अनपैकिंग में वेरिएबलो का स्थान गलत हो और/या वैल्यू की संख्या गलत हो, तो आपको ValueError मिलती है:
>>> fruits_vegetables = [["apple", "banana"], ["carrot", "potato"]]
>>> [[a, b], [d]] = fruits_vegetables
ValueError: too many values to unpack (expected 1)
* की मदद से ऐरे/टपल अनपैक करनाकिसी list/tuple को अनपैक करते समय आप "बची हुई" वैल्यू पकड़ने के लिए * ऑपरेटर का इस्तेमाल कर सकते हैं।
यह list/tuple को स्लाइस करने से ज़्यादा साफ़ है (जो कुछ स्थितियों में पढ़ने में कम आसान होता है)।
उदाहरण के लिए, हम पहला एलिमेंट निकाल सकते हैं और बाकी वैल्यू को पहले एलिमेंट के बिना एक नए list में पैक कर सकते हैं:
>>> fruits = ["apple", "banana", "cherry", "orange", "kiwi", "melon", "mango"]
>>> x, *last = fruits
>>> x
"apple"
>>> last
["banana", "cherry", "orange", "kiwi", "melon", "mango"]
हम list के शुरू और अंत की वैल्यू भी निकाल सकते हैं और बीच की सभी वैल्यू को एक साथ समूहित कर सकते हैं:
>>> fruits = ["apple", "banana", "cherry", "orange", "kiwi", "melon", "mango"]
>>> x, *middle, y, z = fruits
>>> y
"melon"
>>> middle
["banana", "cherry", "orange", "kiwi"]
हम गहरी अनपैकिंग में भी * का इस्तेमाल कर सकते हैं:
>>> fruits_vegetables = [["apple", "banana", "melon"], ["carrot", "potato", "tomato"]]
>>> [[a, *rest], b] = fruits_vegetables
>>> a
"apple"
>>> rest
["banana", "melon"]
डिक्शनरी को अनपैक करना list/tuple को अनपैक करने से थोड़ा अलग है।
डिक्शनरी पर इटरेशन अपने आप की पर होता है।
इसलिए dict को अनपैक करते समय आप सिर्फ की अनपैक कर सकते हैं, वैल्यू नहीं:
>>> fruits_inventory = {"apple": 6, "banana": 2, "cherry": 3}
>>> x, y, z = fruits_inventory
>>> x
"apple"
अगर आप वैल्यू अनपैक करना चाहते हैं, तो <dict>.values() मेथड का इस्तेमाल कर सकते हैं:
>>> fruits_inventory = {"apple": 6, "banana": 2, "cherry": 3}
>>> x, y, z = fruits_inventory.values()
>>> x
6
अगर की और वैल्यू दोनों की ज़रूरत हो, तो <dict>.items() मेथड का इस्तेमाल कीजिए।
<dict>.items() एक इटरेबल व्यू बनाता है जिसमें की-वैल्यू जोड़े होते हैं।
इन्हें एक tuple में अनपैक किया जा सकता है:
>>> fruits_inventory = {"apple": 6, "banana": 2, "cherry": 3}
>>> x, y, z = fruits_inventory.items()
>>> x
("apple", 6)
पैकिंग कई वैल्यू को एक ऐसे list में समूहित करने की सुविधा है जिसे किसी वेरिएबल को असाइन किया जाता है।
यह तब काम आता है जब आप वैल्यू को अनपैक करना, उनमें बदलाव करना और फिर नतीजों को वापस किसी वेरिएबल में पैक करना चाहते हैं।
इससे 2 या उससे ज़्यादा lists/tuples/dicts को आपस में मर्ज करना भी संभव हो जाता है।
* की मदद से ऐरे/टपल पैक करना* ऑपरेटर की मदद से list/tuple को पैक किया जा सकता है।
यह सभी वैल्यू को एक list/tuple में पैक कर देता है।
>>> fruits = ("apple", "banana", "cherry")
>>> more_fruits = ["orange", "kiwi", "melon", "mango"]
# fruits and more_fruits are unpacked and then their elements are packed into combined_fruits
>>> combined_fruits = *fruits, *more_fruits
# If there is no * on to the left of the "=" the result is a tuple
>>> combined_fruits
("apple", "banana", "cherry", "orange", "kiwi", "melon", "mango")
# If the * operator is used on the left side of "=" the result is a list.
# Note the trailing comma.
>>> *combined_fruits_too, = *fruits, *more_fruits
>>> combined_fruits_too
['apple', 'banana', 'cherry', 'orange', 'kiwi', 'melon', 'mango']
# A list literal can be used instead, but might not be as readable.
>>> [*combined_fruits_too] = *fruits, *more_fruits
>>> combined_fruits_too
['apple', 'banana', 'cherry', 'orange', 'kiwi', 'melon', 'mango']
* और ** के इस्तेमाल के बारे में ज़्यादा जानकारी के लिए PEP 3132 और PEP 448 देखिए।
** की मदद से डिक्शनरी पैक करनाडिक्शनरी को पैक करने के लिए ** ऑपरेटर का इस्तेमाल किया जाता है।
यह एक डिक्शनरी के सभी की-वैल्यू जोड़ों को दूसरी डिक्शनरी में पैक कर देता है, या दो डिक्शनरी को आपस में मिला देता है।
>>> fruits_inventory = {"apple": 6, "banana": 2, "cherry": 3}
>>> more_fruits_inventory = {"orange": 4, "kiwi": 1, "melon": 2, "mango": 3}
# fruits_inventory and more_fruits_inventory are unpacked into key-values pairs and combined.
>>> combined_fruits_inventory = {**fruits_inventory, **more_fruits_inventory}
# then the pairs are packed into combined_fruits_inventory
>>> combined_fruits_inventory
{"apple": 6, "banana": 2, "cherry": 3, "orange": 4, "kiwi": 1, "melon": 2, "mango": 3}
* और ** का उपयोगजब आप ऐसा फंक्शन बनाते हैं जो किसी भी संख्या में आर्गुमेंट ले सकता है, तो फंक्शन की परिभाषा में *args या **kwargs इस्तेमाल कर सकते हैं।
*args का इस्तेमाल किसी भी संख्या में पोज़िशनल (बिना कीवर्ड वाले) आर्गुमेंट पैक करने के लिए होता है और
**kwargs का इस्तेमाल किसी भी संख्या में कीवर्ड आर्गुमेंट पैक करने के लिए होता है।
*args का उपयोग:
# This function is defined to take any number of positional arguments
>>> def my_function(*args):
... print(args)
# Arguments given to the function are packed into a tuple
>>> my_function(1, 2, 3)
(1, 2, 3)
>>> my_function("Hello")
("Hello")
>>> my_function(1, 2, 3, "Hello", "Mars")
(1, 2, 3, "Hello", "Mars")
**kwargs का उपयोग:
# This function is defined to take any number of keyword arguments
>>> def my_function(**kwargs):
... print(kwargs)
# Arguments given to the function are packed into a dictionary
>>> my_function(a=1, b=2, c=3)
{"a": 1, "b": 2, "c": 3}
*args और **kwargs को एक साथ भी इस्तेमाल किया जा सकता है:
>>> def my_function(*args, **kwargs):
... print(sum(args))
... for key, value in kwargs.items():
... print(str(key) + " = " + str(value))
>>> my_function(1, 2, 3, a=1, b=2, c=3)
6
a = 1
b = 2
c = 3
आप *args से पहले पैरामीटर भी लिख सकते हैं, ताकि कुछ खास पोज़िशनल आर्गुमेंट भी लिए जा सकें।
ऐसे में अलग-अलग कीवर्ड आर्गुमेंट **kwargs से पहले लिखने पड़ते हैं।
आर्गुमेंट का ढाँचा इस तरह होना चाहिए:
def my_function(<positional_args>, *args, <key-word_args>, **kwargs)
अगर आप इस क्रम का पालन नहीं करते, तो आपको एरर मिलती है।
>>> def my_function(a, b, *args):
... print(a)
... print(b)
... print(args)
>>> my_function(1, 2, 3, 4, 5)
1
2
(3, 4, 5)
गलत क्रम में आर्गुमेंट लिखने पर एरर मिलती है:
>>> def my_function(*args, a, b):
... print(args)
>>>my_function(1, 2, 3, 4, 5)
Traceback (most recent call last):
File "c:\something.py", line 3, in <module>
my_function(1, 2, 3, 4, 5)
TypeError: my_function() missing 2 required keyword-only arguments: 'a' and 'b'
आप * की मदद से आर्गुमेंट के किसी list/tuple को फंक्शन कॉल में अनपैक कर सकते हैं।
यह उन फंक्शन के लिए बहुत काम का है जो iterable नहीं लेते:
>>> def my_function(a, b, c):
... print(c)
... print(b)
... print(a)
numbers = [1, 2, 3]
>>> my_function(*numbers)
3
2
1
zip() बिल्ट-इन के साथ * अनपैकिंग का इस्तेमाल एक और आम उदाहरण है।
zip() फंक्शन कई इटरेबल लेता है और हर iterable से आई वैल्यू को एक साथ समूहित करके tuples का एक list लौटाता है:
>>> values = (['x', 'y', 'z'], [1, 2, 3], [True, False, True])
>>> a, *rest = zip(*values)
>>> rest
[('y', 2, False), ('z', 3, True)]