Я знаю, что __call__
метод в классе запускается, когда вызывается экземпляр класса. Однако я понятия не имею, когда я смогу использовать этот специальный метод, потому что можно просто создать новый метод и выполнить ту же операцию, что и в __call__
методе, и вместо вызова экземпляра вы можете вызвать метод.
Я был бы очень признателен, если бы кто-нибудь дал мне практическое применение этого специального метода.
python
methods
call
magic-methods
mohi666
источник
источник
__call__
скрыто в простом виде; это как вы создаете экземпляр класса:x = Foo()
действительноx = type(Foo).__call__(Foo)
, где__call__
определяется метаклассомFoo
.Ответы:
Модуль форм Django
__call__
прекрасно использует метод для реализации согласованного API для проверки формы. Вы можете написать свой собственный валидатор для формы в Django как функцию.В Django есть некоторые встроенные валидаторы по умолчанию, такие как валидаторы электронной почты, валидаторы URL и т. Д., Которые в общем подпадают под валидаторы RegEx. Чтобы реализовать их чисто, Django прибегает к вызываемым классам (вместо функций). Он реализует логику Regex Validation по умолчанию в RegexValidator, а затем расширяет эти классы для других проверок.
Теперь и ваша пользовательская функция, и встроенный EmailValidator могут вызываться с одинаковым синтаксисом.
Как вы можете видеть, эта реализация в Django похожа на то, что другие объяснили в своих ответах ниже. Может ли это быть реализовано любым другим способом? Вы могли бы, но ИМХО, это не будет так же легко читаемо или так легко расширяемо для больших фреймворков, как Django.
источник
В этом примере используется запоминание , в основном хранение значений в таблице (словарь в данном случае) , так что вы можете посмотреть их позже вместо перерасчета их.
Здесь мы используем простой класс с
__call__
методом для вычисления факториалов (через вызываемый объект ) вместо функции факториала, которая содержит статическую переменную (как это невозможно в Python).Теперь у вас есть
fact
объект, который можно вызвать, как и любую другую функцию. НапримерИ это тоже с учетом состояния.
источник
fact
объект, который индексируется, поскольку ваша__call__
функция по сути является индексом. Также будет использовать список вместо dict, но это только я.__call__
, быть простым и не более того.Я считаю его полезным, поскольку он позволяет мне создавать API-интерфейсы, которые просты в использовании (у вас есть вызываемый объект, требующий определенных аргументов) и просты в реализации, поскольку вы можете использовать объектно-ориентированные практики.
Ниже приведен код, который я написал вчера, который создает версию
hashlib.foo
методов, которые хешируют целые файлы, а не строки:Эта реализация позволяет мне использовать функции аналогично
hashlib.foo
функциям:Конечно, я мог бы реализовать это по-другому, но в этом случае это казалось простым подходом.
источник
__call__
дать вам инструмент, позволяющий вам использовать ОО-методы для решения проблем.isinstance
или что-то подобное.__call__
метод вместо замыкания, - это когда вы имеете дело с многопроцессорным модулем, который использует травление для передачи информации между процессами. Вы не можете засолить замыкание, но вы можете засолить экземпляр класса.__call__
также используется для реализации классов декоратора в python. В этом случае экземпляр класса вызывается при вызове метода с декоратором.источник
Да, когда вы знаете, что имеете дело с объектами, вполне возможно (и во многих случаях желательно) использовать явный вызов метода. Однако иногда вы имеете дело с кодом, который ожидает вызываемые объекты - как правило, функции, но благодаря
__call__
вам вы можете создавать более сложные объекты, с данными экземпляра и большим количеством методов для делегирования повторяющихся задач и т. Д., Которые все еще могут вызываться.Кроме того, иногда вы используете как объекты для сложных задач (где имеет смысл написать выделенный класс), так и объекты для простых задач (которые уже существуют в функциях или легче записываются как функции). Чтобы иметь общий интерфейс, вы должны либо написать крошечные классы, обертывающие эти функции ожидаемым интерфейсом, либо оставить функции функций и сделать более сложные объекты вызываемыми. Давайте возьмем темы в качестве примера. Эти
Thread
объекты из стандартного модуля libarythreading
хотят вызываемые в качествеtarget
аргумента (т.е. как действие , которое будет сделано в новом потоке). С вызываемым объектом вы не ограничены функциями, вы также можете передавать другие объекты, например, относительно сложного работника, который получает задачи для выполнения из других потоков и выполняет их последовательно:Это всего лишь пример из головы, но я думаю, что он уже достаточно сложен, чтобы оправдать класс. Делать это только с функциями сложно, по крайней мере, это требует возврата двух функций, и это постепенно становится сложным. Один мог бы переименовать
__call__
что - то другое и передать связанный метод, но это делает код немного менее очевидно , создавая поток, и не добавляет никакой ценности.источник
__call__
использование экземпляров классов (вместо функций) в качестве приложений WSGI. Вот пример из «Полного руководства по пилонам»: Использование экземпляров классовДекораторы на основе классов используют
__call__
для ссылки на упакованную функцию. Например:Здесь есть хорошее описание различных опций на Artima.com
источник
ИМХО
__call__
метод и замыкания дают нам естественный способ создания шаблона проектирования STRATEGY в Python. Мы определяем семейство алгоритмов, инкапсулируем каждый из них, делаем их взаимозаменяемыми и, в конце концов, мы можем выполнить общий набор шагов и, например, вычислить хеш для файла.источник
Я просто наткнулся на использование
__call__()
совместно с__getattr__()
которой я думаю , что это красиво. Это позволяет скрывать несколько уровней API JSON / HTTP / (однако_serialized) внутри объекта.Эта
__getattr__()
часть обеспечивает итеративный возврат измененного экземпляра того же класса, заполняя еще один атрибут за раз. Затем, после того, как вся информация была исчерпана,__call__()
вступает во владение теми аргументами, которые вы указали.Используя эту модель, вы можете, например, сделать вызов
api.v2.volumes.ssd.update(size=20)
, который заканчивается запросом PUThttps://some.tld/api/v2/volumes/ssd/update
.Конкретный код является драйвером хранилища блоков для определенного бэкэнда тома в OpenStack, вы можете проверить его здесь: https://github.com/openstack/cinder/blob/master/cinder/volume/drivers/nexenta/jsonrpc.py
РЕДАКТИРОВАТЬ: обновил ссылку, чтобы указать на основной ревизии.
источник
Укажите
__metaclass__
и переопределите__call__
метод, и у вас есть указанные мета-классы__new__
возвращен экземпляр класса. У вас есть «функция» с методами.источник
Мы можем использовать
__call__
метод, чтобы использовать другие методы класса в качестве статических методов.источник
Одним из распространенных примеров является
__call__
infunctools.partial
, вот упрощенная версия (с Python> = 3.5):Использование:
источник
Оператор вызова функции.
Метод __call__ можно использовать для переопределения / повторной инициализации того же объекта. Это также облегчает использование экземпляров / объектов класса в качестве функций путем передачи аргументов объектам.
источник
Я нахожу хорошее место для использования вызываемых объектов, которые определяют
__call__()
, когда с помощью функциональных возможностей программирования в Python, такие какmap()
,filter()
,reduce()
.Лучшее время для использования вызываемого объекта над простой функцией или лямбда-функцией - когда логика сложна и требует сохранения какого-то состояния или использует другую информацию, которая не передана
__call__()
функции.Вот некоторый код, который фильтрует имена файлов по их расширению, используя вызываемый объект и
filter()
.Callable:
Использование:
Вывод:
источник
Это слишком поздно, но я привожу пример. Представьте, что у вас есть
Vector
класс иPoint
класс. Оба принимаютx, y
как позиционные аргументы. Представим, что вы хотите создать функцию, которая перемещает точку, которая будет помещена в вектор.4 решения
put_point_on_vec(point, vec)
Сделайте это методом на векторном классе. например
my_vec.put_point(point)
Point
классе.my_point.put_on_vec(vec)
Vector
реализует__call__
, так что вы можете использовать его какmy_vec_instance(point)
На самом деле, это часть некоторых примеров, над которыми я работаю для руководства по более сложным методам, объясненным с помощью математики, которое я собираюсь выпустить рано или поздно.
Я оставил логику перемещения самой точки, потому что это не то, о чем этот вопрос
источник