Cách phân công hoạt động với lát danh sách Python?


99

Tài liệu Python nói rằng việc cắt một danh sách sẽ trả về một danh sách mới.
Bây giờ nếu một danh sách "mới" đang được trả lại, tôi có những nghi ngờ sau liên quan đến "Chuyển nhượng cho các lát"

a = [1, 2, 3]
a[0:2] = [4, 5]
print a

Bây giờ đầu ra sẽ là:

[4, 5, 3] 
  1. Làm thế nào một cái gì đó đang trả lại một cái gì đó có thể xuất hiện ở phía bên trái của biểu thức?
  2. Có, tôi đã đọc tài liệu và nó nói rằng có thể, bây giờ kể từ khi cắt một danh sách trả về một danh sách "mới", tại sao danh sách ban đầu lại được sửa đổi? Tôi không thể hiểu cơ học đằng sau nó.

@Mark Longair xin lỗi, tôi nghĩ chỉ có mã được định dạng chứ không phải đầu ra
Kartik Anand


7
Bạn có hiểu những gì a[0] = 4sẽ làm gì?
Josh Lee

1
@KartikAnand Phép gán Slice là một tình huống đặc biệt trong đó danh sách mới không được tạo. Không có ý nghĩa gì khi tạo một đối tượng mà không có tên ràng buộc ở phía bên trái của an =, vì vậy thay vì loại bỏ điều này như cú pháp không hợp lệ, python biến nó thành một thứ giống như những gì bạn có thể mong đợi. Vì python không có tham chiếu, nó sẽ không hoạt động nếu kết quả của một lát thay đổi danh sách ban đầu. Bạn nhận được một bản sao. Nếu bạn cung cấp thêm thông tin về đơn đăng ký của mình, chúng tôi có thể giúp bạn thực hiện mọi việc theo cách 'pythonic' tốt hơn. :)
Casey Kuball

1
@Darthfett Tôi không làm việc trên bất kỳ ứng dụng ngay bây giờ chứ không phải tôi đang dạy bản thân mình python trước khi tôi bắt đầu nhận được bàn tay bẩn :) tôi
Kartik Anand

Câu trả lời:


114

Bạn đang nhầm lẫn giữa hai hoạt động khác nhau sử dụng cú pháp rất giống nhau:

1) cắt lát:

b = a[0:2]

Thao tác này tạo một bản sao của lát cắt avà gán nó cho b.

2) phân công lát cắt:

a[0:2] = b

Điều này thay thế lát cắt abằng nội dung của b.

Mặc dù cú pháp tương tự nhau (tôi tưởng tượng theo thiết kế!), Đây là hai hoạt động khác nhau.


4
Đó là những gì tôi nghi ngờ là, trong trường hợp thứ hai, tại sao không phải là phần của a, một danh sách mới ??
Kartik Anand

11
@KartikAnand Vì không phải vậy. Đó không phải là những gì ngôn ngữ chỉ định.
Marcin

Nói rõ hơn, "take a slice of" thực sự có nghĩa là "tạo một bản sao của một lát cắt", đây là nguyên nhân dẫn đến một phần của sự nhầm lẫn.
Mark Ransom

2
@KartikAnand: Về cơ bản, có. Thông dịch viên biết cái nào là cái nào và xử lý chúng một cách thích hợp.
NPE

1
@Dubslow: bạn có thể làm điều đó bằng cách sử dụng mô-đun itertools . Đối với trường hợp của bạn sử dụng chức năng islice , với start=1, stop=None. Điều này sẽ tránh bất kỳ bản sao nào và sử dụng đánh giá lười biếng (trong trường hợp của bạn là lười biếng truy cập vào danh sách gốc).
Spiros

66

Khi bạn chỉ định aở phía bên trái của =toán tử, bạn đang sử dụng phép gán thông thường của Python , thao tác này sẽ thay đổi tên atrong ngữ cảnh hiện tại để trỏ đến giá trị mới. Điều này không thay đổi giá trị trước đó ađã trỏ tới.

Bằng cách chỉ định a[0:2]ở bên trái của =toán tử, bạn đang nói với Python rằng bạn muốn sử dụng Slice Assignment . Slice Assignment là một cú pháp đặc biệt cho danh sách, nơi bạn có thể chèn, xóa hoặc thay thế nội dung từ danh sách:

Chèn :

>>> a = [1, 2, 3]
>>> a[0:0] = [-3, -2, -1, 0]
>>> a
[-3, -2, -1, 0, 1, 2, 3]

Xóa :

>>> a
[-3, -2, -1, 0, 1, 2, 3]
>>> a[2:4] = []
>>> a
[-3, -2, 1, 2, 3]

Thay thế :

>>> a
[-3, -2, 1, 2, 3]
>>> a[:] = [1, 2, 3]
>>> a
[1, 2, 3]

Ghi chú:

Độ dài của lát cắt có thể khác với độ dài của trình tự được ấn định, do đó thay đổi độ dài của trình tự đích, nếu trình tự đích cho phép. - nguồn

Slice Assignment cung cấp chức năng tương tự như Tuple Unpacking . Ví dụ, a[0:1] = [4, 5]tương đương với:

# Tuple Unpacking
a[0], a[1] = [4, 5]

Với Tuple Unpacking, bạn có thể sửa đổi danh sách không tuần tự:

>>> a
[4, 5, 3]
>>> a[-1], a[0] = [7, 3]
>>> a
[3, 5, 7]

Tuy nhiên, việc giải nén tuple bị giới hạn ở việc thay thế, vì bạn không thể chèn hoặc xóa các phần tử.

Trước và sau tất cả các hoạt động này, alà cùng một danh sách chính xác. Python chỉ đơn giản là cung cấp một đường cú pháp đẹp để sửa đổi một danh sách tại chỗ.


6
Tương tự nhưng không giống nhau, vì bạn có thể có số phần tử không bằng nhau ở bên trái và bên phải.
Mark Ransom

@MarkRansom Đó là một điểm tuyệt vời, tôi đã bổ sung thêm thông tin để làm rõ điều này.
Casey Kuball

2
a[:] = some_listtương đương với a = some_list[:]hoặc a = some_list?
jadkik94

2
@ jadkik94 Cũng không. a[:] = some_listđặt mọi phần tử của thành phần acủa some_list. Thực hiện một trong những điều bạn đề cập sẽ thay đổi những gì ađang có. Ví dụ: a = [1, 2, 3] b = a a[:] = [4, 5, 6] a is b. Dòng cuối cùng sẽ là Sai nếu nó thay đổi agiá trị của nó, thay vì làm thay đổi nó.
Casey Kuball

@Darthfett Thật thú vị, tôi đã tìm thấy khác :) Cảm ơn.
jadkik94

25

Tôi đã gặp câu hỏi tương tự trước đây và nó liên quan đến đặc điểm ngôn ngữ. Theo báo cáo phân công ,

  1. Nếu phía bên trái của phép gán là đăng ký, Python sẽ gọi __setitem__đối tượng đó. a[i] = xtương đương với a.__setitem__(i, x).

  2. Nếu phía bên trái của phép gán là lát cắt, Python cũng sẽ gọi __setitem__, nhưng với các đối số khác nhau: a[1:4]=[1,2,3]tương đương với a.__setitem__(slice(1,4,None), [1,2,3])

Đó là lý do tại sao lát danh sách ở bên trái của '=' hoạt động khác.


4

Bằng cách cắt ở phía bên trái của một thao tác gán, bạn đang chỉ định các mục cần gán.

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.