Why does splatting create a tuple on the rhs but a list on the lhs?Star * operator on left vs right side of an assignment statementHow do I check if a list is empty?Finding the index of an item given a list containing it in PythonWhat does the “yield” keyword do?What is the difference between Python's list methods append and extend?Does Python have a ternary conditional operator?What does if __name__ == “__main__”: do?How to make a flat list out of list of lists“Least Astonishment” and the Mutable Default ArgumentWhat are “named tuples” in Python?Why not inherit from List<T>?

Why did it take so long for Germany to allow electric scooters / e-rollers on the roads?

The disk image is 497GB smaller than the target device

What is the use case for non-breathable waterproof pants?

Is it legal to have an abortion in another state or abroad?

What did the 'turbo' button actually do?

Can we assume that a hash function with high collision resistance also means highly uniform distribution?

Where is Jon going?

Does "was machen sie" have the greeting meaning of "what do you do"?

A burglar's sunglasses, a lady's odyssey

Why isn't 'chemically-strengthened glass' made with potassium carbonate? To begin with?

Why is the Eisenstein ideal paper so great?

Navigating a quick return to previous employer

Why is this integration method not valid?

If I arrive in the UK, and then head to mainland Europe, does my Schengen visa 90 day limit start when I arrived in the UK, or mainland Europe?

How to teach an undergraduate course without having taken that course formally before?

“For nothing” = “pour rien”?

First Program Tic-Tac-Toe

Interpreation ROC AUC score

3 prong range outlet

How can I prevent holy aura from a human body from radiating too strongly?

How would a developer who mostly fixed bugs for years at a company call out their contributions in their CV?

How does the Earth's center produce heat?

Why is 'additive' EQ more difficult to use than 'subtractive'?

Can you still travel to America on the ESTA waiver program if you have been to Iran in transit?



Why does splatting create a tuple on the rhs but a list on the lhs?


Star * operator on left vs right side of an assignment statementHow do I check if a list is empty?Finding the index of an item given a list containing it in PythonWhat does the “yield” keyword do?What is the difference between Python's list methods append and extend?Does Python have a ternary conditional operator?What does if __name__ == “__main__”: do?How to make a flat list out of list of lists“Least Astonishment” and the Mutable Default ArgumentWhat are “named tuples” in Python?Why not inherit from List<T>?






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;








13















Consider, for example,



squares = *map((2).__rpow__, range(5)),
squares
# (0, 1, 4, 9, 16)

*squares, = map((2).__rpow__, range(5))
squares
# [0, 1, 4, 9, 16]


So, all else being equal we get a list when splatting on the lhs and a tuple when splatting on the rhs.



Why?



Is this by design, and if yes, what's the rationale? Or, if not, are there any technical reasons? Or is this just how it is, no particular reason?










share|improve this question



















  • 1





    Also, relevant, though not a dupe. link

    – Paritosh Singh
    9 hours ago

















13















Consider, for example,



squares = *map((2).__rpow__, range(5)),
squares
# (0, 1, 4, 9, 16)

*squares, = map((2).__rpow__, range(5))
squares
# [0, 1, 4, 9, 16]


So, all else being equal we get a list when splatting on the lhs and a tuple when splatting on the rhs.



Why?



Is this by design, and if yes, what's the rationale? Or, if not, are there any technical reasons? Or is this just how it is, no particular reason?










share|improve this question



















  • 1





    Also, relevant, though not a dupe. link

    – Paritosh Singh
    9 hours ago













13












13








13


3






Consider, for example,



squares = *map((2).__rpow__, range(5)),
squares
# (0, 1, 4, 9, 16)

*squares, = map((2).__rpow__, range(5))
squares
# [0, 1, 4, 9, 16]


So, all else being equal we get a list when splatting on the lhs and a tuple when splatting on the rhs.



Why?



Is this by design, and if yes, what's the rationale? Or, if not, are there any technical reasons? Or is this just how it is, no particular reason?










share|improve this question
















Consider, for example,



squares = *map((2).__rpow__, range(5)),
squares
# (0, 1, 4, 9, 16)

*squares, = map((2).__rpow__, range(5))
squares
# [0, 1, 4, 9, 16]


So, all else being equal we get a list when splatting on the lhs and a tuple when splatting on the rhs.



Why?



Is this by design, and if yes, what's the rationale? Or, if not, are there any technical reasons? Or is this just how it is, no particular reason?







python python-3.x list tuples splat






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 10 hours ago









Flimzy

41.5k1368104




41.5k1368104










asked 10 hours ago









Paul PanzerPaul Panzer

32.4k21846




32.4k21846







  • 1





    Also, relevant, though not a dupe. link

    – Paritosh Singh
    9 hours ago












  • 1





    Also, relevant, though not a dupe. link

    – Paritosh Singh
    9 hours ago







1




1





Also, relevant, though not a dupe. link

– Paritosh Singh
9 hours ago





Also, relevant, though not a dupe. link

– Paritosh Singh
9 hours ago












4 Answers
4






active

oldest

votes


















8














This is specified in PEP-0448 disadvantages




Whilst *elements, = iterable causes elements to be a list, elements = *iterable, causes elements to be a tuple. The reason for this may confuse people unfamiliar with the construct.




Also as per: PEP-3132 specification




This PEP proposes a change to iterable unpacking syntax, allowing to specify a "catch-all" name which will be assigned a list of all items not assigned to a "regular" name.




Also mentioned here: Python-3 exprlists




Except when part of a list or set display, an expression list containing at least one comma yields a tuple.

The trailing comma is required only to create a single tuple (a.k.a. a singleton); it is optional in all other cases. A single expression without a trailing comma doesn’t create a tuple, but rather yields the value of that expression. (To create an empty tuple, use an empty pair of parentheses: ().)




This might also be seen in a simpler example here, where elements in a list



In [27]: *elements, = range(6) 

In [28]: elements
Out[28]: [0, 1, 2, 3, 4, 5]


and here, where elements is a tuple



In [13]: elements = *range(6), 

In [14]: elements
Out[14]: (0, 1, 2, 3, 4, 5)


From what I could understand from the comments and the other answers:



  • The first behaviour is to keep in-line with the existing arbitrary argument lists used in functions ie.*args


  • The second behaviour is to be able to use the variables on LHS further down in the evaluation, so making it a list, a mutable value rather than a tuple makes more sense






share|improve this answer




















  • 4





    While the PEP does refer to a reason, it doesn't appear to actually give one.

    – Paul Panzer
    10 hours ago











  • Yes it doesn't, I am trying to find a reason myself @PaulPanzer :)

    – Devesh Kumar Singh
    10 hours ago






  • 2





    PEP 3132 says that *elements, = range(6) will create a list on the left-hand side. PEP 448 says that elements = *range(6), has generalized unpacking in a tuple display, (*range(6),) with implicit parentheses, creating a tuple on the right-hand side. (cc @PaulPanzer)

    – Andras Deak
    10 hours ago












  • I added what explanation I could gain from the comments above by Andras (Thanks Andras :) ) and the other answers @PaulPanzer

    – Devesh Kumar Singh
    9 hours ago


















7














There is an indication of the reason why at the end of PEP 3132 -- Extended Iterable Unpacking:




Acceptance



After a short discussion on the python-3000 list [1], the
PEP was accepted by Guido in its current form. Possible changes
discussed were:



[...]



Make the starred target a tuple instead of a list. This would be
consistent with a function's *args, but make further processing of the
result harder.




[1] https://mail.python.org/pipermail/python-3000/2007-May/007198.html



So, the advantage of having a mutable list instead of an immutable tuple seems to be the reason.






share|improve this answer






























    6














    not a complete answer, but disassembling gives some clues:



    from dis import dis

    def a():
    squares = (*map((2).__rpow__, range(5)),)
    # print(squares)

    print(dis(a))


    disassembles as



     5 0 LOAD_GLOBAL 0 (map)
    2 LOAD_CONST 1 (2)
    4 LOAD_ATTR 1 (__rpow__)
    6 LOAD_GLOBAL 2 (range)
    8 LOAD_CONST 2 (5)
    10 CALL_FUNCTION 1
    12 CALL_FUNCTION 2
    14 BUILD_TUPLE_UNPACK 1
    16 STORE_FAST 0 (squares)
    18 LOAD_CONST 0 (None)
    20 RETURN_VALUE


    while



    def b():
    *squares, = map((2).__rpow__, range(5))
    print(dis(b))


    results in



     11 0 LOAD_GLOBAL 0 (map)
    2 LOAD_CONST 1 (2)
    4 LOAD_ATTR 1 (__rpow__)
    6 LOAD_GLOBAL 2 (range)
    8 LOAD_CONST 2 (5)
    10 CALL_FUNCTION 1
    12 CALL_FUNCTION 2
    14 UNPACK_EX 0
    16 STORE_FAST 0 (squares)
    18 LOAD_CONST 0 (None)
    20 RETURN_VALUE


    the doc on UNPACK_EX states:




    UNPACK_EX(counts)



    Implements assignment with a starred target: Unpacks an iterable in TOS into individual values, where the total number of values can be
    smaller than the number of items in the iterable: one of the new
    values will be a list of all leftover items.



    The low byte of counts is the number of values before the list value, the high byte of counts the number of values after it. The
    resulting values are put onto the stack right-to-left.




    (emphasis mine). while BUILD_TUPLE_UNPACK returns a tuple:




    BUILD_TUPLE_UNPACK(count)



    Pops count iterables from the stack, joins them in a single tuple, and pushes the result. Implements iterable unpacking in tuple displays
    (*x, *y, *z).







    share|improve this answer


















    • 2





      So would that be a technical reason or no reason?

      – Paul Panzer
      10 hours ago






    • 1





      no, i do not see an argument for a reason here... it might be beneficial to have something mutable in the second case... but that is just a guess.

      – hiro protagonist
      9 hours ago


















    2














    For the RHS, there is not much of an issue. the answer here states it well:




    We have it working as it usually does in function calls. It expands
    the contents of the iterable it is attached to. So, the statement:



    elements = *iterable


    can be viewed as:



    elements = 1, 2, 3, 4,


    which is another way for a tuple to be initialized.




    Now, for the LHS,
    Yes, there are technical reasons for the LHS using a list, as indicated in the discussion around the initial PEP 3132 for extending unpacking



    The reasons can be gleaned from the conversation on the PEP(added at the end).



    Essentially it boils down to a couple key factors:



    • The LHS needed to support a "starred expression" that was not necessarily restricted to the end only.

    • The RHS needed to allow various sequence types to be accepted, including iterators.

    • The combination of the two points above required manipulation/mutation of the contents after accepting them into the starred expression.

    • An alternative approach to handling, one to mimic the iterator fed on the RHS, even leaving implementation difficulties aside, was shot down by Guido for its inconsistent behaviour.

    • Given all the factors above, a tuple on LHS would have to be a list first, and then converted. This approach would then just add overhead, and did not invite any further discussion.

    Summary: A combination of various factors led to the decision to allow a list on the LHS, and the reasons fed off of each other.




    Relevant extract for disallowing inconsistent types:




    The important use case in Python for the proposed semantics is when
    you have a variable-length record, the first few items of which are
    interesting, and the rest of which is less so, but not unimportant.
    (If you wanted to throw the rest away, you'd just write a, b, c =
    x[:3] instead of a, b, c, *d = x.) It is much more convenient for this
    use case if the type of d is fixed by the operation, so you can count
    on its behavior.



    There's a bug in the design of filter() in Python 2 (which will be
    fixed in 3.0 by turning it into an iterator BTW): if the input is a
    tuple, the output is a tuple too, but if the input is a list or
    anything else
    , the output is a list. That's a totally insane
    signature, since it means that you can't count on the result being a
    list, nor on it being a tuple -- if you need it to be one or the
    other, you have to convert it to one, which is a waste of time and
    space. Please let's not repeat this design bug.

    -Guido






    I have also tried to recreate a partially quoted conversation that pertains to the summary above.Source
    Emphasis mine.



    1.




    In argument lists, *args exhausts iterators, converting them to
    tuples. I think it would be confusing if *args in tuple unpacking
    didn't do the same thing.



    This brings up the question of why the patch produces lists, not
    tuples.
    What's the reasoning behind that?



    STeVe




    2.




    IMO, it's likely that you would like to further process the resulting
    sequence, including modifying it.



    Georg




    3.




    Well if that's what you're aiming at, then I'd expect it to be more
    useful to have the unpacking generate not lists, but the same type you
    started with,
    e.g. if I started with a string, I probably want to
    continue using strings::
    --additional text snipped off




    4.




    When dealing with an iterator, you don't know the length in advance,
    so the only way to get a tuple would be to produce a list first and
    then create a tuple from it.

    Greg




    5.




    Yep. That was one of the reasons it was suggested that the *args
    should only appear at the end of the tuple unpacking.



    STeVe




    couple convos skipped



    6.




    I don't think that returning the type given is a goal that should be
    attempted, because it can only ever work for a fixed set of known
    types.
    Given an arbitrary sequence type, there is no way of knowing
    how to create a new instance of it with specified contents.



    -- Greg




    skipped convos



    7.





    I'm suggesting, that:



    • lists return lists

    • tuples return tuples

    • XYZ containers return XYZ containers

    • non-container iterables return iterators.



    How do you propose to distinguish between the last two cases?
    Attempting to slice it and catching an exception is not acceptable,
    IMO, as it can too easily mask bugs.



    -- Greg




    8.




    But I expect less useful. It won't support "a, *b, c = "
    either.
    From an implementation POV, if you have an unknown object on
    the RHS, you have to try slicing it before you try iterating over it;
    this may cause problems
    e.g. if the object happens to be a defaultdict
    -- since x[3:] is implemented as x[slice(None, 3, None)], the defaultdict will give you its default value. I'd much rather define
    this in terms of iterating over the object until it is exhausted,
    which can be optimized for certain known types like lists and tuples.



    --
    --Guido van Rossum







    share|improve this answer

























      Your Answer






      StackExchange.ifUsing("editor", function ()
      StackExchange.using("externalEditor", function ()
      StackExchange.using("snippets", function ()
      StackExchange.snippets.init();
      );
      );
      , "code-snippets");

      StackExchange.ready(function()
      var channelOptions =
      tags: "".split(" "),
      id: "1"
      ;
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function()
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled)
      StackExchange.using("snippets", function()
      createEditor();
      );

      else
      createEditor();

      );

      function createEditor()
      StackExchange.prepareEditor(
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader:
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      ,
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      );



      );













      draft saved

      draft discarded


















      StackExchange.ready(
      function ()
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f56237733%2fwhy-does-splatting-create-a-tuple-on-the-rhs-but-a-list-on-the-lhs%23new-answer', 'question_page');

      );

      Post as a guest















      Required, but never shown

























      4 Answers
      4






      active

      oldest

      votes








      4 Answers
      4






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      8














      This is specified in PEP-0448 disadvantages




      Whilst *elements, = iterable causes elements to be a list, elements = *iterable, causes elements to be a tuple. The reason for this may confuse people unfamiliar with the construct.




      Also as per: PEP-3132 specification




      This PEP proposes a change to iterable unpacking syntax, allowing to specify a "catch-all" name which will be assigned a list of all items not assigned to a "regular" name.




      Also mentioned here: Python-3 exprlists




      Except when part of a list or set display, an expression list containing at least one comma yields a tuple.

      The trailing comma is required only to create a single tuple (a.k.a. a singleton); it is optional in all other cases. A single expression without a trailing comma doesn’t create a tuple, but rather yields the value of that expression. (To create an empty tuple, use an empty pair of parentheses: ().)




      This might also be seen in a simpler example here, where elements in a list



      In [27]: *elements, = range(6) 

      In [28]: elements
      Out[28]: [0, 1, 2, 3, 4, 5]


      and here, where elements is a tuple



      In [13]: elements = *range(6), 

      In [14]: elements
      Out[14]: (0, 1, 2, 3, 4, 5)


      From what I could understand from the comments and the other answers:



      • The first behaviour is to keep in-line with the existing arbitrary argument lists used in functions ie.*args


      • The second behaviour is to be able to use the variables on LHS further down in the evaluation, so making it a list, a mutable value rather than a tuple makes more sense






      share|improve this answer




















      • 4





        While the PEP does refer to a reason, it doesn't appear to actually give one.

        – Paul Panzer
        10 hours ago











      • Yes it doesn't, I am trying to find a reason myself @PaulPanzer :)

        – Devesh Kumar Singh
        10 hours ago






      • 2





        PEP 3132 says that *elements, = range(6) will create a list on the left-hand side. PEP 448 says that elements = *range(6), has generalized unpacking in a tuple display, (*range(6),) with implicit parentheses, creating a tuple on the right-hand side. (cc @PaulPanzer)

        – Andras Deak
        10 hours ago












      • I added what explanation I could gain from the comments above by Andras (Thanks Andras :) ) and the other answers @PaulPanzer

        – Devesh Kumar Singh
        9 hours ago















      8














      This is specified in PEP-0448 disadvantages




      Whilst *elements, = iterable causes elements to be a list, elements = *iterable, causes elements to be a tuple. The reason for this may confuse people unfamiliar with the construct.




      Also as per: PEP-3132 specification




      This PEP proposes a change to iterable unpacking syntax, allowing to specify a "catch-all" name which will be assigned a list of all items not assigned to a "regular" name.




      Also mentioned here: Python-3 exprlists




      Except when part of a list or set display, an expression list containing at least one comma yields a tuple.

      The trailing comma is required only to create a single tuple (a.k.a. a singleton); it is optional in all other cases. A single expression without a trailing comma doesn’t create a tuple, but rather yields the value of that expression. (To create an empty tuple, use an empty pair of parentheses: ().)




      This might also be seen in a simpler example here, where elements in a list



      In [27]: *elements, = range(6) 

      In [28]: elements
      Out[28]: [0, 1, 2, 3, 4, 5]


      and here, where elements is a tuple



      In [13]: elements = *range(6), 

      In [14]: elements
      Out[14]: (0, 1, 2, 3, 4, 5)


      From what I could understand from the comments and the other answers:



      • The first behaviour is to keep in-line with the existing arbitrary argument lists used in functions ie.*args


      • The second behaviour is to be able to use the variables on LHS further down in the evaluation, so making it a list, a mutable value rather than a tuple makes more sense






      share|improve this answer




















      • 4





        While the PEP does refer to a reason, it doesn't appear to actually give one.

        – Paul Panzer
        10 hours ago











      • Yes it doesn't, I am trying to find a reason myself @PaulPanzer :)

        – Devesh Kumar Singh
        10 hours ago






      • 2





        PEP 3132 says that *elements, = range(6) will create a list on the left-hand side. PEP 448 says that elements = *range(6), has generalized unpacking in a tuple display, (*range(6),) with implicit parentheses, creating a tuple on the right-hand side. (cc @PaulPanzer)

        – Andras Deak
        10 hours ago












      • I added what explanation I could gain from the comments above by Andras (Thanks Andras :) ) and the other answers @PaulPanzer

        – Devesh Kumar Singh
        9 hours ago













      8












      8








      8







      This is specified in PEP-0448 disadvantages




      Whilst *elements, = iterable causes elements to be a list, elements = *iterable, causes elements to be a tuple. The reason for this may confuse people unfamiliar with the construct.




      Also as per: PEP-3132 specification




      This PEP proposes a change to iterable unpacking syntax, allowing to specify a "catch-all" name which will be assigned a list of all items not assigned to a "regular" name.




      Also mentioned here: Python-3 exprlists




      Except when part of a list or set display, an expression list containing at least one comma yields a tuple.

      The trailing comma is required only to create a single tuple (a.k.a. a singleton); it is optional in all other cases. A single expression without a trailing comma doesn’t create a tuple, but rather yields the value of that expression. (To create an empty tuple, use an empty pair of parentheses: ().)




      This might also be seen in a simpler example here, where elements in a list



      In [27]: *elements, = range(6) 

      In [28]: elements
      Out[28]: [0, 1, 2, 3, 4, 5]


      and here, where elements is a tuple



      In [13]: elements = *range(6), 

      In [14]: elements
      Out[14]: (0, 1, 2, 3, 4, 5)


      From what I could understand from the comments and the other answers:



      • The first behaviour is to keep in-line with the existing arbitrary argument lists used in functions ie.*args


      • The second behaviour is to be able to use the variables on LHS further down in the evaluation, so making it a list, a mutable value rather than a tuple makes more sense






      share|improve this answer















      This is specified in PEP-0448 disadvantages




      Whilst *elements, = iterable causes elements to be a list, elements = *iterable, causes elements to be a tuple. The reason for this may confuse people unfamiliar with the construct.




      Also as per: PEP-3132 specification




      This PEP proposes a change to iterable unpacking syntax, allowing to specify a "catch-all" name which will be assigned a list of all items not assigned to a "regular" name.




      Also mentioned here: Python-3 exprlists




      Except when part of a list or set display, an expression list containing at least one comma yields a tuple.

      The trailing comma is required only to create a single tuple (a.k.a. a singleton); it is optional in all other cases. A single expression without a trailing comma doesn’t create a tuple, but rather yields the value of that expression. (To create an empty tuple, use an empty pair of parentheses: ().)




      This might also be seen in a simpler example here, where elements in a list



      In [27]: *elements, = range(6) 

      In [28]: elements
      Out[28]: [0, 1, 2, 3, 4, 5]


      and here, where elements is a tuple



      In [13]: elements = *range(6), 

      In [14]: elements
      Out[14]: (0, 1, 2, 3, 4, 5)


      From what I could understand from the comments and the other answers:



      • The first behaviour is to keep in-line with the existing arbitrary argument lists used in functions ie.*args


      • The second behaviour is to be able to use the variables on LHS further down in the evaluation, so making it a list, a mutable value rather than a tuple makes more sense







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited 9 hours ago

























      answered 10 hours ago









      Devesh Kumar SinghDevesh Kumar Singh

      11.5k1929




      11.5k1929







      • 4





        While the PEP does refer to a reason, it doesn't appear to actually give one.

        – Paul Panzer
        10 hours ago











      • Yes it doesn't, I am trying to find a reason myself @PaulPanzer :)

        – Devesh Kumar Singh
        10 hours ago






      • 2





        PEP 3132 says that *elements, = range(6) will create a list on the left-hand side. PEP 448 says that elements = *range(6), has generalized unpacking in a tuple display, (*range(6),) with implicit parentheses, creating a tuple on the right-hand side. (cc @PaulPanzer)

        – Andras Deak
        10 hours ago












      • I added what explanation I could gain from the comments above by Andras (Thanks Andras :) ) and the other answers @PaulPanzer

        – Devesh Kumar Singh
        9 hours ago












      • 4





        While the PEP does refer to a reason, it doesn't appear to actually give one.

        – Paul Panzer
        10 hours ago











      • Yes it doesn't, I am trying to find a reason myself @PaulPanzer :)

        – Devesh Kumar Singh
        10 hours ago






      • 2





        PEP 3132 says that *elements, = range(6) will create a list on the left-hand side. PEP 448 says that elements = *range(6), has generalized unpacking in a tuple display, (*range(6),) with implicit parentheses, creating a tuple on the right-hand side. (cc @PaulPanzer)

        – Andras Deak
        10 hours ago












      • I added what explanation I could gain from the comments above by Andras (Thanks Andras :) ) and the other answers @PaulPanzer

        – Devesh Kumar Singh
        9 hours ago







      4




      4





      While the PEP does refer to a reason, it doesn't appear to actually give one.

      – Paul Panzer
      10 hours ago





      While the PEP does refer to a reason, it doesn't appear to actually give one.

      – Paul Panzer
      10 hours ago













      Yes it doesn't, I am trying to find a reason myself @PaulPanzer :)

      – Devesh Kumar Singh
      10 hours ago





      Yes it doesn't, I am trying to find a reason myself @PaulPanzer :)

      – Devesh Kumar Singh
      10 hours ago




      2




      2





      PEP 3132 says that *elements, = range(6) will create a list on the left-hand side. PEP 448 says that elements = *range(6), has generalized unpacking in a tuple display, (*range(6),) with implicit parentheses, creating a tuple on the right-hand side. (cc @PaulPanzer)

      – Andras Deak
      10 hours ago






      PEP 3132 says that *elements, = range(6) will create a list on the left-hand side. PEP 448 says that elements = *range(6), has generalized unpacking in a tuple display, (*range(6),) with implicit parentheses, creating a tuple on the right-hand side. (cc @PaulPanzer)

      – Andras Deak
      10 hours ago














      I added what explanation I could gain from the comments above by Andras (Thanks Andras :) ) and the other answers @PaulPanzer

      – Devesh Kumar Singh
      9 hours ago





      I added what explanation I could gain from the comments above by Andras (Thanks Andras :) ) and the other answers @PaulPanzer

      – Devesh Kumar Singh
      9 hours ago













      7














      There is an indication of the reason why at the end of PEP 3132 -- Extended Iterable Unpacking:




      Acceptance



      After a short discussion on the python-3000 list [1], the
      PEP was accepted by Guido in its current form. Possible changes
      discussed were:



      [...]



      Make the starred target a tuple instead of a list. This would be
      consistent with a function's *args, but make further processing of the
      result harder.




      [1] https://mail.python.org/pipermail/python-3000/2007-May/007198.html



      So, the advantage of having a mutable list instead of an immutable tuple seems to be the reason.






      share|improve this answer



























        7














        There is an indication of the reason why at the end of PEP 3132 -- Extended Iterable Unpacking:




        Acceptance



        After a short discussion on the python-3000 list [1], the
        PEP was accepted by Guido in its current form. Possible changes
        discussed were:



        [...]



        Make the starred target a tuple instead of a list. This would be
        consistent with a function's *args, but make further processing of the
        result harder.




        [1] https://mail.python.org/pipermail/python-3000/2007-May/007198.html



        So, the advantage of having a mutable list instead of an immutable tuple seems to be the reason.






        share|improve this answer

























          7












          7








          7







          There is an indication of the reason why at the end of PEP 3132 -- Extended Iterable Unpacking:




          Acceptance



          After a short discussion on the python-3000 list [1], the
          PEP was accepted by Guido in its current form. Possible changes
          discussed were:



          [...]



          Make the starred target a tuple instead of a list. This would be
          consistent with a function's *args, but make further processing of the
          result harder.




          [1] https://mail.python.org/pipermail/python-3000/2007-May/007198.html



          So, the advantage of having a mutable list instead of an immutable tuple seems to be the reason.






          share|improve this answer













          There is an indication of the reason why at the end of PEP 3132 -- Extended Iterable Unpacking:




          Acceptance



          After a short discussion on the python-3000 list [1], the
          PEP was accepted by Guido in its current form. Possible changes
          discussed were:



          [...]



          Make the starred target a tuple instead of a list. This would be
          consistent with a function's *args, but make further processing of the
          result harder.




          [1] https://mail.python.org/pipermail/python-3000/2007-May/007198.html



          So, the advantage of having a mutable list instead of an immutable tuple seems to be the reason.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered 9 hours ago









          Thierry LathuilleThierry Lathuille

          10.3k82831




          10.3k82831





















              6














              not a complete answer, but disassembling gives some clues:



              from dis import dis

              def a():
              squares = (*map((2).__rpow__, range(5)),)
              # print(squares)

              print(dis(a))


              disassembles as



               5 0 LOAD_GLOBAL 0 (map)
              2 LOAD_CONST 1 (2)
              4 LOAD_ATTR 1 (__rpow__)
              6 LOAD_GLOBAL 2 (range)
              8 LOAD_CONST 2 (5)
              10 CALL_FUNCTION 1
              12 CALL_FUNCTION 2
              14 BUILD_TUPLE_UNPACK 1
              16 STORE_FAST 0 (squares)
              18 LOAD_CONST 0 (None)
              20 RETURN_VALUE


              while



              def b():
              *squares, = map((2).__rpow__, range(5))
              print(dis(b))


              results in



               11 0 LOAD_GLOBAL 0 (map)
              2 LOAD_CONST 1 (2)
              4 LOAD_ATTR 1 (__rpow__)
              6 LOAD_GLOBAL 2 (range)
              8 LOAD_CONST 2 (5)
              10 CALL_FUNCTION 1
              12 CALL_FUNCTION 2
              14 UNPACK_EX 0
              16 STORE_FAST 0 (squares)
              18 LOAD_CONST 0 (None)
              20 RETURN_VALUE


              the doc on UNPACK_EX states:




              UNPACK_EX(counts)



              Implements assignment with a starred target: Unpacks an iterable in TOS into individual values, where the total number of values can be
              smaller than the number of items in the iterable: one of the new
              values will be a list of all leftover items.



              The low byte of counts is the number of values before the list value, the high byte of counts the number of values after it. The
              resulting values are put onto the stack right-to-left.




              (emphasis mine). while BUILD_TUPLE_UNPACK returns a tuple:




              BUILD_TUPLE_UNPACK(count)



              Pops count iterables from the stack, joins them in a single tuple, and pushes the result. Implements iterable unpacking in tuple displays
              (*x, *y, *z).







              share|improve this answer


















              • 2





                So would that be a technical reason or no reason?

                – Paul Panzer
                10 hours ago






              • 1





                no, i do not see an argument for a reason here... it might be beneficial to have something mutable in the second case... but that is just a guess.

                – hiro protagonist
                9 hours ago















              6














              not a complete answer, but disassembling gives some clues:



              from dis import dis

              def a():
              squares = (*map((2).__rpow__, range(5)),)
              # print(squares)

              print(dis(a))


              disassembles as



               5 0 LOAD_GLOBAL 0 (map)
              2 LOAD_CONST 1 (2)
              4 LOAD_ATTR 1 (__rpow__)
              6 LOAD_GLOBAL 2 (range)
              8 LOAD_CONST 2 (5)
              10 CALL_FUNCTION 1
              12 CALL_FUNCTION 2
              14 BUILD_TUPLE_UNPACK 1
              16 STORE_FAST 0 (squares)
              18 LOAD_CONST 0 (None)
              20 RETURN_VALUE


              while



              def b():
              *squares, = map((2).__rpow__, range(5))
              print(dis(b))


              results in



               11 0 LOAD_GLOBAL 0 (map)
              2 LOAD_CONST 1 (2)
              4 LOAD_ATTR 1 (__rpow__)
              6 LOAD_GLOBAL 2 (range)
              8 LOAD_CONST 2 (5)
              10 CALL_FUNCTION 1
              12 CALL_FUNCTION 2
              14 UNPACK_EX 0
              16 STORE_FAST 0 (squares)
              18 LOAD_CONST 0 (None)
              20 RETURN_VALUE


              the doc on UNPACK_EX states:




              UNPACK_EX(counts)



              Implements assignment with a starred target: Unpacks an iterable in TOS into individual values, where the total number of values can be
              smaller than the number of items in the iterable: one of the new
              values will be a list of all leftover items.



              The low byte of counts is the number of values before the list value, the high byte of counts the number of values after it. The
              resulting values are put onto the stack right-to-left.




              (emphasis mine). while BUILD_TUPLE_UNPACK returns a tuple:




              BUILD_TUPLE_UNPACK(count)



              Pops count iterables from the stack, joins them in a single tuple, and pushes the result. Implements iterable unpacking in tuple displays
              (*x, *y, *z).







              share|improve this answer


















              • 2





                So would that be a technical reason or no reason?

                – Paul Panzer
                10 hours ago






              • 1





                no, i do not see an argument for a reason here... it might be beneficial to have something mutable in the second case... but that is just a guess.

                – hiro protagonist
                9 hours ago













              6












              6








              6







              not a complete answer, but disassembling gives some clues:



              from dis import dis

              def a():
              squares = (*map((2).__rpow__, range(5)),)
              # print(squares)

              print(dis(a))


              disassembles as



               5 0 LOAD_GLOBAL 0 (map)
              2 LOAD_CONST 1 (2)
              4 LOAD_ATTR 1 (__rpow__)
              6 LOAD_GLOBAL 2 (range)
              8 LOAD_CONST 2 (5)
              10 CALL_FUNCTION 1
              12 CALL_FUNCTION 2
              14 BUILD_TUPLE_UNPACK 1
              16 STORE_FAST 0 (squares)
              18 LOAD_CONST 0 (None)
              20 RETURN_VALUE


              while



              def b():
              *squares, = map((2).__rpow__, range(5))
              print(dis(b))


              results in



               11 0 LOAD_GLOBAL 0 (map)
              2 LOAD_CONST 1 (2)
              4 LOAD_ATTR 1 (__rpow__)
              6 LOAD_GLOBAL 2 (range)
              8 LOAD_CONST 2 (5)
              10 CALL_FUNCTION 1
              12 CALL_FUNCTION 2
              14 UNPACK_EX 0
              16 STORE_FAST 0 (squares)
              18 LOAD_CONST 0 (None)
              20 RETURN_VALUE


              the doc on UNPACK_EX states:




              UNPACK_EX(counts)



              Implements assignment with a starred target: Unpacks an iterable in TOS into individual values, where the total number of values can be
              smaller than the number of items in the iterable: one of the new
              values will be a list of all leftover items.



              The low byte of counts is the number of values before the list value, the high byte of counts the number of values after it. The
              resulting values are put onto the stack right-to-left.




              (emphasis mine). while BUILD_TUPLE_UNPACK returns a tuple:




              BUILD_TUPLE_UNPACK(count)



              Pops count iterables from the stack, joins them in a single tuple, and pushes the result. Implements iterable unpacking in tuple displays
              (*x, *y, *z).







              share|improve this answer













              not a complete answer, but disassembling gives some clues:



              from dis import dis

              def a():
              squares = (*map((2).__rpow__, range(5)),)
              # print(squares)

              print(dis(a))


              disassembles as



               5 0 LOAD_GLOBAL 0 (map)
              2 LOAD_CONST 1 (2)
              4 LOAD_ATTR 1 (__rpow__)
              6 LOAD_GLOBAL 2 (range)
              8 LOAD_CONST 2 (5)
              10 CALL_FUNCTION 1
              12 CALL_FUNCTION 2
              14 BUILD_TUPLE_UNPACK 1
              16 STORE_FAST 0 (squares)
              18 LOAD_CONST 0 (None)
              20 RETURN_VALUE


              while



              def b():
              *squares, = map((2).__rpow__, range(5))
              print(dis(b))


              results in



               11 0 LOAD_GLOBAL 0 (map)
              2 LOAD_CONST 1 (2)
              4 LOAD_ATTR 1 (__rpow__)
              6 LOAD_GLOBAL 2 (range)
              8 LOAD_CONST 2 (5)
              10 CALL_FUNCTION 1
              12 CALL_FUNCTION 2
              14 UNPACK_EX 0
              16 STORE_FAST 0 (squares)
              18 LOAD_CONST 0 (None)
              20 RETURN_VALUE


              the doc on UNPACK_EX states:




              UNPACK_EX(counts)



              Implements assignment with a starred target: Unpacks an iterable in TOS into individual values, where the total number of values can be
              smaller than the number of items in the iterable: one of the new
              values will be a list of all leftover items.



              The low byte of counts is the number of values before the list value, the high byte of counts the number of values after it. The
              resulting values are put onto the stack right-to-left.




              (emphasis mine). while BUILD_TUPLE_UNPACK returns a tuple:




              BUILD_TUPLE_UNPACK(count)



              Pops count iterables from the stack, joins them in a single tuple, and pushes the result. Implements iterable unpacking in tuple displays
              (*x, *y, *z).








              share|improve this answer












              share|improve this answer



              share|improve this answer










              answered 10 hours ago









              hiro protagonisthiro protagonist

              22.5k84569




              22.5k84569







              • 2





                So would that be a technical reason or no reason?

                – Paul Panzer
                10 hours ago






              • 1





                no, i do not see an argument for a reason here... it might be beneficial to have something mutable in the second case... but that is just a guess.

                – hiro protagonist
                9 hours ago












              • 2





                So would that be a technical reason or no reason?

                – Paul Panzer
                10 hours ago






              • 1





                no, i do not see an argument for a reason here... it might be beneficial to have something mutable in the second case... but that is just a guess.

                – hiro protagonist
                9 hours ago







              2




              2





              So would that be a technical reason or no reason?

              – Paul Panzer
              10 hours ago





              So would that be a technical reason or no reason?

              – Paul Panzer
              10 hours ago




              1




              1





              no, i do not see an argument for a reason here... it might be beneficial to have something mutable in the second case... but that is just a guess.

              – hiro protagonist
              9 hours ago





              no, i do not see an argument for a reason here... it might be beneficial to have something mutable in the second case... but that is just a guess.

              – hiro protagonist
              9 hours ago











              2














              For the RHS, there is not much of an issue. the answer here states it well:




              We have it working as it usually does in function calls. It expands
              the contents of the iterable it is attached to. So, the statement:



              elements = *iterable


              can be viewed as:



              elements = 1, 2, 3, 4,


              which is another way for a tuple to be initialized.




              Now, for the LHS,
              Yes, there are technical reasons for the LHS using a list, as indicated in the discussion around the initial PEP 3132 for extending unpacking



              The reasons can be gleaned from the conversation on the PEP(added at the end).



              Essentially it boils down to a couple key factors:



              • The LHS needed to support a "starred expression" that was not necessarily restricted to the end only.

              • The RHS needed to allow various sequence types to be accepted, including iterators.

              • The combination of the two points above required manipulation/mutation of the contents after accepting them into the starred expression.

              • An alternative approach to handling, one to mimic the iterator fed on the RHS, even leaving implementation difficulties aside, was shot down by Guido for its inconsistent behaviour.

              • Given all the factors above, a tuple on LHS would have to be a list first, and then converted. This approach would then just add overhead, and did not invite any further discussion.

              Summary: A combination of various factors led to the decision to allow a list on the LHS, and the reasons fed off of each other.




              Relevant extract for disallowing inconsistent types:




              The important use case in Python for the proposed semantics is when
              you have a variable-length record, the first few items of which are
              interesting, and the rest of which is less so, but not unimportant.
              (If you wanted to throw the rest away, you'd just write a, b, c =
              x[:3] instead of a, b, c, *d = x.) It is much more convenient for this
              use case if the type of d is fixed by the operation, so you can count
              on its behavior.



              There's a bug in the design of filter() in Python 2 (which will be
              fixed in 3.0 by turning it into an iterator BTW): if the input is a
              tuple, the output is a tuple too, but if the input is a list or
              anything else
              , the output is a list. That's a totally insane
              signature, since it means that you can't count on the result being a
              list, nor on it being a tuple -- if you need it to be one or the
              other, you have to convert it to one, which is a waste of time and
              space. Please let's not repeat this design bug.

              -Guido






              I have also tried to recreate a partially quoted conversation that pertains to the summary above.Source
              Emphasis mine.



              1.




              In argument lists, *args exhausts iterators, converting them to
              tuples. I think it would be confusing if *args in tuple unpacking
              didn't do the same thing.



              This brings up the question of why the patch produces lists, not
              tuples.
              What's the reasoning behind that?



              STeVe




              2.




              IMO, it's likely that you would like to further process the resulting
              sequence, including modifying it.



              Georg




              3.




              Well if that's what you're aiming at, then I'd expect it to be more
              useful to have the unpacking generate not lists, but the same type you
              started with,
              e.g. if I started with a string, I probably want to
              continue using strings::
              --additional text snipped off




              4.




              When dealing with an iterator, you don't know the length in advance,
              so the only way to get a tuple would be to produce a list first and
              then create a tuple from it.

              Greg




              5.




              Yep. That was one of the reasons it was suggested that the *args
              should only appear at the end of the tuple unpacking.



              STeVe




              couple convos skipped



              6.




              I don't think that returning the type given is a goal that should be
              attempted, because it can only ever work for a fixed set of known
              types.
              Given an arbitrary sequence type, there is no way of knowing
              how to create a new instance of it with specified contents.



              -- Greg




              skipped convos



              7.





              I'm suggesting, that:



              • lists return lists

              • tuples return tuples

              • XYZ containers return XYZ containers

              • non-container iterables return iterators.



              How do you propose to distinguish between the last two cases?
              Attempting to slice it and catching an exception is not acceptable,
              IMO, as it can too easily mask bugs.



              -- Greg




              8.




              But I expect less useful. It won't support "a, *b, c = "
              either.
              From an implementation POV, if you have an unknown object on
              the RHS, you have to try slicing it before you try iterating over it;
              this may cause problems
              e.g. if the object happens to be a defaultdict
              -- since x[3:] is implemented as x[slice(None, 3, None)], the defaultdict will give you its default value. I'd much rather define
              this in terms of iterating over the object until it is exhausted,
              which can be optimized for certain known types like lists and tuples.



              --
              --Guido van Rossum







              share|improve this answer





























                2














                For the RHS, there is not much of an issue. the answer here states it well:




                We have it working as it usually does in function calls. It expands
                the contents of the iterable it is attached to. So, the statement:



                elements = *iterable


                can be viewed as:



                elements = 1, 2, 3, 4,


                which is another way for a tuple to be initialized.




                Now, for the LHS,
                Yes, there are technical reasons for the LHS using a list, as indicated in the discussion around the initial PEP 3132 for extending unpacking



                The reasons can be gleaned from the conversation on the PEP(added at the end).



                Essentially it boils down to a couple key factors:



                • The LHS needed to support a "starred expression" that was not necessarily restricted to the end only.

                • The RHS needed to allow various sequence types to be accepted, including iterators.

                • The combination of the two points above required manipulation/mutation of the contents after accepting them into the starred expression.

                • An alternative approach to handling, one to mimic the iterator fed on the RHS, even leaving implementation difficulties aside, was shot down by Guido for its inconsistent behaviour.

                • Given all the factors above, a tuple on LHS would have to be a list first, and then converted. This approach would then just add overhead, and did not invite any further discussion.

                Summary: A combination of various factors led to the decision to allow a list on the LHS, and the reasons fed off of each other.




                Relevant extract for disallowing inconsistent types:




                The important use case in Python for the proposed semantics is when
                you have a variable-length record, the first few items of which are
                interesting, and the rest of which is less so, but not unimportant.
                (If you wanted to throw the rest away, you'd just write a, b, c =
                x[:3] instead of a, b, c, *d = x.) It is much more convenient for this
                use case if the type of d is fixed by the operation, so you can count
                on its behavior.



                There's a bug in the design of filter() in Python 2 (which will be
                fixed in 3.0 by turning it into an iterator BTW): if the input is a
                tuple, the output is a tuple too, but if the input is a list or
                anything else
                , the output is a list. That's a totally insane
                signature, since it means that you can't count on the result being a
                list, nor on it being a tuple -- if you need it to be one or the
                other, you have to convert it to one, which is a waste of time and
                space. Please let's not repeat this design bug.

                -Guido






                I have also tried to recreate a partially quoted conversation that pertains to the summary above.Source
                Emphasis mine.



                1.




                In argument lists, *args exhausts iterators, converting them to
                tuples. I think it would be confusing if *args in tuple unpacking
                didn't do the same thing.



                This brings up the question of why the patch produces lists, not
                tuples.
                What's the reasoning behind that?



                STeVe




                2.




                IMO, it's likely that you would like to further process the resulting
                sequence, including modifying it.



                Georg




                3.




                Well if that's what you're aiming at, then I'd expect it to be more
                useful to have the unpacking generate not lists, but the same type you
                started with,
                e.g. if I started with a string, I probably want to
                continue using strings::
                --additional text snipped off




                4.




                When dealing with an iterator, you don't know the length in advance,
                so the only way to get a tuple would be to produce a list first and
                then create a tuple from it.

                Greg




                5.




                Yep. That was one of the reasons it was suggested that the *args
                should only appear at the end of the tuple unpacking.



                STeVe




                couple convos skipped



                6.




                I don't think that returning the type given is a goal that should be
                attempted, because it can only ever work for a fixed set of known
                types.
                Given an arbitrary sequence type, there is no way of knowing
                how to create a new instance of it with specified contents.



                -- Greg




                skipped convos



                7.





                I'm suggesting, that:



                • lists return lists

                • tuples return tuples

                • XYZ containers return XYZ containers

                • non-container iterables return iterators.



                How do you propose to distinguish between the last two cases?
                Attempting to slice it and catching an exception is not acceptable,
                IMO, as it can too easily mask bugs.



                -- Greg




                8.




                But I expect less useful. It won't support "a, *b, c = "
                either.
                From an implementation POV, if you have an unknown object on
                the RHS, you have to try slicing it before you try iterating over it;
                this may cause problems
                e.g. if the object happens to be a defaultdict
                -- since x[3:] is implemented as x[slice(None, 3, None)], the defaultdict will give you its default value. I'd much rather define
                this in terms of iterating over the object until it is exhausted,
                which can be optimized for certain known types like lists and tuples.



                --
                --Guido van Rossum







                share|improve this answer



























                  2












                  2








                  2







                  For the RHS, there is not much of an issue. the answer here states it well:




                  We have it working as it usually does in function calls. It expands
                  the contents of the iterable it is attached to. So, the statement:



                  elements = *iterable


                  can be viewed as:



                  elements = 1, 2, 3, 4,


                  which is another way for a tuple to be initialized.




                  Now, for the LHS,
                  Yes, there are technical reasons for the LHS using a list, as indicated in the discussion around the initial PEP 3132 for extending unpacking



                  The reasons can be gleaned from the conversation on the PEP(added at the end).



                  Essentially it boils down to a couple key factors:



                  • The LHS needed to support a "starred expression" that was not necessarily restricted to the end only.

                  • The RHS needed to allow various sequence types to be accepted, including iterators.

                  • The combination of the two points above required manipulation/mutation of the contents after accepting them into the starred expression.

                  • An alternative approach to handling, one to mimic the iterator fed on the RHS, even leaving implementation difficulties aside, was shot down by Guido for its inconsistent behaviour.

                  • Given all the factors above, a tuple on LHS would have to be a list first, and then converted. This approach would then just add overhead, and did not invite any further discussion.

                  Summary: A combination of various factors led to the decision to allow a list on the LHS, and the reasons fed off of each other.




                  Relevant extract for disallowing inconsistent types:




                  The important use case in Python for the proposed semantics is when
                  you have a variable-length record, the first few items of which are
                  interesting, and the rest of which is less so, but not unimportant.
                  (If you wanted to throw the rest away, you'd just write a, b, c =
                  x[:3] instead of a, b, c, *d = x.) It is much more convenient for this
                  use case if the type of d is fixed by the operation, so you can count
                  on its behavior.



                  There's a bug in the design of filter() in Python 2 (which will be
                  fixed in 3.0 by turning it into an iterator BTW): if the input is a
                  tuple, the output is a tuple too, but if the input is a list or
                  anything else
                  , the output is a list. That's a totally insane
                  signature, since it means that you can't count on the result being a
                  list, nor on it being a tuple -- if you need it to be one or the
                  other, you have to convert it to one, which is a waste of time and
                  space. Please let's not repeat this design bug.

                  -Guido






                  I have also tried to recreate a partially quoted conversation that pertains to the summary above.Source
                  Emphasis mine.



                  1.




                  In argument lists, *args exhausts iterators, converting them to
                  tuples. I think it would be confusing if *args in tuple unpacking
                  didn't do the same thing.



                  This brings up the question of why the patch produces lists, not
                  tuples.
                  What's the reasoning behind that?



                  STeVe




                  2.




                  IMO, it's likely that you would like to further process the resulting
                  sequence, including modifying it.



                  Georg




                  3.




                  Well if that's what you're aiming at, then I'd expect it to be more
                  useful to have the unpacking generate not lists, but the same type you
                  started with,
                  e.g. if I started with a string, I probably want to
                  continue using strings::
                  --additional text snipped off




                  4.




                  When dealing with an iterator, you don't know the length in advance,
                  so the only way to get a tuple would be to produce a list first and
                  then create a tuple from it.

                  Greg




                  5.




                  Yep. That was one of the reasons it was suggested that the *args
                  should only appear at the end of the tuple unpacking.



                  STeVe




                  couple convos skipped



                  6.




                  I don't think that returning the type given is a goal that should be
                  attempted, because it can only ever work for a fixed set of known
                  types.
                  Given an arbitrary sequence type, there is no way of knowing
                  how to create a new instance of it with specified contents.



                  -- Greg




                  skipped convos



                  7.





                  I'm suggesting, that:



                  • lists return lists

                  • tuples return tuples

                  • XYZ containers return XYZ containers

                  • non-container iterables return iterators.



                  How do you propose to distinguish between the last two cases?
                  Attempting to slice it and catching an exception is not acceptable,
                  IMO, as it can too easily mask bugs.



                  -- Greg




                  8.




                  But I expect less useful. It won't support "a, *b, c = "
                  either.
                  From an implementation POV, if you have an unknown object on
                  the RHS, you have to try slicing it before you try iterating over it;
                  this may cause problems
                  e.g. if the object happens to be a defaultdict
                  -- since x[3:] is implemented as x[slice(None, 3, None)], the defaultdict will give you its default value. I'd much rather define
                  this in terms of iterating over the object until it is exhausted,
                  which can be optimized for certain known types like lists and tuples.



                  --
                  --Guido van Rossum







                  share|improve this answer















                  For the RHS, there is not much of an issue. the answer here states it well:




                  We have it working as it usually does in function calls. It expands
                  the contents of the iterable it is attached to. So, the statement:



                  elements = *iterable


                  can be viewed as:



                  elements = 1, 2, 3, 4,


                  which is another way for a tuple to be initialized.




                  Now, for the LHS,
                  Yes, there are technical reasons for the LHS using a list, as indicated in the discussion around the initial PEP 3132 for extending unpacking



                  The reasons can be gleaned from the conversation on the PEP(added at the end).



                  Essentially it boils down to a couple key factors:



                  • The LHS needed to support a "starred expression" that was not necessarily restricted to the end only.

                  • The RHS needed to allow various sequence types to be accepted, including iterators.

                  • The combination of the two points above required manipulation/mutation of the contents after accepting them into the starred expression.

                  • An alternative approach to handling, one to mimic the iterator fed on the RHS, even leaving implementation difficulties aside, was shot down by Guido for its inconsistent behaviour.

                  • Given all the factors above, a tuple on LHS would have to be a list first, and then converted. This approach would then just add overhead, and did not invite any further discussion.

                  Summary: A combination of various factors led to the decision to allow a list on the LHS, and the reasons fed off of each other.




                  Relevant extract for disallowing inconsistent types:




                  The important use case in Python for the proposed semantics is when
                  you have a variable-length record, the first few items of which are
                  interesting, and the rest of which is less so, but not unimportant.
                  (If you wanted to throw the rest away, you'd just write a, b, c =
                  x[:3] instead of a, b, c, *d = x.) It is much more convenient for this
                  use case if the type of d is fixed by the operation, so you can count
                  on its behavior.



                  There's a bug in the design of filter() in Python 2 (which will be
                  fixed in 3.0 by turning it into an iterator BTW): if the input is a
                  tuple, the output is a tuple too, but if the input is a list or
                  anything else
                  , the output is a list. That's a totally insane
                  signature, since it means that you can't count on the result being a
                  list, nor on it being a tuple -- if you need it to be one or the
                  other, you have to convert it to one, which is a waste of time and
                  space. Please let's not repeat this design bug.

                  -Guido






                  I have also tried to recreate a partially quoted conversation that pertains to the summary above.Source
                  Emphasis mine.



                  1.




                  In argument lists, *args exhausts iterators, converting them to
                  tuples. I think it would be confusing if *args in tuple unpacking
                  didn't do the same thing.



                  This brings up the question of why the patch produces lists, not
                  tuples.
                  What's the reasoning behind that?



                  STeVe




                  2.




                  IMO, it's likely that you would like to further process the resulting
                  sequence, including modifying it.



                  Georg




                  3.




                  Well if that's what you're aiming at, then I'd expect it to be more
                  useful to have the unpacking generate not lists, but the same type you
                  started with,
                  e.g. if I started with a string, I probably want to
                  continue using strings::
                  --additional text snipped off




                  4.




                  When dealing with an iterator, you don't know the length in advance,
                  so the only way to get a tuple would be to produce a list first and
                  then create a tuple from it.

                  Greg




                  5.




                  Yep. That was one of the reasons it was suggested that the *args
                  should only appear at the end of the tuple unpacking.



                  STeVe




                  couple convos skipped



                  6.




                  I don't think that returning the type given is a goal that should be
                  attempted, because it can only ever work for a fixed set of known
                  types.
                  Given an arbitrary sequence type, there is no way of knowing
                  how to create a new instance of it with specified contents.



                  -- Greg




                  skipped convos



                  7.





                  I'm suggesting, that:



                  • lists return lists

                  • tuples return tuples

                  • XYZ containers return XYZ containers

                  • non-container iterables return iterators.



                  How do you propose to distinguish between the last two cases?
                  Attempting to slice it and catching an exception is not acceptable,
                  IMO, as it can too easily mask bugs.



                  -- Greg




                  8.




                  But I expect less useful. It won't support "a, *b, c = "
                  either.
                  From an implementation POV, if you have an unknown object on
                  the RHS, you have to try slicing it before you try iterating over it;
                  this may cause problems
                  e.g. if the object happens to be a defaultdict
                  -- since x[3:] is implemented as x[slice(None, 3, None)], the defaultdict will give you its default value. I'd much rather define
                  this in terms of iterating over the object until it is exhausted,
                  which can be optimized for certain known types like lists and tuples.



                  --
                  --Guido van Rossum








                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited 9 hours ago

























                  answered 9 hours ago









                  Paritosh SinghParitosh Singh

                  2,8252522




                  2,8252522



























                      draft saved

                      draft discarded
















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid


                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.

                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f56237733%2fwhy-does-splatting-create-a-tuple-on-the-rhs-but-a-list-on-the-lhs%23new-answer', 'question_page');

                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      Siegen Nawigatsjuun

                      Log på Navigationsmenu

                      Log på Navigationsmenu