Là thay đổi loại của một biến giữa chừng thông qua một thủ tục trong một phong cách xấu ngôn ngữ gõ?


8

Trong Python (và đôi khi là PHP) khi các biến không có kiểu cố định, tôi sẽ thường xuyên thực hiện 'biến đổi kiểu' trên một phần của biến thông qua logic của mã của tôi. Tôi không (nhất thiết) nói về các phôi đơn giản, nhưng về các hàm thay đổi loại biến trong khi về cơ bản nó đại diện cho cùng một giá trị hoặc dữ liệu.

Ví dụ: tôi có thể viết mã như thế này khi thực hiện một yêu cầu web, sử dụng responsebiến để lưu trữ một đối tượng addurlinfo, sau đó là nội dung chuỗi của đối tượng đó và từ điển được trả về bằng cách phân tích chuỗi dưới dạng JSON:

response = urlopen(some_url)
assert response.info().type == 'application/json'

response = response.read()
logger.debug('Received following JSON response: ' + response)

response = json.loads(response)
do_something(response)

(Được rồi, đó là một ví dụ hơi khó hiểu, nhưng tôi nghĩ nó thể hiện ý tưởng tốt). Cảm giác của tôi là điều này tốt hơn so với việc sử dụng ba tên biến riêng biệt bởi vì a) nó truyền tải rằng responsebiến đó chứa thông tin cơ bản giống nhau, chỉ "biến đổi" thành một loại khác và b) nó truyền tải rằng các đối tượng trước đó sẽ không không cần thiết nữa, vì bằng cách gán lại biến của chúng, tôi đã làm cho chúng không có sẵn cho mã sau này.

Sự đánh đổi, tôi đoán, là người đọc có thể trở nên bối rối về loại biến là gì tại bất kỳ thời điểm nào.

Đây có phải là phong cách xấu và tôi có nên sử dụng ba biến khác nhau trong ví dụ trên thay vì gán lại cho một biến không? Ngoài ra, đây có phải là tiêu chuẩn thực hành trong các ngôn ngữ gõ động, hay không? Tôi chưa thấy đủ mã của người khác để biết.

Câu trả lời:


9

Tôi sẽ đi ra ngoài và nói: Không, đây là một ý tưởng tồi tệ.

Đây chỉ là một trường hợp đặc biệt của việc sử dụng lại một biến, đó là một ý tưởng tồi - chủ yếu là vì nó làm cho khó hiểu những gì một biến chứa tại bất kỳ điểm nào trong luồng chương trình. Xem ví dụ: Tôi có nên sử dụng lại các biến?

Về điểm của bạn: Điểm bạn tăng là hợp lệ, chỉ là việc sử dụng lại biến không phải là giải pháp tốt :-).

a) nó truyền tải rằng biến trả lời về cơ bản chứa cùng một thông tin, chỉ cần 'biến đổi' thành một loại khác

Cung cấp thông tin này là một ý tưởng tốt . Tuy nhiên, đừng làm điều này bằng cách sử dụng cùng một biến, bởi vì sau đó bạn che khuất sự thật rằng thông tin đã được chuyển đổi. Thay vào đó, sử dụng tên với tiền tố / hậu tố phổ biến. Trong ví dụ của bạn:

rawResponse = urlopen(some_url)
[...]    
jsonResponse = response.read()
[...]    
responseData = json.loads(response)
[...]

Điều này cho thấy rõ rằng các biến có liên quan chặt chẽ với nhau, nhưng cũng không chứa cùng một dữ liệu.

b) nó truyền đạt rằng các đối tượng trước đó sẽ không cần thiết nữa, vì bằng cách gán lại biến của chúng, tôi đã làm cho chúng không có sẵn cho mã sau này.

Một lần nữa, truyền đạt thông tin "không còn cần thiết" này là tốt, nhưng đừng làm điều đó bằng cách sử dụng lại biến: Việc gán lại sử dụng thường sẽ khó nhìn thấy, vì vậy bạn chỉ khiến người đọc nhầm lẫn.

Thay vào đó, nếu một biến tồn tại lâu sau lần sử dụng cuối cùng, đó là một dấu hiệu cho thấy phương thức / hàm quá dài. Chia phần với các biến có thời gian tồn tại thành hàm phụ; điều đó làm cho mã dễ đọc hơn và giới hạn vòng đời thay đổi.

Lưu ý: Tôi thường thậm chí đi xa hơn một bước so với việc không sử dụng lại các biến và cố gắng thậm chí chỉ gán một giá trị một lần (nghĩa là không bao giờ thay đổi giá trị, làm cho nó không thay đổi). Đây là một ý tưởng chủ yếu từ các ngôn ngữ chức năng, nhưng tôi thấy nó có thể làm cho mã rõ ràng hơn nhiều. Tất nhiên, trong các ngôn ngữ phi chức năng, đôi khi bạn cần thay đổi một biến (ví dụ rõ ràng là biến vòng lặp), nhưng một khi bạn bắt đầu tìm kiếm, bạn sẽ thấy rằng trong hầu hết các trường hợp, biến "tươi" giúp dễ đọc và dễ đọc hơn mã dễ bị lỗi.


6

Tôi biết rằng bạn đang đọc từ một URL trong ví dụ của mình, nhưng nếu bạn đã thử điều tương tự với một tệp, bạn sẽ không thể đóng tệp vì phản hồi không còn trỏ đến tệp nữa, hiện tại nó đang giữ một sting mà bạn đã lấy từ tập tin.

Đó là mối nguy hiểm lớn, bạn có thể quên giá trị của nó vì nó thay đổi trong suốt vòng đời của chương trình hoặc mô-đun. Sẽ thật khó hiểu khi ai đó đọc mã của bạn bởi vì họ sẽ không bao giờ biết loại giá trị nào đang giữ.

Đây là những con bọ vui vẻ thử và bí.


4

Nói chung, tôi nói có, đó là phong cách xấu, nhưng có những trường hợp khi nó cần thiết và hữu ích để sử dụng lại một biến; Tôi chỉ khuyên bạn nên tránh sử dụng nó một cách giản dị, lười biếng.

Vấn đề với ví dụ của bạn không phải do gõ động mà vì bạn sử dụng cùng một biến để chỉ ba điều khác nhau. Mã này ít rõ ràng hơn đối với tôi bởi vì khi tôi đọc nó, tôi phải suy nghĩ nhiều hơn để tìm ra những gì responseđề cập đến.

Bạn có thể làm điều gì đó tương tự khó chịu trong một ngôn ngữ được gõ tĩnh như Java (với hạn chế là những thứ khác nhau có liên quan thông qua hệ thống phân cấp loại). Điểm mấu chốt là việc sử dụng một biến duy nhất để trỏ đến các đối tượng khác nhau có thể gây nhầm lẫn, bất kể hệ thống loại nào.


Điều này có vẻ như là một sự phản đối hợp lý và tôi nghĩ rằng tôi sẽ cố gắng loại bỏ kiểu này ra khỏi mã của mình. Theo dõi: làm thế nào bạn sẽ đặt tên cho các biến khác nhau mà về mặt khái niệm đề cập đến cùng một điều, nhưng với các loại khác nhau? Ký hiệu Hungarian là loại xấu xí, và trailing loại (giống như có response_addurlinfo, response_str, response_dict) là xấu xí vẫn còn. Bạn làm nghề gì?
Đánh dấu Amery

@MarkAmery Tôi nghĩ điều quan trọng là các biến không khái niệm đề cập đến cùng một điều. Đầu tiên chỉ là một số phản hồi của máy chủ có thể là một lỗi, thứ hai là một chuỗi văn bản có thể không hợp lệ và thứ ba là cấu trúc dữ liệu. Có nhiều ngữ nghĩa hơn là một phản hồi và một loại. Theo kinh nghiệm của tôi, đặt tên biến tốt là rất khó nhưng thường đáng giá. Xin lỗi tôi không thể cụ thể hơ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.