Я учу себя Python, и мой последний урок состоял в том, что Python - это не Java , и поэтому я просто потратил некоторое время, превращая все свои методы Class в функции.
Теперь я понимаю, что мне не нужно использовать методы класса для того, что я делал бы с static
методами в Java, но теперь я не уверен, когда я буду их использовать. Все советы, которые я могу найти о методах класса Python, должны быть такими же, как у новичков, таких как я, и стандартная документация наиболее непрозрачна при их обсуждении.
У кого-нибудь есть хороший пример использования метода Class в Python или, по крайней мере, кто-нибудь может сказать мне, когда методы Class могут быть разумно использованы?
источник
obj.cls_mthd(...)
илиtype(obj).cls_mthd(...)
?Фабричные методы (альтернативные конструкторы) действительно являются классическим примером методов класса.
По сути, методы класса подходят в любое время, когда вы хотите иметь метод, который естественным образом вписывается в пространство имен класса, но не связан с конкретным экземпляром класса.
Как пример, в отличном модуле unipath :
Текущий каталог
Path.cwd()
Path("/tmp/my_temp_dir")
. Это метод класса..chdir()
Поскольку текущий каталог является широким процессом, у
cwd
метода нет конкретного экземпляра, с которым он должен быть связан. Однако изменениеcwd
каталога данногоPath
экземпляра действительно должно быть методом экземпляра.Хм ... как на
Path.cwd()
самом деле возвращаетPath
экземпляр, я думаю, это можно считать фабричным методом ...источник
Подумайте об этом так: обычные методы полезны, чтобы скрыть детали диспетчеризации: вы можете печатать,
myobj.foo()
не беспокоясь о томfoo()
, реализован ли методmyobj
классом объекта или одним из его родительских классов. Методы класса в точности аналогичны этому, но вместо этого они используют объект класса: они позволяют вам вызывать,MyClass.foo()
не беспокоясь о томfoo()
, реализован ли он специально,MyClass
потому что ему нужна собственная специализированная версия, или он разрешает своему родительскому классу обрабатывать вызов.Методы класса необходимы, когда вы выполняете настройку или вычисление, которое предшествует созданию фактического экземпляра, потому что, пока экземпляр не существует, вы, очевидно, не можете использовать экземпляр в качестве точки отправки для вызовов вашего метода. Хороший пример можно посмотреть в исходном коде SQLAlchemy; взгляните на
dbapi()
метод класса по следующей ссылке:https://github.com/zzzeek/sqlalchemy/blob/ab6946769742602e40fb9ed9dde5f642885d1906/lib/sqlalchemy/dialects/mssql/pymssql.py#L47
Вы можете видеть, что
dbapi()
метод, который серверная часть базы данных использует для импорта библиотеки базы данных конкретного поставщика, которая ему нужна по требованию, является методом класса, потому что он должен быть запущен до того, как экземпляры определенного соединения с базой данных начнут создаваться - но он не может быть простой функцией или статической функцией, потому что они хотят, чтобы она могла вызывать другие, поддерживающие методы, которые аналогичным образом должны быть написаны более конкретно в подклассах, чем в их родительском классе. А если вы отправляете функцию или статический класс, то вы «забываете» и теряете знания о том, какой класс выполняет инициализацию.источник
Недавно я хотел получить очень легкий класс журналирования, который бы выводил различное количество выходных данных в зависимости от уровня ведения журнала, который мог бы быть установлен программно. Но я не хотел создавать экземпляр класса каждый раз, когда хотел вывести отладочное сообщение или ошибку или предупреждение. Но я также хотел инкапсулировать функционирование этого средства регистрации и сделать его многоразовым без объявления каких-либо глобальных переменных.
Поэтому я использовал переменные класса и
@classmethod
декоратор для достижения этой цели.С моим простым классом Logging я мог сделать следующее:
Затем, в моем коде, если я хотел выпустить кучу отладочной информации, мне просто нужно было кодировать
Ошибки могут быть выведены с
В «производственной» среде я могу указать
и теперь выводится только сообщение об ошибке. Отладочное сообщение не будет напечатано.
Вот мой класс:
И некоторый код, который проверяет это только немного:
источник
Альтернативные конструкторы являются классическим примером.
источник
Когда пользователь входит на мой сайт, объект User () создается из имени пользователя и пароля.
Если мне нужен объект пользователя без пользователя, чтобы войти в систему (например, администратор может захотеть удалить учетную запись другого пользователя, поэтому мне нужно создать экземпляр этого пользователя и вызвать его метод удаления):
У меня есть методы класса, чтобы захватить пользовательский объект.
источник
Я думаю, что самый ясный ответ - AmanKow . Это сводится к тому, как вы хотите организовать свой код. Вы можете написать все как функции уровня модуля, которые обернуты в пространство имен модуля, т.е.
Вышеупомянутый процедурный код не очень хорошо организован, как вы можете видеть, что после всего 3 модулей он сбивает с толку, что делает каждый метод? Вы можете использовать длинные описательные имена для функций (как в java), но ваш код очень быстро становится неуправляемым.
Объектно-ориентированный способ состоит в том, чтобы разбить ваш код на управляемые блоки, т.е. классы, объекты и функции могут быть связаны с экземплярами объектов или с классами.
С функциями класса вы получаете другой уровень деления в вашем коде по сравнению с функциями уровня модуля. Таким образом, вы можете сгруппировать связанные функции внутри класса, чтобы сделать их более специфичными для задачи, назначенной этому классу. Например, вы можете создать файл утилиты класса:
Этот способ является более гибким и более обслуживаемым, вы группируете функции вместе, и это более очевидно для каждой функции. Также вы предотвращаете конфликты имен, например, функция копирования может существовать в другом импортированном модуле (например, сетевая копия), который вы используете в своем коде, поэтому, когда вы используете полное имя FileUtil.copy (), вы устраняете проблему и обе функции копирования. можно использовать бок о бок.
источник
FileUtil
методы класса как функцииfile_util
модуля, это было бы сопоставимо и не использовало бы ООП, если на самом деле не существует никаких объектов (на самом деле вы могли бы утверждать, что это предпочтительнее, потому что вы не получаете в итогеfrom file_util import FileUtil
или другого многословия). Аналогичным образом можно избежать конфликтов имен в процедурном коде, выполнивimport file_util
вместоfrom file_util import ...
.Честно? Я никогда не находил применение статическому или классному методу. Я еще не видел операцию, которую нельзя выполнить с помощью глобальной функции или метода экземпляра.
Было бы по-другому, если бы Python использовал закрытые и защищенные члены, как Java. В Java мне нужен статический метод, чтобы иметь возможность доступа к закрытым членам экземпляра для выполнения каких-либо задач. В Python это редко необходимо.
Обычно я вижу людей, использующих статические методы и методы классов, когда все, что им действительно нужно, это лучше использовать пространства имен на уровне модулей Python.
источник
Это позволяет вам писать универсальные методы класса, которые вы можете использовать с любым совместимым классом.
Например:
Если вы не используете,
@classmethod
вы можете сделать это с помощью ключевого слова self, но для этого нужен экземпляр Class:источник
Раньше я работал с PHP, и недавно я спрашивал себя, что происходит с этим методом класса? Руководство по Python очень техническое и очень короткое на словах, поэтому оно не поможет понять эту функцию. Я гуглил и гуглял и нашел ответ -> http://code.anjanesh.net/2007/12/python-classmethods.html .
Если вам лень кликнуть. Мое объяснение короче и ниже. :)
в PHP (может быть, не все из вас знают PHP, но этот язык настолько прост, что каждый должен понимать, о чем я говорю), у нас есть статические переменные, подобные этой:
Выход будет в обоих случаях 20.
Однако в python мы можем добавить декоратор @classmethod и, таким образом, можно получить выходные данные 10 и 20 соответственно. Пример:
Умный, не так ли?
источник
B.setInnerVar(20)
его10
опустить , он напечатает дважды (вместо того, чтобы выдавать ошибку при втором вызове echoInnerBar (), который неinner_var
был определен)Методы класса обеспечивают «семантический сахар» (не знаю, широко ли используется этот термин) или «семантическое удобство».
Пример: вы получили набор классов, представляющих объекты. Возможно, вы захотите иметь метод класса
all()
илиfind()
написатьUser.all()
илиUser.find(firstname='Guido')
. Это может быть сделано с использованием функций уровня модуля, конечно ...источник
Что меня только поразило, так это то, что так называемый метод класса и так называемый метод экземпляра - это просто функция с семантическим значением, примененная к ее первому параметру, который молча передается, когда функция вызывается как метод объект (то есть
obj.meth()
).Обычно этот объект должен быть экземпляром, но
@classmethod
декоратор метода изменяет правила для передачи класса. Вы можете вызвать метод класса в экземпляре (это просто функция) - первым аргументом будет его класс.Поскольку это просто функция , она может быть объявлена только один раз в любой заданной области (то есть в
class
определении). Следовательно, если в качестве сюрприза для Rubyist следует, что у вас не может быть метода класса и метода экземпляра с одинаковым именем .Учти это:
Вы можете позвонить
foo
на экземплярНо не в классе:
Теперь добавьте
@classmethod
:Вызов экземпляра теперь передает его класс:
как и при вызове класса:
Это единственное соглашение, которое предписывает использовать
self
этот первый аргумент в методе экземпляра иcls
в методе класса. Я не использовал ни того, ни другого, чтобы проиллюстрировать, что это просто аргумент. В Rubyself
это ключевое слово.Контраст с Ruby:
Метод класса Python - это просто декорированная функция, и вы можете использовать те же методы для создания собственных декораторов . Декорированный метод оборачивает реальный метод (в случае
@classmethod
его передачи дополнительный аргумент класса). Основной метод все еще там, скрытый, но все еще доступный .сноска: я написал это после того, как столкновение имен между классом и методом экземпляра пробудило мое любопытство. Я далеко не эксперт по Python и хотел бы комментарии, если что-то из этого не так.
источник
super()
). AFICT, «магия» происходит, когда атрибут установлен или прочитан. Вызовobj.meth(arg)
в Python (в отличие от Ruby) означает просто(obj.meth)(arg)
. Ничто молча нигде не передается,obj.meth
это просто вызываемый объект, который принимает на один аргумент меньше, чем функция, из которой он был создан.obj.meth
В свою очередь означает простоgetattr(obj, "meth")
.Это интересная тема. Я предполагаю, что метод класса Python работает как синглтон, а не как фабрика (которая возвращает произведенный экземпляр класса). Причина, по которой он является единичным, состоит в том, что существует общий объект, который создается (словарь), но только один раз для класса, но используется всеми экземплярами.
Чтобы проиллюстрировать это, вот пример. Обратите внимание, что все экземпляры имеют ссылку на один словарь. Это не Фабричный образец, насколько я понимаю. Это, вероятно, очень уникально для Python.
источник
Я задавал себе один и тот же вопрос несколько раз. И хотя ребята изо всех сил пытались это объяснить, ИМХО лучший (и самый простой) ответ, который я нашел, это описание метода Class в документации по Python.
Также есть ссылка на статический метод. И в случае, если кто-то уже знает методы экземпляра (что я предполагаю), этот ответ может быть последней частью, чтобы собрать все вместе ...
Более подробную информацию по этой теме можно найти также в документации: Стандартная иерархия типов (прокрутите вниз до раздела Методы экземпляра ).
источник
@classmethod
может быть полезен для простого создания экземпляров объектов этого класса из внешних ресурсов. Учтите следующее:Тогда в другом файле:
Доступ к inst.x даст то же значение, что и настройки ['x'].
источник
Конечно, класс определяет набор экземпляров. И методы класса работают на отдельных экземплярах. Методы класса (и переменные) - это место, где можно повесить другую информацию, связанную с множеством экземпляров.
Например, если ваш класс определяет набор учащихся, вы можете захотеть, чтобы переменные класса или методы определяли такие вещи, как набор оценок, членами которых могут быть учащиеся.
Вы также можете использовать методы класса для определения инструментов для работы со всем набором. Например, Student.all_of_em () может вернуть всех известных студентов. Очевидно, что если ваш набор экземпляров имеет больше структуры, чем просто набор, вы можете предоставить методы класса, чтобы узнать об этой структуре. Students.all_of_em (класс = 'юниоры')
Подобные методы, как правило, ведут к хранению членов набора экземпляров в структурах данных, которые коренятся в переменных класса. Вы должны позаботиться о том, чтобы не сорвать сборку мусора.
источник