[issue27135] nested list produced with multiplication is linked to the same list

2016-05-27 Thread Emanuel Barry

Emanuel Barry added the comment:

You do raise a valid point, sequence repetition (*) on lists of mutable objects 
serves very little purpose. However, as I stated, it is a side-effect of the 
data model and changing it would be yet another special case, which aren't 
special enough to break the rules, and this applies here.

Keep in mind that, currently, this is only confusing to newbies. Your idea 
would make this confusing for long-time Python programmers.

If you still wish to propose such a change, I recommend to take this to the 
Python-ideas mailing list (point to this issue in your email). Be warned though 
that most core developers (and most non-core devs such as myself) will probably 
prefer the statu quo, again because the change would be yet another special 
case, and probably view this as an attractive nuisance ("Why does [[x] * y] * n 
create separate lists but x = y = [] refer to the same list?").

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue27135] nested list produced with multiplication is linked to the same list

2016-05-27 Thread Matthew Tanous

Matthew Tanous added the comment:

It makes sense, except for this case is not true when "x" is an immutable data 
type - it appears as though something like [5] * n creates a list of totally 
separate elements (even if they start as the same thing).

It is difficult to see a case where I would not want separate elements from a 
mutable type as well. It would seem to me that having the "*" operator function 
as the list comprehension does now would be more logical and straightforward.

This would change the default list in a way that is mostly unseen: [5] * 3 
would still result in [5, 5, 5] while treating mutable nesting in a way that I 
believe would be more understandable from the apparent intent of the syntax in 
question.

This would also resolve the problem of being unable to use the list 
multiplication to create a list of mutable objects. If I have a mutable object 
Foo and wish to create a list of different instances of them, I cannot use the 
straightforward syntax [Foo()] * n at present to do this, as there will only be 
one actual Foo instance in that list. I think that this is confusing to 
developers who would generally expect that this shortcut (and this is the only 
purpose of the operator for lists) would create a list of different instances.

> On May 27, 2016, at 6:30 AM, Emanuel Barry  wrote:
> 
> 
> Emanuel Barry added the comment:
> 
> The reason why Python behaves like that in this case is a side-effect of the 
> way the data model is implemented. Lists are a mutable data type, which means 
> that referencing the same list - which is what you are doing - as opposed to 
> creating a new one each time, does exactly what is expected of the data 
> model, which is to keep a reference to the original list. Consider:
> 
> x = ??
> y = x
> 
> The object bound to `y` refers to the same object as the one bound to `x`, 
> such that `x is y`, for every possible value of `x`. As `=` is the assignment 
> operator (and not the copy operator, is such a thing existed), `y` merely has 
> a reference to `x`.
> 
> There are very valid use cases where you will want to get a reference to the 
> original list to modify it, for example in a function that is meant to alter 
> the original. If you want a copy, use `l[:]` (or `l.copy()` in more recent 
> versions).
> 
> In Python, every object and operation is evaluated once, when the interpreter 
> comes across it (in a for or while loop, it will come over the same point 
> multiple times, so it will evaluate it multiple times). By doing:
> 
> [[x] * y] * n
> 
> You are essentially doing this:
> 
> l_1 = [x] # one-element list
> l_2 = l_1 * y # list with `y` times `x` in it (references to `x`, not copies)
> l_3 = [l_2] # a new list with one element, `l_2`
> l_4 = l_3 * n # list with `n` times `l_3` in it (references to `l_3`, not 
> copies)
> 
> As you can see, it makes no sense to have multiple different lists by doing 
> that. Doing a list comprehension, such as:
> 
> [[None] * n for _ in range(N)]
> 
> Will evaluate a new list each time the interpreter comes across it, which 
> will be N times for this case. Thus, you get a different list everytime.
> 
> In other words, the reason that "That's just how it works" is because this 
> behaviour is a side-effect, not something that's out of the way. Creating a 
> new special case for this particular case seems like a very big stretch. 
> Remember, "Special cases aren't special enough to break the rules."
> 
> This change that is "seemingly trivial" to you is actually asking to break 
> the Python semantics in some weird and convoluted way, for no gain since we 
> have list comprehensions (that you seem to already be acquainted with).
> 
> Did that seem like a sufficient answer? ;-)
> 
> --
> nosy: +ebarry
> 
> ___
> Python tracker 
> 
> ___

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue27135] nested list produced with multiplication is linked to the same list

2016-05-27 Thread Emanuel Barry

Emanuel Barry added the comment:

The reason why Python behaves like that in this case is a side-effect of the 
way the data model is implemented. Lists are a mutable data type, which means 
that referencing the same list - which is what you are doing - as opposed to 
creating a new one each time, does exactly what is expected of the data model, 
which is to keep a reference to the original list. Consider:

x = ??
y = x

The object bound to `y` refers to the same object as the one bound to `x`, such 
that `x is y`, for every possible value of `x`. As `=` is the assignment 
operator (and not the copy operator, is such a thing existed), `y` merely has a 
reference to `x`.

There are very valid use cases where you will want to get a reference to the 
original list to modify it, for example in a function that is meant to alter 
the original. If you want a copy, use `l[:]` (or `l.copy()` in more recent 
versions).

In Python, every object and operation is evaluated once, when the interpreter 
comes across it (in a for or while loop, it will come over the same point 
multiple times, so it will evaluate it multiple times). By doing:

[[x] * y] * n

You are essentially doing this:

l_1 = [x] # one-element list
l_2 = l_1 * y # list with `y` times `x` in it (references to `x`, not copies)
l_3 = [l_2] # a new list with one element, `l_2`
l_4 = l_3 * n # list with `n` times `l_3` in it (references to `l_3`, not 
copies)

As you can see, it makes no sense to have multiple different lists by doing 
that. Doing a list comprehension, such as:

[[None] * n for _ in range(N)]

Will evaluate a new list each time the interpreter comes across it, which will 
be N times for this case. Thus, you get a different list everytime.

In other words, the reason that "That's just how it works" is because this 
behaviour is a side-effect, not something that's out of the way. Creating a new 
special case for this particular case seems like a very big stretch. Remember, 
"Special cases aren't special enough to break the rules."

This change that is "seemingly trivial" to you is actually asking to break the 
Python semantics in some weird and convoluted way, for no gain since we have 
list comprehensions (that you seem to already be acquainted with).

Did that seem like a sufficient answer? ;-)

--
nosy: +ebarry

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue27135] nested list produced with multiplication is linked to the same list

2016-05-27 Thread Matthew Tanous

Matthew Tanous added the comment:

I'm aware that it's how Python works at present. My point was that this is 
awkward and counter-intuitive, with no purpose I can see worth serving.

"That's just how it works" seems to me a rather insufficient answer, especially 
for such a seemingly trivial change.

So, no, it's not technically a bug. But I think it's worth some discussion.

> On May 26, 2016, at 11:42 PM, Benjamin Peterson  
> wrote:
> 
> 
> Benjamin Peterson added the comment:
> 
> That's just how Python works. 
> https://docs.python.org/3/faq/programming.html#how-do-i-create-a-multidimensional-list
> 
> --
> nosy: +benjamin.peterson
> resolution:  -> not a bug
> status: open -> closed
> 
> ___
> Python tracker 
> 
> ___

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue27135] nested list produced with multiplication is linked to the same list

2016-05-26 Thread Benjamin Peterson

Benjamin Peterson added the comment:

That's just how Python works. 
https://docs.python.org/3/faq/programming.html#how-do-i-create-a-multidimensional-list

--
nosy: +benjamin.peterson
resolution:  -> not a bug
status: open -> closed

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue27135] nested list produced with multiplication is linked to the same list

2016-05-26 Thread Matthew Tanous

New submission from Matthew Tanous:

If I produce a list in this fashion:

l = [[x] * n] * n

I would expect that I would obtain a matrix-like structure.  Instead, I get a 
list of the *same* list, such that the statement:

l[x][y] = z

would change, in essence, every value in "column" y.  This is different from 
the case where the list contains a string or integer value, where the new list 
points to separate instances of the internal values.

In my view, this is strange and counter-intuitive behavior.  If I want to 
create a matrix-like set to None to start, instead of using:

 mat = [[None] * N] * N

I have to use:

 mat = [[None] * N for i in range(N)]

If there is any possibility for it to be changed, I think that would improve 
things considerably.  In almost no cases, in my opinion, would I want a list of 
lists that are forced to be the same.

--
components: Interpreter Core
messages: 266475
nosy: Matthew Tanous
priority: normal
severity: normal
status: open
title: nested list produced with multiplication is linked to the same list
versions: Python 2.7, Python 3.5

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com