2009-08-09 2 views
12

Мне интересно услышать некоторое обсуждение атрибутов класса в Python. Например, что является хорошим вариантом использования атрибутов класса? По большей части я не могу придумать случай, когда атрибут класса предпочтительнее использовать атрибут уровня модуля. Если это так, то почему их вокруг?Атрибуты класса Python и модуля

Проблема, с которой я сталкиваюсь, заключается в том, что по ошибке слишком сложно сбивать значение атрибута класса, а затем ваше «глобальное» значение превратилось в атрибут локального экземпляра.

Не стесняйтесь комментировать, как бы вы в следующих ситуациях:

  1. Постоянные значения, используемые классом и/или подклассов. Это может включать в себя словарные клавиши «магического номера» или индексы списка, которые никогда не изменятся, но, возможно, потребуется однократная инициализация.
  2. По умолчанию атрибут класса, который в редких случаях обновляется для специального экземпляра класса.
  3. Глобальная структура данных, используемая для представления внутреннего состояния класса, общего для всех экземпляров.
  4. Класс, который инициализирует ряд атрибутов по умолчанию, не подверженных влиянию аргументов конструктора.

Некоторые Похожие сообщения:
Difference Between Class and Instance Attributes

+0

должен быть wiki сообщества – SilentGhost

ответ

7

# 4: Я никогда использование класса Атрибуты для инициализации экземпляра по умолчанию атрибуты (те, которые вы обычно положить в __init__). Например:

class Obj(object): 
    def __init__(self): 
     self.users = 0 

и никогда:

class Obj(object): 
    users = 0 

Почему? Потому что это непоследовательно: он не делает то, что вы хотите, когда вы назначаете ничего, кроме инвариантного объекта:

class Obj(object): 
    users = [] 

вызывает список пользователей, которые будут доступны во всех объектах, которые в данном случае не хотел. Сложно разбить их на атрибуты классов и присвоения в __init__ в зависимости от их типа, поэтому я всегда ставил их все в __init__, которые я нахожу более ясными в любом случае.

Что касается остальных, я обычно помещаю значения класса в класс.Это не так много, потому что глобальные «злые» - они не такие большие, как на некоторых языках, потому что они все еще привязаны к модулю, если только сам модуль слишком велик, - но если внешний код хочет получить к ним доступ, удобно иметь все соответствующие значения в одном месте. Например, в module.py:

class Obj(object): 
    class Exception(Exception): pass 
    ... 

, а затем:

from module import Obj 

try: 
    o = Obj() 
    o.go() 
except o.Exception: 
    print "error" 

Помимо позволяя подклассы, чтобы изменить значение (которое не всегда хотели в любом случае), это означает, что у меня нет для трудоемкого импорта имен исключений и множества других вещей, необходимых для использования Obj. «из импорта модуля Obj, ObjException, ...» становится утомительно быстро.

2

атрибуты класса часто используются, чтобы верховные по умолчанию в подклассах. Например, BaseHTTPRequestHandler имеет константы класса sys_version и server_version, последний по умолчанию - "BaseHTTP/" + __version__. SimpleHTTPRequestHandler переопределяет server_version на "SimpleHTTP/" + __version__.

+0

Однако метод доступа атрибута класса будет фактором, если это сработало или нет. Другая причина, по которой атрибуты класса опасны. – cmcginty

+0

Какой «метод доступа»? cls.version, self.version, getattr, все дадут правильный ответ. * Определить класс для разрешения переопределений * работает так же хорошо, как и для кода, так что, Кейси, почему вы думаете, что это опасно для данных, но отлично подходит для кода ?! –

+0

Использование класса Class.value вместо self.value в методе доступа к атрибуту предотвратит появление переопределения.Иногда это желаемый случай, иногда нет. – cmcginty

1

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

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

3

, что является хорошим примером использования класса атрибутов

Случай 0. методы класса являются атрибутами всего класса. Это не просто техническое сходство - вы можете получить доступ и изменить методы класса во время выполнения, назначив для них вызывающие права.

Корпус 1. Модуль может легко определить несколько классов. Разумно заключить все о class A в A... и все о class B в B.... Например,

# module xxx 
class X: 
    MAX_THREADS = 100 
    ... 

# main program 
from xxx import X 

if nthreads < X.MAX_THREADS: ... 

Случай 2. Этот класс имеет множество атрибутов по умолчанию, которые могут быть изменены в экземпляре. Здесь способность оставить атрибут «глобальным дефолтом» является функцией, а не ошибкой.

class NiceDiff: 
    """Formats time difference given in seconds into a form '15 minutes ago'.""" 

    magic = .249 
    pattern = 'in {0}', 'right now', '{0} ago' 

    divisions = 1 

    # there are more default attributes 

Один создает экземпляр NiceDiff использовать существующее или слегка измененное форматирование, но локализатор на другом язык подклассы класса для реализации некоторых функций в принципиально ином способе и переопределяют константы:

class Разница(NiceDiff): # NiceDiff localized to Russian 
    '''Из разницы во времени, типа -300, делает конкретно '5 минут назад'.''' 

    pattern = 'через {0}', 'прям щас', '{0} назад' 

Ваши дела:

  • константы - вы s, я помещаю их в класс. Странно сказать self.CONSTANT = ..., поэтому я не вижу большого риска для их скрещивания.
  • Атрибут по умолчанию - смешанный, как указано выше, может перейти в класс, но также может перейти в __init__ в зависимости от семантики.
  • Глобальная структура данных --- подходит к классу, если используется только по классу, но может также пойти в модуль, в любом случае должен быть очень хорошо документирован.
Смежные вопросы