Hướng dẫn are nested functions bad in python? - các hàm lồng nhau có xấu trong python không?

r/Python

Đăng bởi 1 năm trước1 year ago

Lưu trữ

Hôm nay trên PR, tôi đã thấy một số chức năng được xác định trong hàm STR và tôi lưu ý rằng điều đó nên được thay đổi để đáp ứng các thực tiễn tốt nhất/PEP8.str function, and I noted that that should be changed to meet best practices/pep8.

Người gửi lập luận rằng đó không phải là vấn đề và chắc chắn tôi đã kiểm tra PEP8 và không thể tìm thấy một tham chiếu đến nó.

Tôi có thể tuyên thệ rằng các tuyên bố chức năng làm tổ bị coi thường/thực hành xấu trong Python; Tôi đúng hay tôi chỉ đang đánh giá sai?

Chủ đề này được lưu trữ

Nhận xét mới không thể được đăng và phiếu bầu không thể được chọn

Tôi không đề cập đến việc đóng cửa, trong đó hàm bên ngoài trả về hàm bên trong hoặc ghi nhớ, cụ thể. Đã có một vài trường hợp tôi muốn viết một chức năng đệ quy, có lẽ với ghi nhớ và có vẻ đơn giản hơn nhiều để khởi tạo từ điển hoặc một số cấu trúc dữ liệu khác ở hàm bên ngoài, và sau đó có chức năng trợ giúp đệ quy ghi và truy cập các dict và các đối số của hàm bên ngoài. Đây là những gì tôi muốn nói -

def foo[arr, l]:
   cache = {}
   result = []

   def recursive_foo_helper[i, j, k]:
      # some code that depends on arr, l, i, j, k, cache, and result

   for [x, y] in arr:
      if recursive_foo_helper[x, y, k]:
         return result
   return None

thay vì có chức năng trợ giúp được khai báo riêng với một số chữ ký siêu dài như,

recursive_foo_helper[arr, l, i, j, k, cache={}, result=[]]

Tôi đã đọc rằng làm điều này là khá tiêu chuẩn để ghi nhớ, nhưng tôi tò mò liệu có sự đồng thuận về việc liệu có ổn không khi làm cho các chức năng của người trợ giúp đệ quy.

Trong một bài tập về nhà gần đây, cuối cùng tôi đã gọi các chức năng của mình theo cách xấu xí

recursive_foo_helper[arr, l, i, j, k, cache={}, result=[]]
1, chương trình này đã hoạt động hoàn hảo nhưng tôi vẫn cảm thấy như mình đang làm gì đó sai.

Là những chức năng gọi như thế này thực hành xấu và nếu vậy: thay vào đó tôi nên làm gì?

BLRFL

Huy hiệu vàng 20k247 Huy hiệu bạc75 Huy hiệu đồng2 gold badges47 silver badges75 bronze badges

Hỏi ngày 17 tháng 4 năm 2016 lúc 11:06Apr 17, 2016 at 11:06

9

Điều này thực sự phụ thuộc vào số lượng làm tổ bạn sử dụng. Rốt cuộc, bạn được phép sử dụng kết quả chức năng trực tiếp trong các biểu thức để cải thiện khả năng đọc. Cả hai, mã không sử dụng các biểu thức lồng nhau [như mã trình biên dịch] và mã sử dụng quá nhiều biểu thức lồng nhau là khó đọc. Mã tốt cố gắng đạt được sự cân bằng giữa các thái cực.

Vì vậy, hãy nhìn vào một số ví dụ. Người bạn đã đưa ra trong câu hỏi của bạn có vẻ khá hợp pháp đối với tôi, vì vậy không có gì phải lo lắng ở đây. Tuy nhiên, một dòng như

foo[bar[baz[moo, fab], bim[bam[ext, rel, woot, baz[moo, fab]], noob], bom, zak[bif]]];

Chắc chắn sẽ không được chấp nhận. Tương tự như vậy, mã như

double xsquare = x*x;
double ysquare = y*y;
double zsquare = z*z;
double xysquare = xsquare + ysquare;
double xyzsquare = xysquare + zsquare;
double length = sqrt[xyzsquare];

cũng sẽ không dễ đọc.

recursive_foo_helper[arr, l, i, j, k, cache={}, result=[]]
2 dễ hiểu hơn nhiều, mặc dù nó kết hợp tổng cộng sáu hoạt động khác nhau trong một biểu thức.

Lời khuyên của tôi là chú ý đến những biểu hiện mà bạn vẫn có thể phân tích trong đầu một cách dễ dàng. Thời điểm bạn cần có một cái nhìn thứ hai để nắm bắt những gì một biểu thức làm, đã đến lúc giới thiệu một biến bổ sung.

Đã trả lời ngày 17 tháng 4 năm 2016 lúc 20:35Apr 17, 2016 at 20:35

4

Khái niệm này dựa trên câu hỏi của bạn rất quan trọng, tôi cảm thấy nó cần một câu trả lời khác thay vì chỉ là một nhận xét [như tôi đã bắt đầu làm].

3 câu trả lời khác cho đến nay cung cấp một số điểm xem xét hữu ích về việc liệu một tình huống nhất định có xứng đáng bằng cách sử dụng những gì bạn gọi là "chức năng lồng nhau gọi" hay không. Nhưng có lẽ một điểm quan trọng hơn là ẩn trong các bình luận trong câu hỏi của bạn: Trong trường hợp bạn bỏ lỡ sự tinh tế trong những gì những người uyên bác đó đang gợi ý, Carl, bạn đã tự mình khám phá ra chủ đề thực sự được gọi là lập trình chức năng. Nếu bạn chưa bao giờ thấy thuật ngữ này, bạn có thể không nghĩ rằng đó thực sự là một "điều" trong nhận xét của @HighPerformAcemark.functional programming. If you have never seen the term, you might not have thought it was really a "thing" in @HighPerformanceMark's comment.

Nhưng thực sự nó là! Lập trình chức năng đã được viết trong nhiều thập kỷ, vì bài báo bán kết của John Hughes tại sao các vấn đề lập trình chức năng. Có một số ngôn ngữ là ngôn ngữ chức năng [nghĩa là chúng chỉ cho phép bạn viết theo kiểu lập trình chức năng], các ngôn ngữ như Erlang, Lisp, Ocaml hoặc Haskell. Nhưng có nhiều ngôn ngữ hơn là các ngôn ngữ bắt buộc/chức năng lai. Đó là, chúng là các ngôn ngữ bắt buộc theo truyền thống nhưng cũng cung cấp một số hỗ trợ cho lập trình chức năng, bao gồm Perl, C ++, Java, C#, và nhiều hơn nữa. Mục nhập của Wikipedia về lập trình chức năng cung cấp một phần đẹp cho thấy so sánh phong cách chức năng so với phong cách bắt buộc cho một số ngôn ngữ.

Có nhiều điều để nói về sự khác biệt giữa các kiểu bắt buộc và chức năng, nhưng điểm khởi đầu quan trọng là với lập trình chức năng, các chức năng hoặc phương pháp không có tác dụng phụ, làm cho nó nói chung dễ hiểu và gỡ lỗi hơn.

Để đọc thêm, bạn cũng có thể xem xét tại sao "tại sao vấn đề lập trình chức năng" quan trọng và một bài viết thú vị khác ở đây, tại sao ngôn ngữ chức năng?

Đã trả lời ngày 18 tháng 4 năm 2016 lúc 3:40Apr 18, 2016 at 3:40

Tôi nghĩ rằng nó tốt hay xấu phụ thuộc rất nhiều vào bối cảnh. Lý do chính có thể được coi là xấu là vì nó có thể làm cho mã khó đọc và gỡ lỗi hơn. Điều này đặc biệt đúng khi bạn đầu tiên học lập trình. Khi kỹ năng mã hóa và mã của bạn trở nên tiên tiến hơn, có những lúc điều này được chấp nhận.

Ví dụ, hãy xem xét một thông báo lỗi như thế này:

line 1492: missing argument "foo"

Làm thế nào để bạn biết nếu đối số bị thiếu là

recursive_foo_helper[arr, l, i, j, k, cache={}, result=[]]
3,
recursive_foo_helper[arr, l, i, j, k, cache={}, result=[]]
4 hoặc
recursive_foo_helper[arr, l, i, j, k, cache={}, result=[]]
5? Tùy thuộc vào ngôn ngữ, thông báo lỗi có thể cho bạn biết, nhưng nó có thể không.

Nếu đã phá vỡ các chức năng đó các cuộc gọi khác nhau và thông báo lỗi vẫn chỉ cho bạn vào dòng 1492, bạn sẽ biết ngay lập tức vấn đề nằm ở đâu:

1491: input = cashInput[]
1492: parsed_value = cashParser[input]
1493: receipt = uglyReceipt[parsed_value]

Với các bước bị phá vỡ riêng biệt, việc gỡ lỗi dễ dàng hơn nhiều vì có thể đặt điểm dừng ở bất kỳ bước nào và bạn có thể dễ dàng tiêm các giá trị bằng cách thay đổi giá trị của các biến cục bộ.

Đã trả lời ngày 17 tháng 4 năm 2016 lúc 15:31Apr 17, 2016 at 15:31

Bryan Oakleybryan OakleyBryan Oakley

25K5 Huy hiệu vàng64 Huy hiệu bạc88 Huy hiệu đồng5 gold badges64 silver badges88 bronze badges

Nó hoàn toàn không phải là một thực hành xấu nói chung. Các chức năng Call Chấp nhận các giá trị và một cách tạo ra một giá trị là bằng cách gọi một hàm khác.

Khi tôi thấy một biến được xác định, như:

parsed_value = cashParser[input]

... Tôi phải xem xét rằng

recursive_foo_helper[arr, l, i, j, k, cache={}, result=[]]
6 có thể được sử dụng nhiều lần và có lẽ tôi sẽ phải kiểm tra xem điều này có đúng hay không [nếu thay đổi của tôi phá vỡ thứ gì khác ở nơi khác?]. Khi bạn bắt đầu thêm nhiều biến, nó có thể trở nên phức tạp hơn cho người đọc để theo dõi tất cả chúng và cách chúng có liên quan. Vì vậy, tôi cảm thấy nhẹ nhõm khi thấy:

receipt = uglyReceipt[cashParser[input]]

... Bởi vì phạm vi/tuổi thọ của giá trị trung gian là rõ ràng. Bây giờ, như mọi khi, việc chia một biểu thức dài thành các câu lệnh riêng biệt có thể giúp ích, đặc biệt là nếu một tên biến có thể cho độ chính xác hơn về mục đích của một giá trị:

user_name = input[]

Đã trả lời ngày 17 tháng 4 năm 2016 lúc 16:08Apr 17, 2016 at 16:08

Coredumpcoredumpcoredump

5,8151 Huy hiệu vàng20 Huy hiệu bạc27 Huy hiệu đồng1 gold badge20 silver badges27 bronze badges

Một số Pro và Con liên quan đến khả năng đọc và trải nghiệm gỡ lỗi đã được đưa ra. Một điều hiển nhiên nhất trong quan điểm của tôi vẫn còn thiếu: bằng cách xâu chuỗi các cuộc gọi lại với nhau, bạn sẽ chuyển cơ hội để kể câu chuyện logic.

Bằng cách gán kết quả trung gian cho các biến, bạn thể hiện ý nghĩa của chúng thông qua các định danh biến của bạn.

SendDoc[ReadFile[GetFilePath[]], context.GetUsersByType[UserType.LoggedOn | UserType.Recent]];

Đó là rất nhiều để đưa vào. Người đọc cần phân tích lại tuyên bố và đưa ra các giả định về những gì đang xảy ra hoặc không thể bị làm phiền vì nó quá nhiều. Rõ ràng một số tài liệu được gửi ...

recursive_foo_helper[arr, l, i, j, k, cache={}, result=[]]
0

Điều này làm cho nó dễ quản lý hơn với đầu: một báo cáo được đọc từ một tệp và được gửi đến người dùng đang hoạt động.

Nó cũng dễ dàng hơn để sửa đổi và một thay đổi sẽ dễ dàng hơn để làm theo. Nếu bạn cần thêm một bước sẽ là một hoặc nhiều dòng bổ sung hơn là tháo gỡ một lớp lót hoặc chèn thêm vào đó.

Đã trả lời ngày 25 tháng 12 năm 2021 lúc 13:06Dec 25, 2021 at 13:06

Martin Maatmartin MaatMartin Maat

16.7k3 Huy hiệu vàng26 Huy hiệu bạc53 Huy hiệu Đồng3 gold badges26 silver badges53 bronze badges

Có tốt không khi có các chức năng lồng nhau trong Python?

Trừ khi bạn cần che giấu các chức năng của mình từ thế giới bên ngoài, không có lý do cụ thể nào để chúng được lồng. Bạn có thể định nghĩa các chức năng đó là các chức năng cấp cao nhất và bạn sẽ tốt.there's no specific reason for them to be nested. You could define those functions as private top-level functions, and you'd be good to go.

Có tệ khi sử dụng các chức năng lồng nhau trong Python không?

Khi mã hóa, chúng tôi muốn ẩn chi tiết phi vật chất.Ví dụ.Chúng tôi đánh dấu các chức năng riêng tư càng nhiều càng tốt [trong Python, chúng tôi thực sự không thể, vì vậy chúng tôi sử dụng một hội nghị nhấn mạnh hàng đầu _Lhe_this].Vì vậy, đó là một lý do chính đáng để sử dụng các chức năng lồng nhau - giúp người đọc hiểu rằng logic của thanh sẽ không được sử dụng ở bất kỳ nơi nào khác.help the reader understand that the logic of bar will not be used anywhere else.

Có tệ không khi có các chức năng lồng nhau?

Không, không có gì sai với điều đó, và trong JS, đó thường là một điều tốt.Các hàm bên trong có thể không phải là một hàm thuần túy, nếu chúng dựa vào các biến đóng.Nếu bạn không cần đóng cửa hoặc không cần phải lo lắng về việc gây ô nhiễm không gian tên của bạn, hãy viết nó như một anh chị em.. the inside functions may not be a pure function, if they rely on closure variables. If you don't need a closure or don't need to worry about polluting your namespace, write it as a sibling.

Có tốt không khi có các chức năng lồng nhau?

Các chức năng lồng nhau rất hữu ích khi một tác vụ phải được thực hiện nhiều lần trong hàm nhưng không nằm ngoài hàm.Theo cách này, các chức năng lồng nhau giúp chức năng cha mẹ thực hiện nhiệm vụ của mình trong khi ẩn trong chức năng cha.THỬ NÓ!Gọi hàm my_dist_xyz cho x = [0, 0], y = [0, 1], z = [1, 1].. In this way, nested functions help the parent function perform its task while hiding in the parent function. TRY IT! Call the function my_dist_xyz for x = [0, 0], y = [0, 1], z = [1, 1].

Bài Viết Liên Quan

Chủ Đề