2010-09-20 33 views
22

Tôi đã xác định lớp Vector có ba biến thuộc tính: x, yz. Tọa phải số thực, nhưng không có gì để ngăn chặn một từ cách làm như sau là:Nhập an toàn bằng Python

>>> v = Vector(8, 7.3, -1) 
>>> v.x = "foo" 
>>> v.x 
"foo" 

tôi có thể thực hiện "an toàn kiểu" như thế này:

import numbers 

class Vector: 
    def __init__(self, x, y, z): 
     self.setposition(x, y, z) 

    def setposition(self, x, y, z): 
     for i in (x, y, z): 
      if not isinstance(i, numbers.Real): 
       raise TypeError("Real coordinates only") 

     self.__x = x 
     self.__y = y 
     self.__z = z 

    @property 
    def x(self): 
     return self.__x 

    @property 
    def y(self): 
     return self.__y 

    @property 
    def z(self): 
     return self.__z 

... nhưng điều đó dường un- Pythonic.

Đề xuất?

+0

Nhưng tại sao? Số nguyên hoàn toàn hoạt động. –

+0

Tôi hiểu loại mối quan tâm này thường xuất hiện với các dự án/nhóm lớn. Nếu typesafety là thứ bạn cảm thấy mạnh mẽ thì tôi khuyên bạn nên xem xét scala thay thế. – BlueSky

Trả lời

17

Bạn phải tự hỏi tại sao bạn muốn kiểm tra loại khi đặt các giá trị này. Chỉ cần tăng một số TypeError trong bất kỳ phép tính nào xảy ra để vấp phải sai số giá trị sai. Tiền thưởng: các hoạt động chuẩn đã làm điều này.

>>> 3.0/'abc' 
Traceback (most recent call last): 
    File "<stdin>", line 1, in ? 
TypeError: unsupported operand type(s) for /: 'float' and 'str' 
+2

Và sau đó viết một tập hợp toàn diện các bài kiểm tra đơn vị thực hiện tất cả các nhánh của mã của bạn, để bắt TypeErrors của bạn trước khi người dùng của bạn làm. Đúng? Dù sao, liên quan đến khi nào lỗi nên được ném: nếu bạn biết rằng một kết hợp nhất định không hợp lệ và sẽ gây ra vấn đề, nó sẽ không được tốt hơn/rõ ràng hơn để thất bại càng sớm càng tốt? Không sớm làm cho việc tìm kiếm vấn đề gốc dễ dàng hơn nhiều? (Tôi cho rằng "tại sao nó không hợp lệ" là ít rõ ràng hơn, mặc dù.) –

+1

Tôi nghĩ rằng câu hỏi là về LBYL vs EAFP, do đó, trong một "pythonic" cách nó có ý nghĩa để không chỉ "cho phép" cho các loại bạn ban đầu dự định . Đối với một kết quả "được biết xấu", nó có ý nghĩa hoàn hảo để cắt đường dẫn thực hiện của nó (nâng cao). – knitti

4

Nhưng không có gì để ngăn chặn một từ cách làm như sau là:

Tôi tin rằng cố gắng để ngăn người khác làm điều gì đó như thế là un-Pythonic. Nếu bạn phải, thì bạn nên kiểm tra loại an toàn trong thời gian bất kỳ hoạt động nào bạn có thể thực hiện bằng cách sử dụng Vector, theo ý kiến ​​của tôi.

Để báo G.V.R:

chúng ta đều trưởng thành.

. Xem số question và câu trả lời của nó để biết thêm thông tin.

Tôi chắc rằng Pythonistas có kinh nghiệm hơn ở đây có thể cung cấp cho bạn câu trả lời tốt hơn.

12

Duck Typing là cách thông thường trong Python. Nó phải làm việc với bất kỳ điều gì mà cư xử giống như một số, nhưng không nhất thiết phải một số thực.

Trong hầu hết các trường hợp trong Python, không nên kiểm tra rõ ràng các loại. Bạn có được sự linh hoạt bởi vì mã của bạn có thể được sử dụng với các kiểu dữ liệu tùy chỉnh, miễn là chúng hoạt động chính xác.

4

Các câu trả lời khác đã chỉ ra rằng không có ý nghĩa gì khi kiểm tra loại ở đây. Hơn nữa, lớp học của bạn sẽ không nhanh nếu nó được viết bằng Python thuần túy.

Nếu bạn muốn có một giải pháp pythonic hơn - bạn có thể sử dụng setters tài sản như:

@x.setter 
def x(self, value): 
    assert isinstance(value, numbers.Real) 
    self.__x = value 

Tuyên bố khẳng định sẽ bị gỡ bỏ khi bạn vô hiệu hóa hoặc gỡ lỗi kích hoạt chế độ tối ưu hóa.

Cách khác, bạn có thể buộc value vào dấu phẩy động trong trình cài đặt.Điều đó sẽ làm tăng ngoại lệ nếu loại/giá trị không thể chuyển đổi:

@x.setter 
def x(self, value): 
    self.__x = float(value) 
2

Bạn không được phép cung cấp loại an toàn theo cách này. Có, ai đó có thể cố tình phá vỡ mã của bạn bằng cách cung cấp các giá trị mà vùng chứa của bạn sẽ không hoạt động - nhưng điều này chỉ giống với các ngôn ngữ khác. Và ngay cả khi ai đó đặt giá trị đúng cho tham số vào hàm hoặc hàm thành viên không nhất thiết có nghĩa là nó không bị hỏng: Nếu chương trình mong đợi địa chỉ IP, nhưng bạn chuyển tên máy chủ, nó vẫn không hoạt động, mặc dù cả hai có thể dây.

Điều tôi đang nói là: Tư duy của Python vốn đã khác biệt. Kiểu gõ vịt về cơ bản nói: Này, tôi không bị giới hạn ở một số kiểu nhất định, mà là giao diện, hoặc hành vi của các đối tượng. Nếu một vật thể hành động như thể đó là loại đối tượng tôi mong đợi, tôi không quan tâm - chỉ cần đi cho nó.

Nếu bạn cố gắng giới thiệu kiểm tra kiểu, về cơ bản bạn giới hạn một trong những tính năng hữu ích nhất của ngôn ngữ.

Điều đó đang được nói, bạn thực sự cần phải tham gia vào thử nghiệm phát triển theo định hướng hoặc kiểm tra đơn vị ít nhất. Có thực sự là không có lý do gì để không làm điều đó với ngôn ngữ động - nó chỉ di chuyển cách (loại) lỗi đang được phát hiện đến một bước khác trong quá trình xây dựng, từ thời gian biên dịch để chạy một bộ kiểm tra nhiều lần một ngày. Mặc dù điều này có vẻ như thêm nỗ lực, nhưng nó thực sự sẽ giảm thời gian để gỡ lỗi và sửa mã, vì đó là một cách mạnh mẽ hơn để phát hiện lỗi trong mã của bạn.

Nhưng đủ rồi, tôi đã rambling.

+0

Mặc dù "giao diện" là một chút nhầm lẫn ở đây, vì không có giao diện nào được xác định rõ ràng (ngoại trừ hy vọng trong các nhận xét). Nhập liệu có nghĩa là bạn đã thực sự xem xét hoặc chạy mã để xem giao diện là gì. Trong kinh nghiệm của tôi (giới hạn) trong Python, đây là nhược điểm lớn nhất đối với việc gõ vịt. Viết mã của riêng tôi nhanh hơn, nhưng việc sử dụng API không có giấy tờ của người khác (ví dụ: viết một plugin) khó hơn nhiều, vì vậy nhận xét trở nên quan trọng hơn. –

+1

Các bài kiểm tra đơn vị là rất tốt, nhưng bước qua các bài kiểm tra trong trình gỡ rối không phải là cách tối ưu nhất để tìm hiểu loại vịt nào mà mỗi phương thức được mong đợi được truyền - nghĩa là cách sử dụng API đúng cách. Và thật khó để đảm bảo rằng bài kiểm tra đơn vị của bạn luôn bao gồm mọi trường hợp cạnh. –

Các vấn đề liên quan