Giả sử chúng ta có hệ thống phân cấp lớp sau đây:Có cách nào để truy cập __dict__ (hoặc một cái gì đó giống như nó) bao gồm các lớp cơ sở?
class ClassA:
@property
def foo(self): return "hello"
class ClassB(ClassA):
@property
def bar(self): return "world"
Nếu tôi khám phá __ dict __ trên ClassB như vậy, tôi chỉ nhìn thấy các thuộc tính thanh:
for name,_ in ClassB.__dict__.items():
if name.startswith("__"):
continue
print(name)
Output là thanh
Tôi có thể cuộn phương tiện của riêng mình để nhận các thuộc tính không chỉ về loại được chỉ định mà còn là tổ tiên của nó. Tuy nhiên, câu hỏi của tôi là liệu đã có một cách trong python cho tôi để làm điều này mà không tái phát minh ra một bánh xe.
def return_attributes_including_inherited(type):
results = []
return_attributes_including_inherited_helper(type,results)
return results
def return_attributes_including_inherited_helper(type,attributes):
for name,attribute_as_object in type.__dict__.items():
if name.startswith("__"):
continue
attributes.append(name)
for base_type in type.__bases__:
return_attributes_including_inherited_helper(base_type,attributes)
Chạy mã của tôi như sau ...
for attribute_name in return_attributes_including_inherited(ClassB):
print(attribute_name)
... cho lại cả quầy bar và foo. Lưu ý rằng tôi đang đơn giản hoá một số thứ: va chạm tên, sử dụng các mục() khi cho ví dụ này tôi có thể sử dụng dict, bỏ qua bất kỳ thứ gì bắt đầu bằng __, bỏ qua khả năng hai tổ tiên có tổ tiên chung, v.v. .
EDIT1 - Tôi đã cố giữ ví dụ đơn giản. Nhưng tôi thực sự muốn cả tên thuộc tính và tham chiếu thuộc tính cho mỗi lớp và lớp tổ tiên. Một trong những câu trả lời dưới đây có tôi theo dõi tốt hơn, tôi sẽ đăng một số mã tốt hơn khi tôi làm cho nó hoạt động.
EDIT2 - Điều này làm những gì tôi muốn và rất ngắn gọn. Nó dựa trên câu trả lời của Eli dưới đây.
def get_attributes(type):
attributes = set(type.__dict__.items())
for type in type.__mro__:
attributes.update(type.__dict__.items())
return attributes
Nó cung cấp cả tên thuộc tính và tham chiếu của chúng.
EDIT3 - Một trong các câu trả lời bên dưới được đề xuất sử dụng inspect.getmembers. Điều này xuất hiện rất hữu ích bởi vì nó giống như dict chỉ nó hoạt động trên các lớp tổ tiên là tốt.
Kể từ khi một phần lớn của những gì tôi đang cố gắng làm là tìm các thuộc tính được đánh dấu bằng một mô tả đặc biệt, và bao gồm các lớp tổ tiên, đây là một số mã mà có thể giúp làm điều đó trong trường hợp nó giúp mọi người:
class MyCustomDescriptor:
# This is greatly oversimplified
def __init__(self,foo,bar):
self._foo = foo
self._bar = bar
pass
def __call__(self,decorated_function):
return self
def __get__(self,instance,type):
if not instance:
return self
return 10
class ClassA:
@property
def foo(self): return "hello"
@MyCustomDescriptor(foo="a",bar="b")
def bar(self): pass
@MyCustomDescriptor(foo="c",bar="d")
def baz(self): pass
class ClassB(ClassA):
@property
def something_we_dont_care_about(self): return "world"
@MyCustomDescriptor(foo="e",bar="f")
def blah(self): pass
# This will get attributes on the specified type (class) that are of matching_attribute_type. It just returns the attributes themselves, not their names.
def get_attributes_of_matching_type(type,matching_attribute_type):
return_value = []
for member in inspect.getmembers(type):
member_name = member[0]
member_instance = member[1]
if isinstance(member_instance,matching_attribute_type):
return_value.append(member_instance)
return return_value
# This will return a dictionary of name & instance of attributes on type that are of matching_attribute_type (useful when you're looking for attributes marked with a particular descriptor)
def get_attribute_name_and_instance_of_matching_type(type,matching_attribute_type):
return_value = {}
for member in inspect.getmembers(ClassB):
member_name = member[0]
member_instance = member[1]
if isinstance(member_instance,matching_attribute_type):
return_value[member_name] = member_instance
return return_value
Chính xác bạn sẽ làm gì với danh sách thuộc tính khi bạn có nó? –
Các lớp được đề cập đại diện cho các thư đã được deserialized. Các tin nhắn sử dụng thừa kế khi chúng chia sẻ các trường. Có một phương thức cần in thông tin về từng trường của từng thư. Mỗi thuộc tính của các lớp thông điệp này thực sự được đánh dấu bằng bộ mô tả nhưng tôi đã để lại chi tiết đó vì tôi nghĩ nó không liên quan. –
... Vì vậy, hãy cập nhật bộ mô tả để nó thêm thuộc tính được mô tả vào danh sách? Hoặc - và điều này có thể là một chút quá cấp tiến - sử dụng một dict với các phím chuỗi thay vì các thuộc tính riêng biệt? –