"Ba chấm" trong Python có nghĩa là gì khi lập chỉ mục những gì trông giống như một số?


87

Ý nghĩa của x[...]dưới đây là gì?

a = np.arange(6).reshape(2,3)
for x in np.nditer(a, op_flags=['readwrite']):
    x[...] = 2 * x

1
Đó không phải là một danh sách.
user2357112 hỗ trợ Monica


1
Phải hiểu theo cách thú vị đây là bài nói chuyện của James Powell trên youtube.com/watch?v=65_-6kEAq58
SARose

Câu trả lời:


69

Trong khi bản sao được đề xuất Đối tượng Dấu ba chấm trong Python làm gì? trả lời câu hỏi trong pythonbối cảnh chung , việc sử dụng nó trong một nditervòng lặp yêu cầu, tôi nghĩ, thêm thông tin.

https://docs.scipy.org/doc/numpy/reference/arrays.nditer.html#modizing-array-values

Phép gán thông thường trong Python chỉ đơn giản là thay đổi một tham chiếu trong từ điển biến cục bộ hoặc toàn cục thay vì sửa đổi một biến hiện có tại chỗ. Điều này có nghĩa là chỉ cần gán cho x sẽ không đặt giá trị vào phần tử của mảng, mà chuyển x từ tham chiếu phần tử mảng thành tham chiếu đến giá trị bạn đã gán. Để thực sự sửa đổi phần tử của mảng, x phải được lập chỉ mục bằng dấu chấm lửng.

Phần đó bao gồm ví dụ mã của bạn.

Vì vậy, theo cách nói của tôi, x[...] = ...sửa đổi xtại chỗ; x = ...sẽ phá vỡ liên kết đến nditerbiến và không thay đổi nó. Nó giống như x[:] = ...nhưng hoạt động với các mảng có kích thước bất kỳ (bao gồm cả 0d). Trong bối cảnh xnày không chỉ là một số, mà là một mảng.

Có lẽ điều gần nhất với sự nditerlặp lại này mà không có nditerlà:

In [667]: for i, x in np.ndenumerate(a):
     ...:     print(i, x)
     ...:     a[i] = 2 * x
     ...:     
(0, 0) 0
(0, 1) 1
...
(1, 2) 5
In [668]: a
Out[668]: 
array([[ 0,  2,  4],
       [ 6,  8, 10]])

Lưu ý rằng tôi phải lập chỉ mục và sửa đổi a[i]trực tiếp. Tôi không thể đã sử dụng x = 2*x,. Trong lần lặp xnày là một đại lượng vô hướng và do đó không thể thay đổi

In [669]: for i,x in np.ndenumerate(a):
     ...:     x[...] = 2 * x
  ...
TypeError: 'numpy.int32' object does not support item assignment

Nhưng trong nditertrường hợp xnày là một mảng 0d và có thể thay đổi.

In [671]: for x in np.nditer(a, op_flags=['readwrite']):
     ...:     print(x, type(x), x.shape)
     ...:     x[...] = 2 * x
     ...:     
0 <class 'numpy.ndarray'> ()
4 <class 'numpy.ndarray'> ()
...

Và bởi vì nó là 0d, x[:]không thể được sử dụng thay thế chox[...]

----> 3     x[:] = 2 * x
IndexError: too many indices for array

Việc lặp lại mảng đơn giản hơn cũng có thể cung cấp thông tin chi tiết:

In [675]: for x in a:
     ...:     print(x, x.shape)
     ...:     x[:] = 2 * x
     ...:     
[ 0  8 16] (3,)
[24 32 40] (3,)

điều này lặp lại trên các hàng (mờ đầu tiên) của a. xsau đó là mảng 1d và có thể được sửa đổi bằng x[:]=...hoặc x[...]=....

Và nếu tôi thêm các external_looplá cờ từ tiếp theo phần , xbây giờ là một mảng 1d, và x[:] =sẽ làm việc. Nhưng x[...] =vẫn hoạt động và tổng quát hơn. x[...]được sử dụng tất cả các nditerví dụ khác .

In [677]: for x in np.nditer(a, op_flags=['readwrite'], flags=['external_loop']):
     ...:     print(x, type(x), x.shape)
     ...:     x[...] = 2 * x
[ 0 16 32 48 64 80] <class 'numpy.ndarray'> (6,)

So sánh lần lặp hàng đơn giản này (trên mảng 2d):

In [675]: for x in a:
     ...:     print(x, x.shape)
     ...:     x[:] = 2 * x
     ...:     
[ 0  8 16] (3,)
[24 32 40] (3,)

điều này lặp lại trên các hàng (mờ đầu tiên) của a. xsau đó là mảng 1d và có thể được sửa đổi bằng x[:] = ...hoặc x[...] = ....

Đọc và thử nghiệm với nditertrang này từ đầu đến cuối. Tự nó, nditerkhông phải là hữu ích trong python. Nó không tăng tốc độ lặp lại - không cho đến khi bạn chuyển mã của mình sang cython. np.ndindexlà một trong số ít các numpyhàm không được biên dịch sử dụng nditer.


Lưu ý rằng những thứ như x [1,:, ...] cũng là một cú pháp được phép. Còn lại để tham khảo trong tương lai.
borgr
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.