Есть ли способ получить (статический) метод для вызова при создании класса (не экземпляр)? - PullRequest
2 голосов
/ 19 октября 2011

еще раз, немного удивлен, что не нашел ответа на этот вопрос ...

Реальная причина моего вопроса: У меня есть словарь констант в классе

class MySQLConstants():

  DECIMAL = 0
  TINY = 1
  SHORT = 2
  LONG = 3
  FLOAT = 4
  DOUBLE = 5

  ... etc.

и я хочу словарь, чтобы я мог найти константу, если бы дал число ... достаточно просто:

fieldTypeDic = {}
for fieldType in dir( MySQLConstants ):
   value = getattr( MySQLConstants, fieldType )
   fieldTypeDic[ value ] = fieldType

... было бы достаточно легко сделать этот метод @static для MySQLConstants и вызвать его, выполнив MySQLConstants.createDic () после выполнения оператора определения класса ... но мне просто интересно, есть ли какой-нибудь способ заставить метод, неизбежно @static, запускаться при создании класса (NB, я не говорю о создании экземпляра этого класса!) ...

Ответы [ 4 ]

3 голосов
/ 19 октября 2011

Вот решение, которое использует метакласс:

class ConstantDictMeta(type):
    def __new__(cls, name, bases, dct):
        fieldTypeDic = dict((v, k) for k, v in dct.items() if k.isupper())
        dct["fieldTypeDic"] = fieldTypeDic
        return type.__new__(cls, name, bases, dct)

class MySQLConstants():
    __metaclass__ = ConstantDictMeta
    DECIMAL = 0
    TINY = 1
    SHORT = 2
    LONG = 3
    FLOAT = 4
    DOUBLE = 5

>>> MySQLConstants.fieldTypeDic
{0: 'DECIMAL', 1: 'TINY', 2: 'SHORT', 3: 'LONG', 4: 'FLOAT', 5: 'DOUBLE'}
2 голосов
/ 20 октября 2011

на самом деле это было намного проще, чем использование метакласса, и никакой "метод класса" не нужен:

class MySQLConstants():
  DECIMAL = 0
  TINY = 1
  SHORT = 2
  LONG = 3
  FLOAT = 4
  DOUBLE = 5

  def create_dict( dicForReversing ):
    fieldTypeDic = {}
    for key, value in dicForReversing.items():
      if isinstance(value, int):
        fieldTypeDic[ value ] = key
    return fieldTypeDic
  fieldTypeDic = create_dict( vars() )

, но, в частности, спасибо Этану Фурману за то, что он показал, что можно сделатьпроизойдет во время создания класса

NB, если вы предполагаете иметь несколько значений для ваших ключей (это имеет место с константами MySQLdb), лучший способ справиться с этим может быть следующим

ENUM = 247

CHAR = TINY
INTERVAL = ENUM  

def create_dict( dicForReversing ):
  fieldTypeDic = {}
  for key, value in dicForReversing.items():
    if isinstance(value, int):
      if not value in fieldTypeDic: 
        fieldTypeDic[ value ] = set()
      fieldTypeDic[ value ].add( key )
  return fieldTypeDic
fieldTypeDic = create_dict( vars() )
1 голос
/ 19 октября 2011

Чтобы ответить на вопрос напрямую, да:

class MySQLConstants():

    DECIMAL = 0
    TINY = 1
    SHORT = 2
    LONG = 3
    FLOAT = 4
    DOUBLE = 5

    def create_dict(cls):
        fieldTypeDic = {}
        if not isinstance(cls, dict):
            cls = cls.__dict__
        for key, value in cls.items():
            if isinstance(value, int):
                fieldTypeDic[ value ] = key
        cls['fieldTypeDic'] = fieldTypeDic
    create_dict(vars())
    create_dict = classmethod(create_dict)

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

Если это метод однократного использования, я бы предпочел сделать следующее:

class MySQLConstants():
    lookup = {}
    local = vars()
    for i, name in enumerate('DECIMAL TINY SHORT LONG FLOAT DOUBLE'.split()):
        local[name] = i
        lookup[i] = name
    del local, i, name

При этом создаются все имена и создается словарь обратного просмотра в одном удобном пакете.

1 голос
/ 19 октября 2011

Вы можете создать метакласс, который добавляет поведение при создании класса, но ваш сценарий использования достаточно прост, чтобы просто извлечь словарь напрямую, когда вам это нужно:

>>> class MySQLConstants:
  DECIMAL = 0
  TINY = 1
  SHORT = 2
  LONG = 3
  FLOAT = 4
  DOUBLE = 5

>>> vars(MySQLConstants)
{'__module__': '__main__', 'SHORT': 2, 'DOUBLE': 5, 'DECIMAL': 0, 'FLOAT': 4, 'LONG': 3, 'TINY': 1, '__doc__': None}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...