Thuộc tính là biến được tra cứu trên một đối tượng khác sử dụng cú pháp dấu chấm: obj.attribute
. Cách Python được thiết kế, tra cứu thuộc tính có thể làm nhiều thứ, và sự đa dạng đôi khi có thể dẫn đến lỗi nếu bạn không thực sự hiểu những gì đang xảy ra (đây là tài liệu bạn liên kết cảnh báo).
Vấn đề cơ bản nhất là tra cứu thuộc tính có thể tìm thấy giá trị được lưu trữ trong từ điển thể hiện của đối tượng hoặc có thể tìm thấy thứ gì đó từ lớp của đối tượng (hoặc lớp cơ sở, nếu có thừa kế). Các phương thức là các hàm được lưu trữ trong lớp, nhưng bạn thường sử dụng chúng bằng cách tìm kiếm chúng trên một cá thể (mà "liên kết" phương thức, chèn đối tượng làm arguemnt đầu tiên khi phương thức được gọi).
Trình tự chính xác của những gì được kiểm tra khi phức tạp một chút (tôi mô tả quá trình đầy đủ trong an answer to another question), nhưng ở cấp độ cơ bản nhất, các thuộc tính cá thể thường được ưu tiên hơn thuộc tính lớp.
Nếu một thuộc tính thể hiện và thuộc tính lớp có cùng tên tồn tại, thường chỉ có thuộc tính thể hiện mới có thể truy cập được. Điều này có thể rất khó hiểu nếu nó là vô ý.
Xét đoạn mã sau:
class Foo(object):
def __init__(self, lst):
self.lst = lst
def sum(self):
self.sum = sum(self.lst)
return self.sum
f = Foo([1,2,3])
print(f.sum())
print(f.sum())
Ở dưới cùng của mã này, chúng ta thực hiện hai cuộc gọi giống hệt nhau. Việc đầu tiên hoạt động tốt, nhưng thứ hai sẽ tăng một ngoại lệ.
Điều này là do lần đầu tiên chúng tôi tra cứu f.sum
chúng tôi tìm thấy phương thức trong lớp Foo
. Chúng ta có thể gọi phương thức mà không có vấn đề gì. Sự cố xuất phát từ thực tế là phương pháp sum
gán kết quả tính toán của nó (tổng của các phần tử trong self.lst
) vào một thuộc tính thể hiện cũng có tên là sum
. Điều này ẩn phương thức sum
từ chế độ xem.
Khi giây thứ hai f.sum()
gọi tra cứu f.sum
, nó tìm thuộc tính thể hiện, chứa số nguyên 6
, thay vì phương thức dự kiến. Một số nguyên không thể gọi được, vì vậy chúng tôi có ngoại lệ.
Giải pháp, tất nhiên, không được sử dụng cùng tên cho phương pháp và thuộc tính. Đoạn mã trên là một ví dụ khá tầm thường. Các lỗi gây ra bởi loại điều này trong mã phức tạp hơn có thể khó khăn hơn nhiều để tìm ra.
Nếu bạn đang viết mã để thêm thuộc tính vào đối tượng bạn không biết nhiều, bạn nên cẩn thận để tránh các tên thông thường. Nếu bạn đang viết một lớp mixin, hãy xem xét sử dụng hai dấu gạch dưới hàng đầu trong tên thuộc tính để kích hoạt tên mangling của Python, được thiết kế cho chính xác loại tình huống này.
Giải thích của bạn khá đơn giản. Vì vậy, nhìn tôi rằng tài liệu tôi đã liên kết muốn có nghĩa là 'data attribute' = 'instance attribute', 'method attribute' = 'class attribute'. Nếu tôi sai, hãy sửa tôi. –
Vâng, đúng vậy. Tôi nghĩ rằng tài liệu có thể khá cũ và không hoàn toàn cập nhật. Chắc chắn, "thuộc tính dụ" và "thuộc tính lớp" là các thuật ngữ phổ biến hơn trong những ngày này. Nó cũng đáng chú ý rằng tình hình thực tế là một chút phức tạp hơn tôi đã trình bày ở đây. Một số loại thuộc tính lớp (ví dụ: các đối tượng 'thuộc tính') sẽ được ưu tiên hơn các thuộc tính mẫu. Tuy nhiên, bạn sẽ không gặp phải tình huống đó do nhầm lẫn. – Blckknght