Каков хороший способ отслеживать переменные экземпляра класса в Python?

Я программист на C++ только начинаю изучать Python. Я хотел бы знать, как вы отслеживаете переменные экземпляра в больших классах Python. Я привык иметь Это дает мне аккуратный список (с комментариями) всех членов класса. Но поскольку Python позволяет добавлять новые переменные экземпляра на лету, как вы отслеживаете их все?

Я представляю сценарий, где я ошибочно добавляю новую переменную экземпляра, когда у меня уже был один - но это было 1000 подальше от того места, где я работал. Существуют ли стандартные методы, позволяющие избежать этого?

Edit: кажется, я создал некоторую путаницу с термином "переменная-член."Я действительно имею в виду переменную экземпляра, и я соответствующим образом отредактировал свой вопрос.

10 ответов


прежде всего: атрибуты класса или атрибуты экземпляра? Или как? =)

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

если код добавляет атрибуты на лету, у него, вероятно (надеюсь :-) есть веские причины для этого... использование динамических функций, интроспекции и т. д. Кроме этого, добавление атрибутов таким образом наверное, реже, чем вы думаете.


Я бы сказал, стандартная практика, чтобы избежать этого -не писать классы, где вы можете быть 1000 строк ничего!

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

самые большие классы в стандартной библиотеке имеют значительно ниже 100 линий!


переменные должны быть инициализированы в классе __init__() метод. (В общем)

Если это невозможно. Вы можете использовать __dict__ получить словарь всех переменных экземпляра объекта во время выполнения. Если вам действительно нужно отслеживать это в документации, добавьте список переменных экземпляра, которые вы используете в docstring класса.


pylint может статически обнаруживать атрибуты, которые не обнаружены в __init__, наряду со многими другими потенциальными ошибками.

Я бы также рекомендовал писать модульные тесты и часто запускать код, чтобы обнаружить эти типы ошибок программирования "whoopsie".


похоже, вы говорите о переменных экземпляра и переменных класса нет. Обратите внимание, что в следующем коде a-переменная класса, А b-переменная экземпляра.

class foo:
  a = 0 #class variable

  def __init__(self):
    self.b = 0 #instance variable

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


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


Это общая проблема, которую я слышу от многих программистов, которые происходят из C, C++ или другого статически типизированного языка, где переменные предварительно объявлены. На самом деле это была одна из самых больших проблем, которые мы слышали, когда убеждали программистов нашей организации отказаться от C для программ высокого уровня и использовать Python вместо этого.

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

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


Мне кажется, что основная проблема здесь в том, что вы думаете в терминах C++, когда работаете в python.

наличие класса 1000 строк в любом случае не очень мудро в python (я знаю, что это происходит много в C++),

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

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

d = {'command1' : func1, 'command2': func2, 'command3' : func3}
#then somewhere else use this list to dispatch
#given a string `str`
func = d[str]
func() #call the function!

что-то вроде этого в C++ заняло бы так много строк кода!


проще всего использовать IDE. PyDev-это плагин для eclipse.

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

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

локальные переменные области, otoh, должны быть определены ближе всего к тому, когда они используются (за исключением C--which Я считаю, что все еще требует, чтобы переменные были объявлены в начале метода).


рассмотрите возможность использования слоты.

например:

   class Foo:
     __slots__ = "a b c".split()
   x = Foo()
   x.a =1    # ok
   x.b =1    # ok
   x.c =1    # ok
   x.bb = 1  # will raise "AttributeError: Foo instance has no attribute 'bb'"

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