Возможно ли иметь статические переменные класса или методы в Python? Какой синтаксис необходим для этого?
Переменные, объявленные внутри определения класса, но не внутри метода, являются классом или статическими переменными:
>>> class MyClass:
... i = 3
...
>>> MyClass.i
3
Как указывает @ millerdev , это создает i
переменную уровня класса , но она отличается от любой i
переменной уровня экземпляра , поэтому вы можете иметь
>>> m = MyClass()
>>> m.i = 4
>>> MyClass.i, m.i
>>> (3, 4)
Это отличается от C ++ и Java, но не так сильно отличается от C #, где к статическому члену нельзя получить доступ, используя ссылку на экземпляр.
Посмотрите, что в учебнике по Python говорится о предметах классов и объектов классов .
@Steve Johnson уже ответил о статических методах , также описанных в разделе «Встроенные функции» в Справочнике по библиотеке Python .
class C:
@staticmethod
def f(arg1, arg2, ...): ...
@beidy рекомендует использовать classmethod вместо staticmethod, так как метод затем получает тип класса в качестве первого аргумента, но я все еще не совсем понимаю преимущества этого подхода по сравнению со staticmethod. Если вы тоже, то это, вероятно, не имеет значения.
@classmethod
над@staticmethod
AFAIK заключается в том, что вы всегда получаете имя класса, к которому был вызван метод, даже если это подкласс. Статическому методу не хватает этой информации, поэтому он не может вызвать переопределенный метод, например.const.py
с ,PI = 3.14
и вы можете импортировать его везде.from const import PI
i = 3
это не статическая переменная, это атрибут класса, и, поскольку он отличается от атрибута уровня экземпляра,i
он не ведет себя как статическая переменная в других языках. См ответ millerdev в , ответ Yann, и мой ответ ниже.i
(статическая переменная) будет в памяти, даже если я создам сотни экземпляров этого класса?@Blair Conrad сказал, что статические переменные, объявленные внутри определения класса, но не внутри метода, являются классом или «статическими» переменными:
Здесь есть несколько ошибок. Продолжая из приведенного выше примера:
Обратите внимание, как переменная экземпляра
t.i
вышла из синхронизации со «статической» переменной класса, когда атрибутi
был установлен непосредственноt
. Это связано с тем, что онi
был повторно связан сt
пространством имен, которое отличается отTest
пространства имен. Если вы хотите изменить значение «статической» переменной, вы должны изменить его в пределах области (или объекта), где оно было первоначально определено. Я поместил «статический» в кавычки, потому что Python на самом деле не имеет статических переменных в том смысле, как в C ++ и Java.Хотя в нем нет ничего конкретного о статических переменных или методах, в руководстве по Python есть некоторая соответствующая информация о классах и объектах классов .
@Steve Johnson также ответил о статических методах, которые также описаны в разделе «Встроенные функции» в Справочнике по библиотеке Python.
@beid также упомянул classmethod, который похож на staticmethod. Первым аргументом метода класса является объект класса. Пример:
источник
class Test(object):
,_i = 3
,@property
,def i(self)
,return type(self)._i
,@i.setter
,def i(self,val):
,type(self)._i = val
. Теперь вы можете сделатьx = Test()
,x.i = 12
,assert x.i == Test.i
.Статические и классовые методы
Как отмечалось в других ответах, статические методы и методы класса легко реализуются с помощью встроенных декораторов:
Как обычно, первый аргумент to
MyMethod()
связан с объектом экземпляра класса. В противоположность этому , первый аргументMyClassMethod()
будет связан с самим объектом класса (например, в данном случаеTest
). ВедьMyStaticMethod()
ни один из аргументов не связан, а наличие аргументов вообще необязательно.«Статические переменные»
Однако реализация «статических переменных» (ну, в любом случае , изменяемых статических переменных, если это не противоречие в терминах ...) не так проста. Как Миллердев указал в своем ответе , проблема в том, что атрибуты класса Python не являются действительно «статическими переменными». Рассматривать:
Это происходит потому , что линия
x.i = 12
добавлен новый атрибут экземпляра ,i
чтобыx
вместо изменения значенияTest
классаi
атрибута.Частичное ожидаемое поведение статической переменной, т. Е. Синхронизация атрибута между несколькими экземплярами (но не с самим классом; см. «Полученная информация» ниже), может быть достигнута путем превращения атрибута класса в свойство:
Теперь вы можете сделать:
Статическая переменная теперь будет синхронизироваться между всеми экземплярами класса .
(ПРИМЕЧАНИЕ. То есть, если экземпляр класса не решит определить свою собственную версию
_i
! Но если кто-то решит сделать ЭТО, он заслуживает того, что получает, не так ли?)Обратите внимание, что с технической точки зрения,
i
это еще не «статическая переменная» вообще; этоproperty
особый тип дескриптора. Тем не менее,property
поведение теперь эквивалентно (изменяемой) статической переменной, синхронизированной во всех экземплярах класса.Неизменные "статические переменные"
Для поведения неизменяемой статической переменной просто опустите
property
установщик:Теперь попытка установить
i
атрибут экземпляра вернетAttributeError
:Один Gotcha, чтобы быть в курсе
Обратите внимание, что приведенные выше методы работают только с экземплярами вашего класса - они не будут работать при использовании самого класса . Так, например:
Строка
assert Test.i == x.i
выдает ошибку, потому чтоi
атрибутомTest
иx
являются два разных объекта.Многие найдут это удивительным. Однако так не должно быть. Если мы вернемся и проверим
Test
определение нашего класса (вторая версия), мы примем к сведению эту строку:Очевидно, что элемент
i
изTest
должна бытьproperty
объектом, который является тип объекта , возвращаемого изproperty
функции.Если вы находите вышеупомянутое в замешательстве, скорее всего, вы все еще думаете об этом с точки зрения других языков (например, Java или c ++). Вам следует изучить
property
объект, порядок, в котором возвращаются атрибуты Python, протокол дескриптора и порядок разрешения методов (MRO).Я представляю решение вышеупомянутой «ошибки» ниже; Тем не менее, я бы настоятельно рекомендовал вам - не пытаться делать что-то вроде следующего, пока - как минимум - вы полностью не поймете, почему
assert Test.i = x.i
возникает ошибка.РЕАЛЬНЫЕ, АКТУАЛЬНЫЕ статические переменные -
Test.i == x.i
Я представляю решение (Python 3) ниже только в ознакомительных целях. Я не одобряю это как «хорошее решение». У меня есть сомнения относительно того, действительно ли когда-либо необходима эмуляция поведения статических переменных в других языках Python. Тем не менее, независимо от того, насколько он полезен, нижеприведенное должно помочь понять, как работает Python.
ОБНОВЛЕНИЕ: эта попытка действительно ужасна ; если вы настаиваете на том, чтобы сделать что-то вроде этого (подсказка: пожалуйста, не делайте; Python - очень элегантный язык, и вам не нужно, чтобы он вел себя как другой язык), используйте вместо этого код в ответе Итана Фурмана .
Эмуляция поведения статических переменных других языков с использованием метакласса
Метакласс - это класс класса. Метакласс по умолчанию для всех классов в Python (т. Е. Классы «нового стиля» после Python 2.3, я полагаю) таков
type
. Например:Однако вы можете определить свой собственный метакласс следующим образом:
И примените его к своему собственному классу вот так (только Python 3):
Ниже я создал метакласс, который пытается эмулировать поведение «статических переменных» других языков. Он в основном работает, заменяя стандартные методы получения, установки и удаления версиями, которые проверяют, является ли запрашиваемый атрибут «статической переменной».
Каталог «статических переменных» хранится в
StaticVarMeta.statics
атрибуте. Все запросы к атрибутам первоначально пытаются разрешить с использованием порядка разрешения замены. Я назвал это «статическим разрешением» или «SRO». Это делается путем поиска запрошенного атрибута в наборе «статических переменных» для данного класса (или его родительских классов). Если атрибут не отображается в «SRO», класс будет использовать атрибут get / set / delete по умолчанию для атрибута (т. Е. «MRO»).источник
Test
(до того, как использовать его для создания экземпляров), как область метапрограммирования? Например, вы изменяете поведение класса, выполняяTest.i = 0
(здесь вы просто полностью уничтожаете объект свойства). Я предполагаю, что «механизм свойств» включается только при доступе к свойствам экземпляров класса (если, возможно, вы не измените базовое поведение, используя мета-класс в качестве промежуточного). Кстати, пожалуйста, закончите этот ответ :-)Вы также можете добавлять переменные класса к классам на лету
И экземпляры класса могут изменять переменные класса
источник
Лично я использовал бы метод класса всякий раз, когда мне нужен статический метод. Главным образом потому, что я получаю класс в качестве аргумента.
или использовать декоратор
Для статических свойств ... Пришло время посмотреть какое-то определение Python. Переменная всегда может быть изменена. Есть два типа: изменяемые и неизменяемые. Кроме того, есть атрибуты класса и атрибуты экземпляра. Ничто на самом деле не похоже на статические атрибуты в смысле java & c ++.
Зачем использовать статический метод в питоническом смысле, если он не имеет никакого отношения к классу! Если бы я был тобой, я бы либо использовал метод класса, либо определил бы метод, независимый от класса.
источник
Особое внимание следует обратить на статические свойства и свойства экземпляра, показанные в следующем примере:
Это означает, что перед присвоением значения свойству экземпляра, если мы пытаемся получить доступ к свойству через экземпляр, используется статическое значение. Каждое свойство, объявленное в классе Python, всегда имеет статический слот в памяти .
источник
Статические методы в python называются classmethod s. Посмотрите на следующий код
Обратите внимание, что когда мы вызываем метод myInstanceMethod , мы получаем ошибку. Это потому, что он требует, чтобы метод вызывался для экземпляра этого класса. Метод myStaticMethod устанавливается как метод класса с использованием декоратора @classmethod .
Просто для удовольствия мы можем вызвать myInstanceMethod для класса, передав экземпляр класса следующим образом:
источник
@staticmethod
;@classmethod
(очевидно) для методов класса (которые в первую очередь предназначены для использования в качестве альтернативных конструкторов, но могут в крайнем случае служить статическими методами, получающими ссылку на класс, через который они были вызваны).При определении некоторой переменной-члена вне какого-либо метода-члена переменная может быть статической или нестатической в зависимости от того, как она выражена.
Например:
Результаты
источник
Можно иметь
static
переменные класса, но, вероятно, не стоит усилий.Вот доказательство концепции, написанное на Python 3 - если какие-то точные детали неверны, код можно настроить так, чтобы он соответствовал почти любому, что вы подразумеваете под
static variable
:и в использовании:
и некоторые тесты:
источник
Вы также можете заставить класс быть статичным, используя метакласс.
Тогда всякий раз, когда вы случайно попытаетесь инициализировать MyClass, вы получите StaticClassError.
источник
__new__
своих родителей ...Одним из очень интересных моментов в поиске атрибутов Python является то, что его можно использовать для создания « виртуальных переменных»:
Обычно нет никаких назначений этим после того, как они созданы. Обратите внимание, что поиск использует,
self
потому что, хотяlabel
является статическим в том смысле, что он не связан с конкретным экземпляром, значение по-прежнему зависит от (класса) экземпляра.источник
Что касается этого ответа , для постоянной статической переменной вы можете использовать дескриптор. Вот пример:
в результате чего ...
Вы всегда можете вызвать исключение, если тихое игнорирование значения настройки (
pass
выше) не ваша вещь. Если вы ищете C ++, переменную статического класса в стиле Java:Посмотрите этот ответ и документацию HOWTO для получения дополнительной информации о дескрипторах.
источник
@property
, что аналогично использованию дескриптора, но это намного меньше кода.Абсолютно да, Python сам по себе не имеет какого-либо статического члена данных явно, но мы можем сделать это
вывод
объяснение
источник
Да, безусловно, можно писать статические переменные и методы в Python.
Статические переменные: переменные, объявленные на уровне класса, называются статическими переменными, к которым можно обращаться напрямую, используя имя класса.
Переменные экземпляра: Переменные, которые связаны и доступны экземпляру класса, являются переменными экземпляра.
Статические методы: Подобно переменным, статические методы могут быть доступны напрямую с помощью класса Name. Не нужно создавать экземпляр.
Но имейте в виду, что статический метод не может вызывать нестатический метод в Python.
источник
Чтобы избежать возможной путаницы, я бы хотел сопоставить статические переменные и неизменяемые объекты.
Некоторые примитивные типы объектов, такие как целые числа, числа с плавающей запятой, строки и части, являются неизменяемыми в Python. Это означает, что объект, на который ссылается данное имя, не может измениться, если он относится к одному из вышеупомянутых типов объектов. Имя может быть переназначено другому объекту, но сам объект не может быть изменен.
Если сделать статическую переменную еще более продвинутой, запретить имя переменной указывать на любой объект, кроме того, на который она в данный момент указывает. (Примечание: это общая концепция программного обеспечения, а не специфичная для Python; пожалуйста, смотрите посты других пользователей для получения информации о реализации статики в Python).
источник
Лучший способ, который я нашел, - это использовать другой класс. Вы можете создать объект, а затем использовать его на других объектах.
В приведенном выше примере я сделал класс с именем
staticFlag
.Этот класс должен представлять статическую переменную
__success
(Private Static Var).tryIt
класс представляет обычный класс, который мы должны использовать.Теперь я сделал объект для одного флага (
staticFlag
). Этот флаг будет отправлен как ссылка на все обычные объекты.Все эти объекты добавляются в список
tryArr
.Результаты этого скрипта:
источник
Статические переменные в фабрике классов python3.6
Для тех, кто использует фабрику классов с python3.6 и выше, используйте
nonlocal
ключевое слово, чтобы добавить его в область видимости / контекст создаваемого класса следующим образом:источник
hasattr(SomeClass, 'x')
естьFalse
. я сомневаюсь, что это то, что кто-то подразумевает под статической переменной вообще.some_var
неизменным и статически определенным, или нет? Какое отношение имеет внешний доступ получателя к статической переменной или нет? У меня сейчас так много вопросов. хотел бы услышать некоторые ответы, когда у вас будет время.some_var
выше это вовсе не ученик. В Python все члены класса могут быть доступны извне класса.nonlocal
Keywoard «врезается» объем переменной. Область определения тела класса не зависит от области, в которой он обнаруживает себя, когда вы говоритеnonlocal some_var
, что это просто создание нелокальной (читается: НЕ в области определения класса) имени для другого именованного объекта. Поэтому он не привязывается к определению класса, потому что он не находится в области видимости тела класса.Так что это, вероятно, хак, но я использовал
eval(str)
для получения статического объекта, своего рода противоречие, в Python 3.Существует файл Records.py, в котором нет ничего, кроме
class
объектов, определенных статическими методами и конструкторами, которые сохраняют некоторые аргументы. Затем из другого файла .py,import Records
но мне нужно динамически выбирать каждый объект, а затем создавать его по требованию в соответствии с типом данных, которые считываются.Итак, где
object_name = 'RecordOne'
или имя класса, я вызываю,cur_type = eval(object_name)
а затем создаю его экземпляр, который вы делаете.cur_inst = cur_type(args)
Однако перед тем, как создать экземпляр, вы можете вызвать статические методы,cur_type.getName()
например, вроде реализации абстрактного базового класса или любой другой цели. Однако в бэкэнде он, вероятно, создается в python и не является по-настоящему статичным, потому что eval возвращает объект ... который должен быть создан ... который дает статическое поведение.источник
Вы можете использовать список или словарь, чтобы получить «статическое поведение» между экземплярами.
источник
Если вы пытаетесь использовать статическую переменную для, например, увеличения ее в других экземплярах, что-то вроде этого сценария работает нормально:
источник