Вопрос-Ответ

Should I use instance or class attributes if there will only be one instance? [closed]

Должен ли я использовать атрибуты экземпляра или класса, если будет только один экземпляр?

У меня есть классы Python, из которых мне нужен только один экземпляр во время выполнения, поэтому было бы достаточно иметь атрибуты только один раз для каждого класса, а не для каждого экземпляра. Если будет более одного экземпляра (чего не произойдет), все экземпляры должны иметь одинаковую конфигурацию. Интересно, какой из следующих вариантов был бы лучше или более "идиоматичным" для Python.

Переменные класса:

class MyController(Controller):

path = "something/"
children = [AController, BController]

def action(self, request):
pass

Переменные экземпляра:

class MyController(Controller):

def __init__(self):
self.path = "something/"
self.children = [AController, BController]

def action(self, request):
pass
Переведено автоматически
Ответ 1

Если у вас все равно есть только один экземпляр, лучше всего сделать все переменные отдельными для каждого экземпляра, просто потому, что доступ к ним будет (немного) быстрее (на один уровень "поиска" меньше из-за "наследования" от класса к экземпляру), и нет никаких недостатков, которые могли бы компенсировать это небольшое преимущество.

Ответ 2

Повторяю советы Майка и Алекса и добавляю свой собственный цвет...

Использование атрибутов экземпляра - типичный ... более идиоматичный Python. Атрибуты класса используются не так часто, поскольку их варианты использования специфичны. То же самое верно для статических методов и методов класса по сравнению с "обычными" методами. Это специальные конструкции, предназначенные для конкретных случаев использования, в противном случае это код, созданный программистом-аберрантом, желающим показать, что он знает какой-то неясный уголок программирования на Python.

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


  1. локальные

  2. нелокальные

  3. глобальные

  4. встроенные модули

Для доступа к атрибутам порядок следующий:


  1. экземпляр

  2. класс

  3. базовые классы, определенные MRO (порядок разрешения метода)

Оба метода работают "наизнанку", то есть сначала проверяются большинство локальных объектов, затем последовательно проверяются внешние слои.

В вашем примере выше, допустим, вы ищете path атрибут. Когда он встречает ссылку типа "self.path", Python сначала проверяет атрибуты экземпляра на соответствие. Когда это не удается, выполняется проверка класса, из которого был создан экземпляр объекта. Наконец, выполняется поиск по базовым классам. Как сказал Алекс, если ваш атрибут найден в экземпляре, его не нужно искать в другом месте, следовательно, вы немного сэкономите время.

Однако, если вы настаиваете на атрибутах класса, вам понадобится дополнительный поиск. Или, другой ваш вариант - ссылаться на объект через класс вместо экземпляра, например, MyController.path вместо self.path. Это прямой поиск, который позволит обойти отложенный поиск, но, как упоминает Алекс ниже, это глобальная переменная, поэтому вы потеряете ту часть, которую, как вы думали, собирались сохранить (если вы не создадите локальную ссылку на [глобальное] имя класса).

Суть в том, что вы должны использовать атрибуты экземпляра большую часть времени. Однако будут случаи, когда атрибут класса является подходящим инструментом для работы. Код, использующий оба одновременно, потребует наибольшего усердия, потому что использование self даст вам только объект атрибута экземпляра и shadows доступ к одноименному атрибуту класса. В этом случае вы должны использовать доступ к атрибуту по имени класса, чтобы ссылаться на него.

Ответ 3

Если вы сомневаетесь, вам, вероятно, нужен атрибут экземпляра.

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

Ответ 4

Тот же вопрос при производительности доступа к переменным класса в Python - приведенный здесь код адаптирован @Edward Loper

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

Есть 4 области, из которых вы можете получить доступ к переменным:


  1. Переменные экземпляра (self.varname)

  2. Переменные класса (Classname.varname)

  3. Переменные модуля (VARNAME)

  4. Локальные переменные (varname)

Тест:

import timeit

setup='''
XGLOBAL= 5
class A:
xclass = 5
def __init__(self):
self.xinstance = 5
def f1(self):
xlocal = 5
x = self.xinstance
def f2(self):
xlocal = 5
x = A.xclass
def f3(self):
xlocal = 5
x = XGLOBAL
def f4(self):
xlocal = 5
x = xlocal
a = A()
'''

print('access via instance variable: %.3f' % timeit.timeit('a.f1()', setup=setup, number=300000000) )
print('access via class variable: %.3f' % timeit.timeit('a.f2()', setup=setup, number=300000000) )
print('access via module variable: %.3f' % timeit.timeit('a.f3()', setup=setup, number=300000000) )
print('access via local variable: %.3f' % timeit.timeit('a.f4()', setup=setup, number=300000000) )

Результат:

access via instance variable: 93.456
access via class variable: 82.169
access via module variable: 72.634
access via local variable: 72.199
python class