2016-09-12 15 views
6

Tôi có một số lượng lớn các lớp học tự động tạo ra trong python rằng về cơ bản đại diện cho sự đếm cho một phần của một giao thức truyền thông, họ trông như vậyBạn có thể tự động thêm các biến lớp vào python phân lớp không?

# definitions.py 

class StatusCodes(ParamEnum): 
    Success = 1 
    Error = 2 
    UnexpectedAlpaca = 3 

class AlpacaType(ParamEnum): 
    Fuzzy = 0 
    ReallyMean = 1 

# etc etc etc 

Xác định mọi thứ theo cách này làm cho nó dễ dàng cho các tính năng tự động phát điện và cũng để con người sửa đổi. Lớp ParamEnum cung cấp tất cả chức năng, nhận/cài đặt, so sánh, chuyển đổi và tạo từ dữ liệu mạng đến và vv.

Tuy nhiên, các lớp này yêu cầu thêm một số siêu dữ liệu. Tôi không muốn để thêm video này vào định nghĩa nguồn gốc của mỗi lớp mặc dù, vì nó làm cho nó ít có thể đọc được và sẽ phá vỡ autogenerator

Hiện nay tôi đang làm nó như thế này

# param_enum.py 

class ParamEnum(object): 
    def __init__(self): 
     self.__class__._metadata = get_class_metadata(self.__class__) 
tuy nhiên

điều này sẽ xảy ra mỗi khi chúng tôi khởi tạo một trong những Enums này (điều này thường xảy ra), không chỉ trên định nghĩa (siêu dữ liệu không thay đổi, vì vậy nó chỉ cần được đặt một lần)

I đã cố thêm phần này vào cuối tệp định nghĩa nhưng gặp sự cố có quá.

class StatusCodes(ParamEnum): 
    Success = 1 
    Error = 2 
    UnexpectedAlpaca = 3 

for var in locals(): # or globals? 
    add_metadata(var) 
    #doesn't work because it is in the same file, modifying dict while iteratng 

Có cách nào trong python ghi đè/thêm chức năng khi lớp được xác định, có thể được kế thừa cho lớp con không? Lý tưởng nhất là tôi muốn một cái gì đó giống như

class ParamEnum(object): 
    def __when_class_defined__(cls): 
     add_metadata(cls) 
+1

Trong Python, các lớp là trường hợp của Metaclass. Đó là, bạn có thể đạt được điều này bằng cách cho ParamEnum của bạn một Metaclass ghi đè '__new__'. – Phillip

Trả lời

5

Sử dụng trang trí lớp

def add_metadata(cls): 
    cls._metadata = get_class_metadata(cls) 
    return cls 

@add_metadata 
class StatusCodes(ParamEnum): 
    Success = 1 
    Error = 2 
    UnexpectedAlpaca = 3 

Những gì bạn muốn làm là trên thực tế động lực rất có trang trí: Các sửa đổi của một lớp hoặc chức năng sau khi nó có đã được tạo.

Nếu bạn không quen thuộc với trang trí, vui lòng đọc this (mặc dù nó hơi dài).

Bạn cũng có thể sử dụng metaclasses, nhưng chúng giới thiệu phức tạp hơn một trang trí. Nếu bạn muốn tránh đường trang trí bổ sung @add_metadata và bạn cho rằng đó là dự phòng đối với lớp con được chỉ định ParamEnum, bạn cũng có thể thực hiện _metadataa descriptor với đánh giá lười biếng trong lớp cơ sở ParamEnum.

class MetadataDescriptor(object): 
    def __get__(self, obj, cls): 
     if cls._metadata_value is None: 
      cls._metadata_value = get_class_metadata(cls) 
     return cls._metadata_value 

class ParamEnum(object): 
    _metadata_value = None 
    _metadata = MetadataDescriptor() 
+0

Tôi nghĩ rằng một bộ mô tả là tốt hơn so với trang trí. –

+0

@AlbertLee Tôi cũng nghĩ rằng, mô tả là thanh lịch hơn. Tuy nhiên, chúng là "ma thuật" khá tiên tiến, có thể là một chướng ngại vật tùy thuộc vào người duy trì mã. –

+0

Đã đi với bộ mô tả, hoạt động khá độc đáo và giữ cho tệp tự động của tôi được sạch sẽ. Cảm ơn! –

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