Liệt kê phép nhân Python

Cho dù bạn là một tân binh hay một lập trình viên Python có kinh nghiệm, rất có thể bạn đã từng sử dụng phép nhân danh sách và/hoặc đọc về nó trong các bài viết kiểu “các tính năng thú vị của Python” đó

Điều này là do nó chắc chắn là một trong những tính năng thú vị được thiết kế để giúp cuộc sống Python của bạn dễ dàng hơn

Điểm hay của phép nhân danh sách là nó trừu tượng hóa quá trình khởi tạo danh sách

Thay vì sử dụng cách tiếp cận lặp lại hoặc hiểu danh sách

# Iterative approach
my_list = []
for _ in range[N]:
my_list.append[n]
# List comprehension
my_list = [n for _in range[N]]

bạn có thể nhận được kết quả tương tự với

my_list = [n] * N

Bạn thấy đấy, tôi đã học các ngôn ngữ lập trình theo thứ tự sau

C -> C++ -> MATLAB -> R -> Python.

Không có ngôn ngữ lập trình nào khác mà tôi đã làm việc trước Python thậm chí có thể cung cấp từ xa sự ngắn gọn và trực quan như vậy

Tuy nhiên, khi tôi bắt đầu viết mã ngày càng phức tạp hơn, phép nhân danh sách bắt đầu khiến tôi lo lắng.

Tôi nhớ rằng có lần tôi đã dành cả buổi chiều để gỡ lỗi mã chỉ để phát hiện ra rằng vấn đề bắt nguồn từ việc tạo danh sách không đúng cách bằng cách sử dụng toán tử

my_list = [n] * N
3

Do đó, tôi cảm thấy cần phải thảo luận về vấn đề này vì tôi biết thực tế là một số nhà phát triển vẫn chưa biết về sự đánh đổi đi kèm với toán tử ngôi sao khi tạo danh sách

Có gì sai với phép nhân danh sách

Hãy xem xét đoạn mã sau

>>> my_list = [0] * 3
>>> my_list[0] = 1
>>> my_list
[1, 0, 0]

Đây là những gì bạn mong đợi. Càng xa càng tốt

Bây giờ, hãy thử tạo một mảng 2D bằng cách sử dụng phương pháp tương tự

>>> my_list = [[0] * 3] * 5
>>> my_list[0][0] = 1
>>> my_list
[[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0]]

Hừm. Đây có lẽ không phải là điều bạn muốn

Làm thế nào về việc đẩy nó hơn nữa bằng cách khởi tạo một mảng 3D

>>> my_list = [[[0] * 3] * 5] * 2
>>> my_list[0][0][0] = 1
>>> my_list
[[[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0]], [[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0]]]

Đầu ra dự kiến ​​sẽ là cập nhật giá trị đầu tiên của danh sách con

my_list = [n] * N
4. Tuy nhiên, có vẻ như bản cập nhật đã được sao chép trên tất cả các danh sách phụ

Vì vậy, tại sao điều này xảy ra?

Phép nhân danh sách hoạt động như thế nào?

Để hiểu hành vi trước đó, bạn nên xem lại Câu hỏi thường gặp của Python, trong đó nói

“Lý do là việc sao chép danh sách với

my_list = [n] * N
3 không tạo bản sao, nó chỉ tạo tham chiếu đến các đối tượng hiện có. ”

Hãy dịch mã này thành mã để hiểu rõ hơn về cách Python hoạt động bên dưới mui xe

  • Liệt kê phép nhân
my_list = [[0] * 5] * 5
for i in range[5]:
print[id[my_list[i]]]

đầu ra

my_list = [n] * N
0
  • Sử dụng vòng lặp for
my_list = [n] * N
1

đầu ra

my_list = [n] * N
2
  • Diễn dịch

Không giống như vòng lặp

my_list = [n] * N
6, tất cả các danh sách được sao chép thông qua toán tử
my_list = [n] * N
3 trỏ đến cùng một địa chỉ bộ nhớ. Điều này có nghĩa là bất kỳ thay đổi nào ảnh hưởng đến một danh sách lồng nhau sẽ ảnh hưởng đến tất cả các danh sách khác, điều này rõ ràng là đi ngược lại mục đích ban đầu của chúng ta

Câu hỏi bây giờ trở thành

  • Tại sao ví dụ đầu tiên
    my_list = [n] * N
    8 hoạt động tốt, mặc dù tất cả các thành phần của danh sách đều tham chiếu đến cùng một đối tượng?

Hóa ra lý do đằng sau hành vi này [như đã nêu trong Python wikibook] là do danh sách là các mục có thể thay đổi trong khi ________ 19 và những thứ tương tự là bất biến. kiểm tra cái này

Nguồn

Và vì các đối tượng bất biến không thể thay đổi, Python tạo một tham chiếu mới [khác] cho đối tượng khi bạn cập nhật một mục trong danh sách

my_list = [n] * N
0

cách giải quyết

Một cách khắc phục nhanh chóng và dễ dàng cho vấn đề này là sử dụng tính năng hiểu danh sách. Tất nhiên, đây là phần bổ sung cho vòng lặp

my_list = [n] * N
6 tiêu chuẩn

my_list = [n] * N
1

Ngoài ra, chúng ta có thể thấy rằng một địa chỉ bộ nhớ khác đã được phân bổ cho mỗi danh sách

my_list = [n] * N
2

Quan trọng hơn, phương pháp này hoạt động tốt trong mọi tình huống

Vì vậy, tại sao bạn không kiên trì và chơi an toàn hơn là phải suy nghĩ kỹ trước khi sử dụng phép nhân danh sách?

Sự kết luận

Tôi không phải là một fan hâm mộ lớn của đường cú pháp Pythonic

Vâng, tôi đồng ý rằng nó tạo ra một mã ngắn gọn và súc tích

Tuy nhiên, khi nào có

C -> C++ -> MATLAB -> R -> Python.
1 trong ngành công nghiệp phần mềm?

Trên thực tế, càng viết mã bằng Python, tôi càng thấy mình nghiêng về việc sử dụng cú pháp tiêu chuẩn của Python và bỏ qua các phím tắt

Vào cuối ngày, điều quan trọng là hiệu suất, khả năng bảo trì và khả năng đọc. Không phải bạn có bao nhiêu dòng mã

Và nếu bạn không thể làm gì nếu không có phím tắt, thì ít nhất hãy đọc cái hay, cái dở và cái xấu của cú pháp bạn đang sử dụng. Trong trường hợp này, một sự hiểu biết vừa phải về các khái niệm công nghệ phần mềm [i. e. , cấu trúc dữ liệu, cấp phát bộ nhớ…] có thể được yêu cầu

Mã hóa vui vẻ

Nếu bạn thấy điều này hữu ích, hãy cân nhắc trở thành thành viên cao cấp. Nếu bạn sử dụng liên kết này, tôi sẽ nhận được một vết cắt nhỏ

Danh sách trong Python có thể được nhân lên không?

Danh sách và chuỗi có nhiều điểm chung. Cả hai đều có trình tự và giống như trăn, chúng dài ra khi bạn cho chúng ăn. Giống như một chuỗi, chúng ta có thể nối và nhân danh sách Python .

Bạn có thể nhân một danh sách với một danh sách không?

Nhân hai danh sách bằng vòng lặp for . Thông qua vòng lặp for, chúng ta có thể lặp qua danh sách. Tương tự, với mỗi lần lặp, chúng ta có thể nhân các phần tử từ cả hai danh sách. Với mục đích này, chúng ta có thể sử dụng Chức năng Zip.

Chủ Đề