2010-01-06 3 views
1

У меня есть объект, который содержит множество идентификаторов, к которым обращаются статически. Я хочу разбить это на другой объект, который содержит только те идентификаторы без необходимости внесения изменений в уже существующую базу кода. Возьму, к примеру:Загрязнение среды класса

class _CarType(object): 
    DIESEL_CAR_ENGINE = 0 
    GAS_CAR_ENGINE = 1 # lots of these ids 

class Car(object): 
    types = _CarType 

Я хочу, чтобы иметь возможность получить доступ к _CarType.DIESEL_CAR_ENGINE либо по телефону Car.types.DIESEL_CAR_ENGINE, либо Car.DIESEL_CAR_ENGINE для обратной совместимости с существующим кодом. Понятно, что я не могу использовать __getattr__, так что я пытаюсь найти способ сделать эту работу

+0

Почему вы не можете использовать '__getattr__'? Похоже, это самое простое решение. (проверка на isupper и do 'getattr (_CarType, key)') – kibitzer

ответ

3

Нечто подобное (может быть, метаклассами?):

class Car(object): 
    for attr, value in _CarType.__dict__.items(): 
     it not attr.startswith('_'): 
      locals()[attr] = value 
    del attr, value 

Или вы можете сделать это из декларации класса:

class Car(object): 
    # snip 

for attr, value in _CarType.__dict__.items(): 
    it not attr.startswith('_'): 
     setattr(Car, attr, value) 
del attr, value 
+0

Работает очень хорошо, но я ищу более элегантное решение. Если ничего не выйдет, вы победителю! Большое спасибо. – hyperboreean

+1

Вы не должны изменять 'locals()': http://docs.python.org/library/functions.html#locals – 2010-01-06 12:34:51

+1

Это использование setattr - это самое элегантное и простое решение, которое вы собираетесь получить. – 2010-01-06 12:37:06

4

Хотя это не совсем то, что подклассы сделано для, он выполняет то, что вы описали:

class _CarType(object): 
    DIESEL_CAR_ENGINE = 0 
    GAS_CAR_ENGINE = 1 # lots of these ids 

class Car(_CarType): 
    types = _CarType 
+0

Thnaks balpha для вашего ответа, но я не предпочитаю этого, потому что забыл упомянуть, что Car будет подклассифицировать другой класс, и я не очень люблю множественное наследование. Но это хорошая идея, тем не менее! – hyperboreean

+1

Множественное наследование не должно создавать проблемы в этом случае - до тех пор, пока '_CarType' содержит только ваши константы, и они больше нигде не появляются, я не вижу риска для царапин на голове MRO. – balpha

+0

Фактически отвечает на вопрос, в отличие от моей попытки, и это выглядит как самый чистый способ сделать это. –

2

Это, как вы могли бы сделать это с метаклассом:

class _CarType(type): 
    DIESEL_CAR_ENGINE = 0 
    GAS_CAR_ENGINE = 1 # lots of these ids 
    def __init__(self,name,bases,dct): 
     for key in dir(_CarType): 
      if key.isupper(): 
       setattr(self,key,getattr(_CarType,key)) 

class Car(object): 
    __metaclass__=_CarType 

print(Car.DIESEL_CAR_ENGINE) 
print(Car.GAS_CAR_ENGINE) 
+0

Хорошее решение! Хотя метаклассическое программирование рассматривается как нечто темное ... –

+0

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

+0

-1 для метаклассификации без необходимости. Хлоп! –

0
class _CarType(object): 
    DIESEL_CAR_ENGINE = 0 
    GAS_CAR_ENGINE = 1 # lots of these ids 

class Car: 
    types = _CarType 
    def __getattr__(self, name): 
    return getattr(self.types, name) 

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

Работает только на автомобиле, а не на классе.

+0

Вы даже попробовали это решение? Как работает Car.DIESEL_CAR_ENGINE? self относится к уже созданному объекту ... – hyperboreean

+0

Работает на экземпляре Car, но не на классе. –

+0

К сожалению, это должно было ... исправлять ошибки. –

2

Ваши варианты делятся на две значительные категории: вы либо скопировать атрибуты из _CarType в Car, или установить метаклассом Car «s к обычаю один с __getattr__ метода, который делегирует _CarType (так что это не совсем верно, что вы не может использовать __getattr__: вы можете, вам просто нужно положить в meta класс, а не в Car сам ;-).

Второй вариант имеет последствия, которые вы могли бы найти Свой (если они специально не желательно): атрибуты не отображаются на dir(Car), и они не могут быть доступны на например из Car, только на Car себя. То есть:

>>> class MetaGetattr(type): 
... def __getattr__(cls, nm): 
...  return getattr(cls.types, nm) 
... 
>>> class Car: 
... __metaclass__ = MetaGetattr 
... types = _CarType 
... 
>>> Car.GAS_CAR_ENGINE 
1 
>>> Car().GAS_CAR_ENGINE 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'Car' object has no attribute 'GAS_CAR_ENGINE' 

Вы могли бы исправить «не из экземпляра» вопрос по также Добавление __getattr__ к Car:

>>> class Car: 
... __metaclass__ = MetaGetattr 
... types = _CarType 
... def __getattr__(self, nm): 
...  return getattr(self.types, nm) 
... 

сделать оба вида поиска работы, как это, вероятно, ожидается:

>>> Car.GAS_CAR_ENGINE 
1 
>>> Car().GAS_CAR_ENGINE 
1 

Однако, определяя два, по существу, равна __getattr__ s, не кажется элегантным.

Поэтому я подозреваю, что более простой подход, «скопировать все атрибуты», является предпочтительным. В Python 2.6 или лучше, это является очевидным кандидатом на класс декоратора:

def typesfrom(typesclass): 
    def decorate(cls): 
    cls.types = typesclass 
    for n in dir(typesclass): 
     if n[0] == '_': continue 
     v = getattr(typesclass, n) 
     setattr(cls, n, v) 
    return cls 
    return decorate 

@typesfrom(_CarType) 
class Car(object): 
    pass 

В общем, это стоит определение декоратора, если вы используете его больше, чем один раз; если вам нужно выполнить эту задачу только для одного класса, то вместо этого вместо этого следует добавить код inline (после инструкции class).

Если вы застряли с Python 2.5 (или даже 2,4), вы можете определить typesfrom таким же образом, вы просто применить его в несколько менее элегантной материи, т.е. Car определение становится:

class Car(object): 
    pass 
Car = typesfrom(_CarType)(Car) 

Помните, что синтаксис декоратора (представленный в 2.2 для функций, в 2.6 для классов) - это просто удобный способ обернуть эти важные и часто повторяющиеся семантики.

Смежные вопросы