2011-07-31 36 views
8

Tôi đang triển khai một lớp đơn giản để biểu diễn vectơ 2D. Dưới đây là các bước của liên quan:Lỗi lạ của Python: đối tượng "LoạiError: 'NoneType' không thể gọi"

class Vector: 
    def __init__(self, x, y): 
    self.vec_repr = x, y 

    def __add__(self, other): 
    new_x = self.x + other.x 
    new_y = self.y + other.y 
    return Vector(new_x, new_y) 

    def __getattr__(self, name): 
    if name == "x": 
     return self.vec_repr[0] 
    elif name == "y": 
     return self.vec_repr[1] 

Sau đó, tôi có một cái gì đó như:

a = Vector(1, 1) 
b = Vector(2, 2) 
a + b 

tôi nhận được TypeError: 'NoneType' object is not callable. Điều này đặc biệt lạ vì lỗi không được đánh dấu là đang ở trên bất kỳ dòng cụ thể nào, vì vậy tôi không biết phải tìm đâu!

Rất lạ, vì vậy tôi đã thực hiện một số thử nghiệm và phát hiện ra rằng nó xảy ra trên dòng a+b. Ngoài ra, khi tôi làm lại lớp học như sau:

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

    def __add__(self, other): 
    new_x = self.x + other.x 
    new_y = self.y + other.y 
    return Vector(new_x, new_y) 

Lỗi này biến mất!

Tôi thấy rằng có rất nhiều câu hỏi về một lỗi tương tự như vậy - tất cả dường như liên quan đến một số tên hàm bị ghi đè ở đâu đó bởi một biến, nhưng tôi không thấy nơi này đang xảy ra!

Là đầu mối khác, khi tôi thay đổi kiểu trả về mặc định của __getattr__() đến cái gì khác - str, ví dụ - các lỗi biến thành TypeError: 'str' object is not callable

Bất kỳ ý tưởng như những gì đang xảy ra? Có một số hành vi của __getattr__() mà tôi không hiểu không?

Trả lời

11

Vấn đề là __getattr__ của bạn không trả lại bất kỳ điều gì cho các thuộc tính khác ngoài xy và không tăng AttributeError. Do đó khi phương pháp __add__ được tra cứu, __getattr__ trả về None và do đó lỗi của bạn.

Bạn có thể sửa lỗi này bằng cách đặt __getattr__ giá trị trả về cho các thuộc tính khác. Trong thực tế, bạn phải đảm bảo rằng __getattr__ gọi phương thức từ lớp cha của nó cho tất cả các thuộc tính không được xử lý. Nhưng thực sự __getattr__ là điều sai để sử dụng ở đây. Nó nên được sử dụng một cách tiết kiệm, và khi không rõ ràng hơn, các giải pháp mức cao hơn có sẵn. Ví dụ: __getattr__ là điều cần thiết cho công văn động. Nhưng trong trường hợp của bạn, các giá trị xy được biết rõ và được xác định rõ trước khi mã chạy.

Các giải pháp đúng là làm cho xy tài sản và không thực hiện __getattr__ ở tất cả.

@property 
def x(self): 
    return self.vec_repr[0] 

@property 
def y(self): 
    return self.vec_repr[1] 
+0

và chỉ dành riêng cho các bức tranh hoàn chỉnh, nó cố gắng gọi '__coerce__' –

+0

@yi_H Tôi không quen thuộc với '__coerce__', nhưng tôi có thể đoán những gì nó sẽ làm gì, và tại sao nó sẽ được gọi là! –

+0

Ooh. Ồ cảm ơn nhé. Tôi nghĩ rằng nó rơi trở lại trên __getattr __() khi nó không tìm thấy thuộc tính ở nơi khác. Vâng, điều này cực kỳ lúng túng. – Slubb

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