Должен ли я дать своим членам класса значения по умолчанию, например:
class Foo:
num = 1
или вот так?
class Foo:
def __init__(self):
self.num = 1
В этом вопросе я обнаружил, что в обоих случаях
bar = Foo()
bar.num += 1
это четко определенная операция.
Я понимаю, что первый метод предоставит мне переменную класса, а второй - нет. Однако, если мне не нужна переменная класса, а нужно только установить значение по умолчанию для моих переменных экземпляра, одинаково ли хороши оба метода? Или один из них более питонический, чем другой?
Я заметил одну вещь: в учебнике по Django для объявления моделей используется второй метод. Лично мне кажется, что второй метод более элегантен, но я хотел бы знать, что такое «стандартный» способ.
self.attr = attr or []
в рамках__init__
метода. Он дает тот же результат (я думаю), но при этом остается четким и читаемым.Эти два фрагмента делают разные вещи, поэтому дело не в вкусе, а в правильном поведении в вашем контексте. Документация Python объясняет разницу, но вот несколько примеров:
Выставка
class Foo: def __init__(self): self.num = 1
Это привязывается
num
к экземплярам Foo . Изменение в этом поле не распространяется на другие экземпляры.Таким образом:
>>> foo1 = Foo() >>> foo2 = Foo() >>> foo1.num = 2 >>> foo2.num 1
Приложение B
class Bar: num = 1
Это привязывается
num
к классу Bar . Изменения распространяются!>>> bar1 = Bar() >>> bar2 = Bar() >>> bar1.num = 2 #this creates an INSTANCE variable that HIDES the propagation >>> bar2.num 1 >>> Bar.num = 3 >>> bar2.num 3 >>> bar1.num 2 >>> bar1.__class__.num 3
Актуальный ответ
Код на выставке B явно неверен для этого: зачем вам связывать атрибут класса (значение по умолчанию при создании экземпляра) с единственным экземпляром?
Код на выставке А в порядке.
Если вы хотите указать значения по умолчанию для переменных экземпляра в своем конструкторе, я бы сделал следующее:
class Foo: def __init__(self, num = None): self.num = num if num is not None else 1
...или даже:
class Foo: DEFAULT_NUM = 1 def __init__(self, num = None): self.num = num if num is not None else DEFAULT_NUM
... или даже: (желательно, но тогда и только тогда, когда вы имеете дело с неизменяемыми типами!)
class Foo: def __init__(self, num = 1): self.num = num
Таким образом вы можете:
foo1 = Foo(4) foo2 = Foo() #use default
источник
def __init__(self, num = None)
Использование членов класса для задания значений по умолчанию работает очень хорошо, если вы осторожно делаете это только с неизменяемыми значениями. Если вы попытаетесь сделать это со списком или изречением, это будет довольно смертельно. Он также работает, если атрибут экземпляра является ссылкой на класс, если значение по умолчанию - None.
Я видел, как этот метод очень успешно используется в репозитории, который представляет собой фреймворк, работающий поверх Zope. Преимущество здесь не только в том, что когда ваш класс сохраняется в базе данных, необходимо сохранить только атрибуты, отличные от атрибутов по умолчанию, но также и в том случае, когда вам нужно добавить новое поле в схему, все существующие объекты видят новое поле со значением по умолчанию. значение без необходимости изменять сохраненные данные.
Я считаю, что это также хорошо работает в более общем кодировании, но это стиль. Используйте то, что вам нравится больше всего.
источник
Использование членов класса для значений по умолчанию переменных экземпляра - не лучшая идея, и я впервые вижу, что эта идея упоминается вообще. Он работает в вашем примере, но во многих случаях может не работать. Например, если значение является изменяемым, изменение его на неизмененном экземпляре изменит значение по умолчанию:
>>> class c: ... l = [] ... >>> x = c() >>> y = c() >>> x.l [] >>> y.l [] >>> x.l.append(10) >>> y.l [10] >>> c.l [10]
источник
[]
были клонированы только самые первые ;x.l
иy.l
являются одновременно злыми именами и разными непосредственными ценностями, связанными с одним и тем же референтом. (Условия языкового юриста составлены)Вы также можете объявить переменные класса как None, что предотвратит распространение. Это полезно, когда вам нужен четко определенный класс и вы хотите предотвратить AttributeErrors. Например:
>>> class TestClass(object): ... t = None ... >>> test = TestClass() >>> test.t >>> test2 = TestClass() >>> test.t = 'test' >>> test.t 'test' >>> test2.t >>>
Также, если вам нужны значения по умолчанию:
>>> class TestClassDefaults(object): ... t = None ... def __init__(self, t=None): ... self.t = t ... >>> test = TestClassDefaults() >>> test.t >>> test2 = TestClassDefaults([]) >>> test2.t [] >>> test.t >>>
Конечно, по-прежнему следуйте информации в других ответах об использовании изменяемых и неизменяемых типов по умолчанию в
__init__
.источник
С помощью классов данных , функции, добавленной в Python 3.7, теперь есть еще один (довольно удобный) способ добиться установки значений по умолчанию для экземпляров класса. Декоратор
dataclass
автоматически сгенерирует несколько методов вашего класса, например конструктор. Как отмечается в документации, приведенной выше, «[t] переменные-члены для использования в этих сгенерированных методах определены с использованием аннотаций типа PEP 526 ».Рассматривая пример OP, мы могли бы реализовать это так:
from dataclasses import dataclass @dataclass class Foo: num: int = 0
При построении объекта этого типа класса мы можем при желании перезаписать значение.
print('Default val: {}'.format(Foo())) # Default val: Foo(num=0) print('Custom val: {}'.format(Foo(num=5))) # Custom val: Foo(num=5)
источник