Comments 34
Не читал статью, тк не интересен питон, но картинка весьма оригинально подобрана =)
-59
Очевидный недостаток — применимо только для методов, которые либо всегда возвращают None, либо всегда возвращают объект.
Метод типа такого оборачивать небезопасно:
def getChild(name):
return self.internalDict.get(name)
(да, можно спорить о том, что вместо None нужно вернуть null-object, но… все Non'ы замучаешься оборачивать)
Ну и в целом (имхо) недостаток метода в том, что он размывает границы между mutable и immutable объектами: читая код, неочевидно, вызываются ли все add,mul на одном объекте либо на цепочке созданных объектов.
Для похожего можно еще varargs использовать, здесь пример:
stackoverflow.com/questions/3883907/designing-an-python-api-fluent-interface-or-arguments
Вместо
vis = new pv.Panel().width(150).height(150);
использовать
vis = pv.Panel(width=150, height=150)
Метод типа такого оборачивать небезопасно:
def getChild(name):
return self.internalDict.get(name)
(да, можно спорить о том, что вместо None нужно вернуть null-object, но… все Non'ы замучаешься оборачивать)
Ну и в целом (имхо) недостаток метода в том, что он размывает границы между mutable и immutable объектами: читая код, неочевидно, вызываются ли все add,mul на одном объекте либо на цепочке созданных объектов.
Для похожего можно еще varargs использовать, здесь пример:
stackoverflow.com/questions/3883907/designing-an-python-api-fluent-interface-or-arguments
Вместо
vis = new pv.Panel().width(150).height(150);
использовать
vis = pv.Panel(width=150, height=150)
+2
Для процессинга картинок и подобных операций лично мне понравилась идея с Pipe-ами. Этот подход позволяет не трогать реализацию самих классов.
И с getParent/getChild() вы верно заметили. Я бы лучше использовал второй вариант с декоратором: по крайней мере в моём коде потом не запутаются…
И с getParent/getChild() вы верно заметили. Я бы лучше использовал второй вариант с декоратором: по крайней мере в моём коде потом не запутаются…
0
varargs не подходит, если важен порядок операций:
$('#foo').slideUp(300).delay(800).fadeIn(400).delay(800);
0
if fn and type(fn)==MethodType
стоило бы заменить на isinstance(fn, MethodType)
.А по делу — хорошая демонстрация развития идеи и возможностей Пайтона :)
+1
Вы бы рассказали, что это за интерфейсы такие, текучие. Не все читали статью про PHP.
+3
Метод с дек@ратором гораздо лучше, потому что explicit is better than implicit. Имхо.
+11
Тоже считаю, что лучше уж написать 10 «собачек», чем портить себе карму отзывами будущих поколений.
+1
Раз уж речь зашла о Python-way, то не лучше ли будет просто дописать «return self» в конце каждой функции? Цена тому — все таже одна строка кода, зато простоту понимания сторонним читателем повысит неимоверно, нежели декоратор.
+1
Вставьте ссылку на статью про текучие интерфейсы на PHP в первое предложение поста, пожалуйста!
+3
Спасибо за статью! Добавьте, пожалуйста, пример реализации в википедию (текучие интерфейсы), а то там примеры на java, cpp, etc. есть, а на python нет.
+1
аццкий сотона. все конечно весело и красиво, но не дай бог потом поддерживать и фиксить такой код в проекта с овер 200К строк кода, когда измениться апи, конструкции и версии
+1
способ 3 можно чуть модифицировать — если item.startswith('fl') оборачивать метод без 'fl' в fluent обертку, тогда при необходимости можно любой метод вызвать как текучий с сохранением доступа к основному «по умолчанию».
Хотим — пишем как:
а хотим,
Хотим — пишем как:
instance.add(5)
instance.mul(3)
а хотим,
instance.fladd(5).flmul(3)
0
Очевидный недостаток — мы не можем использовать __getattribute__ в своих целях.Не понял, разве с помощью super() это не решается?
0
Можно на Ruby так подмешать, например… хотя смысла мало.
module Chaining
def included(base)
base.class_eval do
instance_methods.each do |method|
alias "#{method}_without_chain" method
define_method method do |*args, &block|
r = block_given? ? send("#{method}_without_chain", *args, &block) : send("#{method}_without_chain", *args)
return self if r.nil?
r
end
end
end
end
end
ThingBase.class_eval { include Chaining }
0
Третий способ от второго чем отличается-то? Ничем. Правильно как? Правильно искать методы в dict и замещать их на chained версии.
И почему вы каждый раз оборачиваете метод? Скорость работы себе представляете?
И почему вы каждый раз оборачиваете метод? Скорость работы себе представляете?
+1
плюс в карму за первое предложение! :) ну и за статью отдельное спасибо!
0
UFO just landed and posted this here
на вкус и цвет фломастеры разные, а вообще тут дело семантики. я на пхп делал мини-валидатор с FI по типу
$validator->validate($data,$rule)->validate($data,$rule)->isValid(); (проверка на корректность всех данных). Имхо очень удобно
$validator->validate($data,$rule)->validate($data,$rule)->isValid(); (проверка на корректность всех данных). Имхо очень удобно
0
как то так можно:
Например, я в SQLAlchemy запросы пишу таким образом
dev = (
Device.init(port=Configs.dispenser_port, baudrate=Configs.dispenser_baudrate)
.test(donors=[0,1], destination=[-1])
.dispense(amount=100, donors=[0])
.disconnect())
Например, я в SQLAlchemy запросы пишу таким образом
users_jets = (
s.query(User, UserJet)
.join((UserJet, User.current_jet_id == UserJet.id))
.filter(User.id.in_(players_ids))
.all())
0
UFO just landed and posted this here
>Не очевидно, что метод test может принадлежать не классу Device (например, Device.init может возвращать объект Dispenser). А выглядит это так, будто Device.test существует.
определяющим фактором для fluent интерфейсов является сохранение контекста между вызовами методов (т.е. то, что метод возвращает self, а не что-то другое). поэтому en.wikipedia.org/wiki/Law_of_Demeter не нарушается и ни какой путаницы быть не может.
по большому счёту, смысл всей этой затеи состоит в том, чтобы упростить выражение, «вынеся за скобки» повторяющееся имя переменной. такое повторение часто получается при конфигурировании объектов.
существуют примеры реализации данного паттерна на уровне языка. например в VisualBasic, где программисты проводят массу времени, занимаясь конфигрурированием объектов:
With testObject
.Height = 100
.Text = "Hello, World"
.ForeColor = System.Drawing.Color.Green
.Font = New System.Drawing.Font(.Font, System.Drawing.FontStyle.Bold)
End With
0
Осталось ещё сравнить производительность всех вариантов. Выиграет наверняка только первый. Ибо всякие фокусы и манипуляции со строками, словаярями и метаинформацией затратны.
0
Вот забавная штука на эту тему
github.com/JulienPalard/Pipe
github.com/JulienPalard/Pipe
>>> from pipe import *
>>> [1, 2, 3, 4, 5, 6] | average
3.5
0
Only those users with full accounts are able to leave comments. Log in, please.
Организация текучих (fluent) интерфейсов в Python