Truyền danh sách trong hàm đệ quy Python

Trong Chương trước, chúng ta đã thảo luận về Danh sách Python, đối tượng

 4
4 tương tự như Danh sách như thế nào và cách chúng ta có thể đặt các đối tượng vào một
 4
4, xem xét phần bù của chúng và
 4
7 đối với
 4
4 trong MusicXML hoặc dưới dạng văn bản. Chúng tôi kết thúc bằng cách đặt một
 4
4 bên trong một
 4
4 khác, đây có vẻ là một thủ thuật hay cho đến khi chúng tôi phát hiện ra rằng chúng tôi không thể lấy được các phần tử bên trong
 4
4 bên trong

Trong chương này, chúng ta sẽ nghiên cứu cách khai thác sức mạnh của

listB[3]
2 lồng nhau. Chúng ta sẽ bắt đầu thảo luận về danh sách đệ quy [vì
listB[3]
2 hoạt động rất giống danh sách]. Những người có một số lập trình có thể sẽ muốn bỏ qua phần sau

danh sách danh sách

Danh sách [tương tự như Mảng trong các ngôn ngữ khác] có thể chứa tất cả những thứ khác bên trong chúng, bao gồm cả các danh sách khác. Vì vậy, hãy bắt đầu bằng cách tạo hai danh sách

listA = [10, 20, 30]
listB = [1, 2, 3, listA]

Bây giờ khi chúng ta nhìn vào danh sách, chúng ta sẽ thấy danh sách đó nằm trong danh sách đó

listB

 [1, 2, 3, [10, 20, 30]]

Lưu ý rằng khi chúng ta nhìn vào độ dài [

listB[3]
4] của danh sách B, nó cho thấy có 4 phần tử chứ không phải 6

len[listB]

 4

Đó là bởi vì phần tử thứ tư của listB [mà bạn sẽ nhớ lại, được gọi là

listB[3]
5 chứ không phải
listB[3]
6] bản thân nó là một danh sách, listA

listB[3]

 [10, 20, 30]

listB[3] is listA

 True

Vì vậy, nếu chúng ta muốn lấy phần tử thứ ba của listA, có một cách dễ dàng để thực hiện

listA[2]

listB
0

Nhưng chúng ta cũng có thể nghĩ rằng

listB[3]
7 cũng là phần tử thứ ba của phần tử thứ tư của listB. Vì vậy, chúng ta có thể viết điều này thay vì

listB
1

listB
0

Ồ, và vì mỗi phần tử này là phần tử cuối cùng trong danh sách tương ứng của chúng, thay vào đó chúng ta có thể viết

listB
3

listB
0

có nghĩa là "lấy phần tử cuối cùng của phần tử cuối cùng của danh sách"

Nhưng điều gì sẽ xảy ra nếu chúng ta chỉ muốn biết mọi số được lưu trữ ở bất kỳ đâu trong listB, ngay cả khi số đó nằm trong chính danh sách đó?

listB
5

listB
6

Thay vào đó, chúng ta phải kiểm tra xem mỗi “số” trong

listB[3]
8 thực sự là một số hay một danh sách. Và nếu đó là một danh sách, chúng ta nên tìm từng số trong đó và in ra. Đây là một bộ lệnh phức tạp hơn một chút để làm điều đó

listB
7

listB
8

Điều đó đã làm nó. Làm thế nào nó hoạt động? . Sau đó, ở dòng tiếp theo

 [10, 20, 30]
0 kiểm tra xem thứ đó có phải là một danh sách không. Nếu đó là
 [10, 20, 30]
1 thì chúng ta sẽ đến một vòng lặp bên trong, nơi chúng ta xem xét “thứ” [trong trường hợp này là
 [10, 20, 30]
2, nhưng chương trình không biết điều đó] và lấy “số” từ đó. Nhưng nếu "thứ" không phải là một danh sách, thì đó là nơi mà ____18_______3 xuất hiện, đó là thứ chúng tôi chạy nếu chúng tôi không có một danh sách, nó chỉ nói, in số

[Trong trường hợp này, chúng tôi giả định rằng chỉ có hai loại sự vật trong

listB[3]
8, các con số và các danh sách khác. ] Gặp lỗi nhớ đừng quên đoạn kết “. ” hoặc thụt lề dòng tiếp theo

Hàm và đệ quy

Nhưng điều gì sẽ xảy ra nếu chúng ta làm điều này

listB
9

Bây giờ vì listB chứa listA, chúng tôi kết thúc với một danh sách trong danh sách trong danh sách

 [1, 2, 3, [10, 20, 30]]
0

 [1, 2, 3, [10, 20, 30]]
1

Nếu chúng tôi muốn in tất cả các số trong listC, chúng tôi có thể viết một tập hợp các lệnh xấu xí như thế này [Tôi sẽ hiểu nếu bạn không thực sự muốn nhập số này và chỉ muốn tin tôi rằng nó hoạt động]

 [1, 2, 3, [10, 20, 30]]
2

 [1, 2, 3, [10, 20, 30]]
3

chà. Nếu đây là cách duy nhất để làm điều đó, tôi sẽ không trách bạn nếu bạn quyết định rằng lập trình không đáng để bạn phải đau đầu. Đặc biệt là vì bạn có thể đã đoán rằng chúng tôi có thể tạo ra.

 [10, 20, 30]
5 và nhận một lớp danh sách khác. May mắn thay, có một chút phép thuật lập trình gọi là “đệ quy” mà chúng ta có thể sử dụng để đi vào trọng tâm của vấn đề. Lưu ý rằng trong mã tôi vừa viết, có một vài dòng về cơ bản giống [với một vài từ được thay đổi] như các phần khác của mã. Với mã hóa đệ quy, chúng tôi sẽ tìm cách lưu các dòng đó để sử dụng lại chúng. Nhập sáu dòng này

 [1, 2, 3, [10, 20, 30]]
4

Những gì chúng tôi đã làm là tạo một chức năng mới gọi là ''flatPrint'' để tiếp cận danh sách các danh sách và in bất kỳ thứ gì có trong đó

Bây giờ cố gắng

 [1, 2, 3, [10, 20, 30]]
5

 [1, 2, 3, [10, 20, 30]]
3

nó hoạt động. Nhưng bằng cách nào?

Câu lệnh

 [10, 20, 30]
6 nói rằng chúng ta sẽ ''xác định'' một chức năng mới. Sau từ
 [10, 20, 30]
6 là tên của hàm – thứ mà chúng ta có thể gọi nó để sử dụng sau này. [Chúng tôi gọi quá trình lấy các cấu trúc lồng nhau và biến chúng thành thứ gì đó tuyến tính là “làm phẳng” chúng, giống như nghiền nát một hộp các tông. Vì đây là một máy làm phẳng cũng in những gì bên trong nó, nên
 [10, 20, 30]
8 là một cái tên hay cho nó. Lưu ý rằng giống như với các biến, trường hợp quan trọng trong Python, do đó,
 [10, 20, 30]
8 không giống như
listB[3] is listA
0 hoặc
listB[3] is listA
1 hoặc
listB[3] is listA
2. ]

Sau “flatPrint”, trong ngoặc đơn là tên biến

listB[3] is listA
3. Lưu ý rằng chúng tôi chưa sử dụng tên
listB[3] is listA
3 – nó không tồn tại. Ý nghĩa của
listB[3] is listA
3 ở đây là bất cứ khi nào chúng ta sử dụng hàm
 [10, 20, 30]
8, bất kể tên của danh sách là gì, thì trong vòng
 [10, 20, 30]
8 nó sẽ được gọi là
listB[3] is listA
3. Vì vậy, bạn có thể nói
listB[3] is listA
9, như chúng ta vừa làm, và trong hàm
 [10, 20, 30]
8,
 True
1 sẽ được gọi là
listB[3] is listA
3

Đây là một chức năng đơn giản hơn sẽ giải thích điều đó tốt hơn.

 True
3 nhận một số và in ra hình vuông của nó

 [1, 2, 3, [10, 20, 30]]
7

Bây giờ chúng ta có thể thử

 [1, 2, 3, [10, 20, 30]]
8

 [1, 2, 3, [10, 20, 30]]
9

len[listB]
0

len[listB]
1

len[listB]
2

len[listB]
3

Lưu ý hai điều trong trường hợp cuối cùng. Đầu tiên số pi không chính xác là 3. 14 – tất cả chúng ta đều biết điều đó; . Thứ hai, chúng tôi đã đưa biến

 True
4 vào hàm
 True
3. Nhưng trong hàm
 True
3 chúng ta không viết.
 True
7; . [Nhân tiện, thay vì viết
listA[2]
0 chúng ta có thể viết
listA[2]
1 vì ‘’ ** ‘’ là cách Python biểu thị số mũ]

Khi kết thúc một chức năng, bạn có thể

listA[2]
2 một thứ gì đó hoặc
listA[2]
3 một giá trị, giá trị này có thể được sử dụng cho bất kỳ thứ gì khác. Đây là
listA[2]
4 hoạt động rất giống với
 True
3, nhưng nó chia số thành khối và thay vì in ra, nó sẽ trả về số đó

len[listB]
4

Bởi vì chúng tôi không in

 True
9, chúng tôi có thể gán giá trị của cubeMe cho một biến khác

len[listB]
5

len[listB]
6

len[listB]
7

len[listB]
8

Lưu ý rằng nếu

listA[2]
7 và
listA[2]
8 thì chúng ta có thể thay thế
listA[2]
9 cho
listB
00 và viết

len[listB]
9

len[listB]
8

Do đó, sử dụng

listA[2]
3 thay vì
listA[2]
2 sẽ hiệu quả hơn, vì vậy sau khi kết thúc với
 [10, 20, 30]
8, chúng ta chủ yếu sẽ viết các hàm
listA[2]
3 chứ không phải hàm
listA[2]
2

Vì vậy, quay lại

 [10, 20, 30]
8, mà bạn sẽ nhớ là [Tôi đang thêm lại số dòng nhận xét để tôi có thể tham khảo]

 4
1

Hãy nhìn vào nó từng dòng một

Dòng 1, như chúng ta đã nói, định nghĩa hàm có tên là

 [10, 20, 30]
8 cần một danh sách mà chúng ta sẽ gọi là
listB[3] is listA
3

Dòng 2, nói “đối với mỗi thứ trong danh sách của tôi, hãy lấy nó và gọi nó là

listB
09. ” Khi chúng ta hoàn thành với
listB
09, chương trình sẽ quay lại dòng 2 để thực hiện việc tiếp theo

Dòng 3, kiểm tra xem

listB
09 có phải là danh sách không. Nếu vậy, chúng tôi làm dòng 4. Nếu không chúng ta nhảy đến dòng 5

Dòng 4. Đây là nơi phép màu xảy ra. Bây giờ chúng ta biết rằng

listB
09 là một danh sách. Vậy làm thế nào để chúng tôi in một danh sách [có thể có các danh sách khác bên trong nó]? . Về bản chất,
 [10, 20, 30]
8 sử dụng khả năng phân biệt rõ ràng giữa danh sách và số để in bất kỳ danh sách nội bộ nào. Chúng ta gọi các hàm sử dụng [“gọi”] chính các hàm đệ quy và quá trình sử dụng các hàm đệ quy được gọi là đệ quy. Đó là một công cụ mạnh mẽ và chúng tôi sẽ sử dụng rất nhiều trong music21

Dòng 5, là nơi chúng ta nhảy từ dòng 3 nếu

listB
09 không phải là danh sách, vì vậy Python sẽ thực thi dòng 6

Dòng 6, chỉ cần in

listB
09, mà bây giờ chúng ta biết là một số

Một lời cảnh báo. không giống như một số ngôn ngữ lập trình [Java, C, v.v. ], Python không bao giờ kiểm tra xem những gì bạn chuyển đến

 [10, 20, 30]
8 có thực sự là một danh sách không. Vì vậy, bạn có thể thử làm điều gì đó như
listB
18 nhưng vì
listB[3]
7 không phải là một danh sách nên bạn sẽ gặp lỗi

 4
2

 4
3

Để biết thêm thông tin về cấu trúc dữ liệu [danh sách, danh sách của danh sách và những thứ chúng tôi chưa hiểu, tôi khuyên bạn nên xem hướng dẫn Python của Google, đặc biệt là lớp 2]

Gói [lại

Trong chương này, chúng ta đã xem xét cách chúng ta có thể nhìn vào bên trong danh sách của danh sách, điều này sẽ rất quan trọng khi chúng ta xem xét cách làm việc với

listB[3]
2 của
listB[3]
2 trong âm nhạc21, để xem xét
listB
22 trong phạm vi
listB
23 trong phạm vi
listB
24. Chúng tôi cũng đã học cách xác định một hàm và viết các hàm đệ quy để thực hiện công việc hiệu quả chỉ trong một vài dòng mã. Trong chương tiếp theo, chúng ta áp dụng tất cả những điều này vào âm nhạc với

Chúng ta có thể sử dụng ngăn xếp trong đệ quy không?

Hàm đệ quy sử dụng thứ gọi là “ngăn xếp cuộc gọi. ” Khi một chương trình gọi một chức năng, chức năng đó sẽ ở trên cùng của ngăn xếp cuộc gọi. Điều này tương tự như một chồng sách.

Lặp lại có nhanh hơn đệ quy không?

Lặp nhanh hơn và hiệu quả hơn đệ quy . Việc tối ưu hóa các mã lặp lại dễ dàng hơn và chúng thường có độ phức tạp về thời gian đa thức. Chúng được sử dụng để lặp lại các phần tử có trong cấu trúc dữ liệu như mảng, tập hợp, bản đồ, v.v.

Bạn có thể thoát khỏi Python đệ quy không?

Một cách để thoát khỏi hàm đệ quy trong Python là ném một ngoại lệ và bắt nó ở cấp cao nhất. Một số người sẽ nói rằng đây không phải là cách đúng đắn để nghĩ về đệ quy, nhưng nó hoàn thành công việc

Trình tạo có thể được đệ quy?

Giống như các hàm thông thường, các trình tạo có thể được đệ quy , nghĩa là chúng có thể gọi chính chúng bên trong thân hàm của chúng.

Chủ Đề