2013-04-30 34 views
7

Tôi đang cố gắng viết một "lớp enum" trong python. Một sự phiền toái nhỏ mà tôi hiện đang gặp là không có khả năng xác định các giá trị enum bên trong lớp enum. Đó là, tôi có thể làm điều này:Python 2.x - tạo thể hiện tĩnh của lớp trong cùng một lớp

class Fruit: 
    def __init__(self, name): 
     self.name = name 

class Fruits(Enum): 
    Apple = Fruit("apple") 

Nhưng tôi muốn làm điều này, hoặc tương đương rõ ràng tương tự:

class Fruit(Enum): 
    def __init__(self, name): 
     self.name = name 

    Apple = Fruit("apple") 

Thật không may, tôi nhận được lỗi sau: tên 'trái cây' không được xác định

Quy tắc hiển thị trong trường hợp này là gì? Có bất kỳ thủ thuật Python ít được biết đến có thể giúp tôi không? Tôi muốn một cái gì đó có thể viết trong metaclass của Enum, vì điều đó sẽ làm cho việc sử dụng ít cồng kềnh hơn cho người dùng.

+1

Các metaclass cho Enum không được hiển thị, vì tôi nghĩ nó khá thích hợp. – Liosan

+0

đó là bởi vì 'lớp' chưa hoàn thành được xác định cho đến khi bạn đạt đến cuối khối của nó – jamylak

+1

Sau khi định nghĩa lớp, bạn có thể làm một' Fruit.Apple = Fruit ("apple") 'để tạo một thể hiện và lưu trữ nó như là một thuộc tính lớp. – martineau

Trả lời

1

Bạn có thể làm một metaclass rằng đã làm một cái gì đó đơn giản như thế này:

class MetaEnum(type): 
    def __new__(cls, class_name, parents, attrs): 
     def __init__(self, name=None): 
      if name is not None: self.name = name 
     attrs['__init__'] = __init__ 
     Klass = type.__new__(cls, class_name, parents, attrs) 
     if 'instances' in attrs: 
      for name in attrs['instances']: 
       setattr(Klass, name.capitalize(), Klass(name)) 
      del Klass.instances # clean up 
     return Klass 

class Fruit(object): 
    __metaclass__ = MetaEnum 
    instances = ('apple', 'banana', 'cranberry') 

for attr_name in dir(Fruit): 
    if not attr_name.startswith('_'): 
     attr = getattr(Fruit, attr_name) 
     if type(attr) is Fruit: 
      print('Fruit.{}, is a Fruit named {}'.format(attr_name, getattr(attr, 'name'))) 
     else: 
      print('Fruit.{}, is a {}'.format(attr, type(attr))) 

Output:

Fruit.Apple, is a Fruit named apple 
Fruit.Banana, is a Fruit named banana 
Fruit.Cranberry, is a Fruit named cranberry 
+0

Không tệ, nếu tôi đọc nó một cách chính xác nó làm những gì tôi muốn. Tôi không nghĩ về con đường này. Đáng tiếc về cú pháp, tôi sẽ làm việc trên nó một chút ... Chắc chắn +1. – Liosan

+0

Bạn muốn các phiên bản? OK, xem câu trả lời cập nhật của tôi cho câu hỏi được cập nhật của bạn. – martineau

+0

Re: cú pháp, nếu bạn xác định '__metaclass__ = MetaEnum' ở cấp mô-đun toàn cầu, nó sẽ trở thành mặc định và áp dụng cho bất kỳ định nghĩa lớp nào theo sau (không chỉ định riêng của chúng). – martineau