python - tutorial - पायथन में आंशिक सूची अनपैक




python tutorial (8)

लेकिन कभी-कभी मैं सूची के आकार को दाईं ओर नहीं जानता, उदाहरण के लिए अगर मैं विभाजन () का उपयोग करता हूं।

हाँ, जब मुझे सीमा> 1 के साथ मामले मिल गए हैं (इसलिए मैं विभाजन का उपयोग नहीं कर सकता) तो मैं आमतौर पर इसके लिए प्रसन्न होता हूं:

def paddedsplit(s, find, limit):
    parts= s.split(find, limit)
    return parts+[parts[0][:0]]*(limit+1-len(parts))

username, password, hash= paddedsplit(credentials, ':', 2)

( parts[0][:0] वहाँ एक खाली 'str' या 'यूनिकोड' प्राप्त करने के लिए है, उनमें से जो भी विभाजित उत्पादन से मेल खाता है। आप चाहें तो किसी का भी उपयोग नहीं कर सकते हैं।)

पायथन में, असाइनमेंट ऑपरेटर इस तरह से एक सूची या टुपल को चर में अनपैक कर सकता है:

l = (1, 2)
a, b = l # Here goes auto unpack

लेकिन मुझे सूची में दाईं ओर आइटम गणना के रूप में बाईं ओर समान नाम निर्दिष्ट करने की आवश्यकता है। लेकिन कभी-कभी मैं सूची के आकार को दाईं ओर नहीं जानता, उदाहरण के लिए, यदि मैं विभाजन () का उपयोग करता हूं।

उदाहरण:

a, b = "length=25".split("=") # This will result in a="length" and b=25

लेकिन निम्नलिखित कोड में त्रुटि होगी:

a, b = "DEFAULT_LENGTH".split("=") # Error, list has only one item

क्या यह संभव है कि किसी भी तरह से ऊपर के उदाहरण में सूची को अनपैक किया जाए ताकि मैं एक = "DEFAULT_LENGTH" प्राप्त कर सकूं और b None बराबर है या सेट नहीं है? एक सीधा रास्ता लंबा दिखता है:

a = b = None
if "=" in string :
  a, b = string.split("=")
else :
  a = string

आप इसे करने के लिए एक सहायक कार्य लिख सकते हैं।

>>> def pack(values, size):
...     if len(values) >= size:
...         return values[:size]
...     return values + [None] * (size - len(values))
...
>>> a, b = pack('a:b:c'.split(':'), 2)
>>> a, b
('a', 'b')
>>> a, b = pack('a'.split(':'), 2)
>>> a, b
('a', None)

एक विकल्प के रूप में, शायद एक नियमित अभिव्यक्ति का उपयोग करें?

>>> import re
>>> unpack_re = re.compile("(\w*)(?:=(\w*))?")

>>> x = "DEFAULT_LENGTH"
>>> unpack_re.match(x).groups()
('DEFAULT_LENGTH', None)

>>> y = "length=107"
>>> unpack_re.match(y).groups()
('length', '107')

यदि आप सुनिश्चित करते हैं कि re.match () हमेशा सफल होता है, .groups () हमेशा आपके ट्यूपल में अनपैक करने के लिए तत्वों की सही संख्या लौटाएगा, ताकि आप सुरक्षित रूप से कर सकें

a,b = unpack_re.match(x).groups()

कई अन्य समाधान प्रस्तावित किए गए हैं, लेकिन मुझे अभी भी सबसे सीधा कहना है

a, b = string.split("=") if "=" in string else (string, None)

जब तक आप पाइथन 3 का उपयोग नहीं कर रहे हैं, तब तक यह आपके लिए किसी काम का नहीं हो सकता है। हालाँकि, पूर्णता के लिए, यह ध्यान देने योग्य है कि वहां पेश किया गया विस्तारित ट्यूपल अनपैकिंग आपको चीजों को करने की अनुमति देता है:

>>> a, *b = "length=25".split("=")
>>> a,b
("length", ['25'])
>>> a, *b = "DEFAULT_LENGTH".split("=")
>>> a,b
("DEFAULT_LENGTH", [])

Ie tuple unpacking अब इसी तरह से काम करता है कि यह तर्क अनपैकिंग में कैसे होता है, इसलिए आप "बाकी वस्तुओं" को * साथ निरूपित कर सकते हैं, और उन्हें एक (संभवतः खाली) सूची के रूप में प्राप्त कर सकते हैं।

विभाजन शायद आपके लिए सबसे अच्छा समाधान है जो आप कर रहे हैं।


मैं इसका उपयोग करने की अनुशंसा नहीं करता, लेकिन यहां केवल मनोरंजन के लिए कुछ कोड है जो वास्तव में आप चाहते हैं। जब आप unpack(<sequence>) , तो unpack फ़ंक्शन स्रोत के वास्तविक रेखा को खोजने के लिए inspect मॉड्यूल inspect उपयोग करता है, जहां फ़ंक्शन को बुलाया गया था, फिर उस लाइन को पार्स करने के लिए ast मॉड्यूल का उपयोग करता है और अनपेक्षित होने वाले चर की संख्या की गणना करता है।

चेतावनियां:

  • एकाधिक असाइनमेंट के लिए (जैसे (a,b) = c = unpack([1,2,3]) ), यह केवल असाइनमेंट में पहले शब्द का उपयोग करता है
  • अगर यह सोर्स कोड नहीं पा रहा है तो यह काम नहीं करेगा (जैसे कि आप इसे उत्तर से बुला रहे हैं)
  • यह काम नहीं करेगा यदि असाइनमेंट स्टेटमेंट कई लाइनों को फैलाता है

कोड:

import inspect, ast
from itertools import islice, chain, cycle

def iter_n(iterator, n, default=None):
    return islice(chain(iterator, cycle([default])), n)

def unpack(sequence, default=None):
    stack = inspect.stack()
    try:
        frame = stack[1][0]
        source = inspect.getsource(inspect.getmodule(frame)).splitlines()
        line = source[frame.f_lineno-1].strip()
        try:
            tree = ast.parse(line, 'whatever', 'exec')
        except SyntaxError:
            return tuple(sequence)
        exp = tree.body[0]
        if not isinstance(exp, ast.Assign):
            return tuple(sequence)
        exp = exp.targets[0]
        if not isinstance(exp, ast.Tuple):
            return tuple(sequence)
        n_items = len(exp.elts)
        return tuple(iter_n(sequence, n_items, default))
    finally:
        del stack

# Examples
if __name__ == '__main__':
    # Extra items are discarded
    x, y = unpack([1,2,3,4,5])
    assert (x,y) == (1,2)
    # Missing items become None
    x, y, z = unpack([9])
    assert (x, y, z) == (9, None, None)
    # Or the default you provide
    x, y, z = unpack([1], 'foo')
    assert (x, y, z) == (1, 'foo', 'foo')
    # unpack() is equivalent to tuple() if it's not part of an assignment
    assert unpack('abc') == ('a', 'b', 'c')
    # Or if it's part of an assignment that isn't sequence-unpacking
    x = unpack([1,2,3])
    assert x == (1,2,3)
    # Add a comma to force tuple assignment:
    x, = unpack([1,2,3])
    assert x == 1
    # unpack only uses the first assignment target
    # So in this case, unpack('foobar') returns tuple('foo')
    (x, y, z) = t = unpack('foobar')
    assert (x, y, z) == t == ('f', 'o', 'o')
    # But in this case, it returns tuple('foobar')
    try:
        t = (x, y, z) = unpack('foobar')
    except ValueError as e:
        assert str(e) == 'too many values to unpack'
    else:
        raise Exception("That should have failed.")
    # Also, it won't work if the call spans multiple lines, because it only
    # inspects the actual line where the call happens:
    try:
        (x, y, z) = unpack([
            1, 2, 3, 4])
    except ValueError as e:
        assert str(e) == 'too many values to unpack'
    else:
        raise Exception("That should have failed.")

सबसे अच्छा तरीका विभाजन स्ट्रिंग विधि का उपयोग कर रहा है:

सेप की पहली घटना पर स्ट्रिंग को विभाजित करें, और विभाजक से पहले भाग वाले विभाजक के बाद एक 3-ट्यूपल लौटें, और विभाजक के बाद का हिस्सा। यदि विभाजक नहीं मिला है, तो स्ट्रिंग से युक्त 3-ट्यूपल को वापस करें, इसके बाद दो खाली तार हैं।

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

>>> inputstr = "length=25"
>>> inputstr.partition("=")
('length', '=', '25')
>>> name, _, value = inputstr.partition("=")
>>> print name, value
length 25

यह स्ट्रिंग के लिए भी काम करता है जिसमें = :

>>> inputstr = "DEFAULT_VALUE"
>>> inputstr.partition("=")
('DEFAULT_VALUE', '', '')

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

>>> x = "DEFAULT_LENGTH"

>>> a = x.split("=")[0]
>>> b = "=".join(x.split("=")[1:])

>>> print (a, b)
('DEFAULT_LENGTH', '')

..और जब x = "length=25" :

('length', '25')

आसानी से एक समारोह या मेमने में बदल गया:

>>> part = lambda x: (x.split("=")[0], "=".join(x.split("=")[1:]))
>>> part("length=25")
('length', '25')
>>> part('DEFAULT_LENGTH')
('DEFAULT_LENGTH', '')

# this will result in a="length" and b="25"
a, b = "length=25".partition("=")[::2]

# this will result in a="DEFAULT_LENGTH" and b=""
a, b = "DEFAULT_LENGTH".partition("=")[::2]




python