2016-10-13 2 views
3

Что такое pythonic Способ рассказать вызывающей функции, какие значения поддерживает данный параметр?Pythonic way about Enums

Он является примером для PyQt (для GUI). Скажем, у меня есть флажок,

class checkbox(object): 
    .... 
    def setCheckState(self, value): 
     .... 

Здесь setCheckState() следует ожидать только проверил или бесконтрольно.

PyQt использует встроенное перечисление (т. Е. Qt.Checked или Qt.Unchecked), но это ужасно. Я постоянно в документации, ищущей перечисление для объекта, с которым я работаю.

Очевидно, PyQt написан в unpythonic C++ sytle. Как должен эту или аналогичную проблему обрабатывать в Python? Согласно PEP 435, перечисления, похоже, являются недавним дополнением к языку и для очень конкретных приложений, поэтому я бы предположил, что есть/был лучший способ справиться с этим?

Я хочу, чтобы код, который я пишу, прост в использовании, когда мои функции требуют определенных значений параметров - почти как функция combobox для функций.

+0

Enums были введены именно потому, что каждый использовал свою собственную взломанную замену. Если вы хотите перечислить, используйте перечисление.Если у вас есть только два состояния, рассмотрите использование логического значения: 'def setCheckState (self, checked = True):'. – MisterMiyagi

+0

Противники с инвертированием могут утверждать, что должны быть три отдельные функции, которые не принимают вместо аргумента * any *: 'checkbox.set_checked()', 'checkbox.set_unchecked()' и 'checkbox.toggle() '. – chepner

+0

Я предполагаю, что это больше основано на мнениях, чем я думал, я надеялся, что, как и большинство вещей на Python, для этого будет правильный путь. –

ответ

1

Один очевидный способ - это аннотации функций.

class CheckBox(enum.Enum): 
    Off = 0 
    On = 1 

def setCheckState(self, value: CheckBox): 
    ... 

Это говорит совершенно ясно, что value должен быть экземпляром CheckBox. Наличие Enum просто делает это немного проще.

Аннотации непосредственно не поддерживаются в 2.7. Общие обходные пути включают размещение этой информации в строке функции doc (где различные инструменты могут ее найти) или в комментариях (как мы уже знали).

Если вы ищете метод для своего собственного кода: используйте аннотирующий декоратор. Это имеет преимущество, продолжая работать в 3+:

class annotate(object): 
    def __init__(self, **kwds): 
     self.kwds = kwds 
    def __call__(self, func): 
     func.__annotations__ = self.kwds 

@annotate(value=CheckBox) 
def setCheckState(self, value): 
    ... 

Чтобы быть надежным декоратор он должен проверить, что содержимое kwds соответствует именам параметров функции.

+0

Функциональные аннотации недоступны в Python 2.7. – chepner

+0

Это объясняет, почему я не слышал о них раньше. –

+0

А, я пропустил тег 2.7, извините. –

0

Это будет делать трюк

import collections 

def create_enum(container, start_num, *enum_words): 
    return collections.namedtuple(container, enum_words)(*range(start_num, start_num + len(enum_words))) 

Switch = create_enum('enums', 1, 'On', 'Off') 

переключателя Ваше перечисление:

In [20]: Switch.On 
Out[20]: 1 

In [21]: Switch.Off 
Out[21]: 2 

ОК, я получил ошибку моего пути - я перепутал представление со значением.

Тем не менее, если вы хотите перечислить больший диапазон - в моем подделке вам не нужно добавлять значения вручную. Конечно, если у вас есть последовательные номера.

И я ненавижу дополнительное набрав :-)

+0

Теперь у Python есть 'Enum', нет необходимости создавать поддельные. –

+0

@ EthanFurman, к сожалению, значения Switch.Off и Включить, созданные с перечислением, не являются 0 и 1 - они являются типами, и вам нужно дополнительно разыменовать, чтобы получить 0 и 1. – volcano

+1

Не, если вы используете 'enum.IntEnum'. –