Construct a matrix from a list: matrix multiplication

This keeps on coming up in one form or another - either someone multiplies a list of lists and ends up surprised that they're all the same, or is frustrated with the verbosity of the alternatives. Can we use the matmul operator for this? class List(list): def __matmul__(self, other): return [copy.copy(x) for x in self for _ in range(other)]
x = List([[0]*4]) @ 2 x [[0, 0, 0, 0], [0, 0, 0, 0]] x[0][0] = 1 x [[1, 0, 0, 0], [0, 0, 0, 0]]
If this were supported by the built-in list type, it would be either of these:
x = [[0] * 4] @ 2 x = [[0] @ 4] @ 4
(identical functionality, as copying an integer has no effect). The semantics could be either as shown above (copy.copy()), or something very simple and narrow like "lists get shallow-copied, other objects get referenced". Thoughts? ChrisA

On Fri, Mar 31, 2017 at 06:58:21PM +1100, Chris Angelico wrote:
This keeps on coming up in one form or another - either someone multiplies a list of lists and ends up surprised that they're all the same, or is frustrated with the verbosity of the alternatives.
Can we use the matmul operator for this?
I like the idea of using * for repetition without copying, and @ for repetition with shallow copying. That does mean that now you have a built-in operator which relies on the copy module, since it has to work with arbitrary objects. Isn't copy written in Python? [...]
If this were supported by the built-in list type, it would be either of these:
x = [[0] * 4] @ 2 x = [[0] @ 4] @ 4
(identical functionality, as copying an integer has no effect).
I think that's an implementation detail: copying immutable objects *might* return a reference to the original immutable object, or it might return a new object. For ints, any sane implementation would surely behave as we say, but let's not specify that as part of the behaviour of @ itself.
The semantics could be either as shown above (copy.copy()), or something very simple and narrow like "lists get shallow-copied, other objects get referenced".
I prefer the distinction copy versus non-copy. That makes it simple to understand, and means that it works if somebody wants a list of dicts instead of a list of lists: data = [{'a': 1, 'b': 2}] @ 5 -- Steve

On Sat, Apr 1, 2017 at 12:44 PM, Steven D'Aprano <steve@pearwood.info> wrote:
On Fri, Mar 31, 2017 at 06:58:21PM +1100, Chris Angelico wrote:
This keeps on coming up in one form or another - either someone multiplies a list of lists and ends up surprised that they're all the same, or is frustrated with the verbosity of the alternatives.
Can we use the matmul operator for this?
I like the idea of using * for repetition without copying, and @ for repetition with shallow copying.
That does mean that now you have a built-in operator which relies on the copy module, since it has to work with arbitrary objects. Isn't copy written in Python?
Yes it is, but I'm not entirely sure of all its semantics.
If this were supported by the built-in list type, it would be either of these:
x = [[0] * 4] @ 2 x = [[0] @ 4] @ 4
(identical functionality, as copying an integer has no effect).
I think that's an implementation detail: copying immutable objects *might* return a reference to the original immutable object, or it might return a new object. For ints, any sane implementation would surely behave as we say, but let's not specify that as part of the behaviour of @ itself.
Right, right. What I meant was that people would be free to build the matrix either way, since it wouldn't have any significant difference. Of course it'd be legal to copy the integer too, but you shouldn't care one way or the other.
The semantics could be either as shown above (copy.copy()), or something very simple and narrow like "lists get shallow-copied, other objects get referenced".
I prefer the distinction copy versus non-copy. That makes it simple to understand, and means that it works if somebody wants a list of dicts instead of a list of lists:
data = [{'a': 1, 'b': 2}] @ 5
Sounds like a plan. Probably, though, the @ operator should be defined in concrete terms that are similar to the implementation of copy.copy(), rather than actually being copy.copy(), in case someone shadows or monkey-patches the module. But normal usage should have them behave the same way. ChrisA

On Fri, Mar 31, 2017 at 3:58 AM, Chris Angelico <rosuav@gmail.com> wrote:
This keeps on coming up in one form or another - either someone multiplies a list of lists and ends up surprised that they're all the same, or is frustrated with the verbosity of the alternatives.
Can we use the matmul operator for this?
In math, a number can be considered a 1-dimensional vector. You can multiply a 1-dimensional vector by an n-dimensional vector _as matrices_ to get the same result as scalar multiplication. Using it as a deep-copy multiplication operator might make things confusing when someone moves to or from Numpy. Instead of using multiplication to create homogenous lists, how about using the list constructor? list(0, 4) #list of 4 elements, all 0 list(0, (4,4)) #4x4 Concerns with my idea: 1. Someone might expect `list(0, 4)` to return `[0, 4]`. 2. Someone might want to write `list(list(0, 4), 4)`, which has the same issue as `[[0] * 4] * 4`. 3. Contrast with the `bytes` constructor. `bytes(n) == b'\0' * 10` The `dict` constructor has a `.fromkeys` class method. An analogous method for `list` can be `list.withshape(4,4, val=0)`. That's likely to be too big a change to solve a small problem.

On 4/1/17, Franklin? Lee <leewangzhong+python@gmail.com> wrote:
On Fri, Mar 31, 2017 at 3:58 AM, Chris Angelico <rosuav@gmail.com> wrote:
This keeps on coming up in one form or another - either someone multiplies a list of lists and ends up surprised that they're all the same, or is frustrated with the verbosity of the alternatives.
Can we use the matmul operator for this?
In math, a number can be considered a 1-dimensional vector. You can multiply a 1-dimensional vector by an n-dimensional vector _as matrices_ to get the same result as scalar multiplication. Using it as a deep-copy multiplication operator might make things confusing when someone moves to or from Numpy.
Too late. ;) [1, 1, 1] * 3 numpy.ones(3) * 3 PL.
participants (5)
-
Chris Angelico
-
Franklin? Lee
-
Greg Ewing
-
Pavol Lisy
-
Steven D'Aprano