Pleasing to see and somehow elegant. I believe .= is a good idea.
Send Python-ideas mailing list submissions to
python-ideas@python.org
To subscribe or unsubscribe via the World Wide Web, visit
https://mail.python.org/mailman/listinfo/python-ideas
or, via email, send a message with subject or body 'help' to
python-ideas-request@python.org
You can reach the person managing the list at
python-ideas-owner@python.org
When replying, please edit your Subject line so it is more specific
than "Re: Contents of Python-ideas digest..."
Today's Topics:
1. Re: "Immutable Builder" Pattern and Operator (Cory Benfield)
2. Re: "Immutable Builder" Pattern and Operator (Paul Moore)
3. Re: "Immutable Builder" Pattern and Operator (Serhiy Storchaka)
4. Re: "Immutable Builder" Pattern and Operator (Soni L.)
5. Re: "Immutable Builder" Pattern and Operator (M.-A. Lemburg)
------------------------------------------------------------ ----------
Message: 1
Date: Mon, 23 Jan 2017 09:32:02 +0000
From: Cory Benfield <cory@lukasa.co.uk>
To: "Soni L." <fakedme+py@gmail.com>
Cc: python-ideas@python.org
Subject: Re: [Python-ideas] "Immutable Builder" Pattern and Operator
Message-ID: <8671EBCA-148F-41C8-A592-46EF653B9CAE@lukasa.co.uk >
Content-Type: text/plain; charset="utf-8"
> On 22 Jan 2017, at 22:45, Soni L. <fakedme+py@gmail.com> wrote:
>
>
This pattern is present in the cryptography module already with things like their x509.CertificateBuilder: https://cryptography.io/en/latest/x509/reference/# <https://cryptography.io/en/cryptography.x509. CertificateBuilder latest/x509/reference/# >.cryptography.x509. CertificateBuilder
My 2c, but I find that code perfectly readable and legible. I don?t think a dot-equals operator would be needed.
Cory
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/ >attachments/20170123/c4e7d09f/ attachment-0001.html
------------------------------
Message: 2
Date: Mon, 23 Jan 2017 09:54:55 +0000
From: Paul Moore <p.f.moore@gmail.com>
To: "Soni L." <fakedme+py@gmail.com>
Cc: Python-Ideas <python-ideas@python.org>
Subject: Re: [Python-ideas] "Immutable Builder" Pattern and Operator
Message-ID:
<CACac1F9CcDEyNuvGBSNSpm+U0=VQNaN9Yd-Mgj+q_Uk16gxGfQ@mail. >gmail.com
Content-Type: text/plain; charset=UTF-8
On 22 January 2017 at 22:45, Soni L. <fakedme+py@gmail.com> wrote:
> I've been thinking of an Immutable Builder pattern and an operator to go
> with it. Since the builder would be immutable, this wouldn't work:
>
> long_name = mkbuilder()
> long_name.seta(a)
> long_name.setb(b)
> y = long_name.build()
>
> Instead, you'd need something more like this:
>
> long_name = mkbuilder()
> long_name = long_name.seta(a)
> long_name = long_name.setb(b)
> y = long_name.build()
>
> Or we could add an operator to simplify it:
>
> long_name = mkbuilder()
> long_name .= seta(a)
> long_name .= setb(b)
> y = long_name.build()
>
> (Yes, I'm aware you can x = mkbuilder().seta(a).setb(b), then y = x.build().
> But that doesn't work if you wanna "fork" the builder. Some builders, like a
> builder for network connections of some sort, would work best if they were
> immutable/forkable.)
I don't think the .= operator adds enough to be worth it. If the
problem you see is the duplication of long_name in those lines (it's
difficult to be sure without a real example) then you can use a
temporary:
b = mkbuilder()
b = b.seta(a)
b = b.setb(b)
long_name = b
y = long_name.build()
For your real example:
On 22 January 2017 at 23:30, Soni L. <fakedme+py@gmail.com> wrote:
> fnircbotbuilder = mkircbotbuilder(network="irc.freenode.net ", port=6697,
> ssl=true)
> mainbot = mkircbotbuilder(parent=fnircbotbuilder, # ???
> channels=["#bots"]).build()
> fndccbotbuilder = mkircbotbuilder(parent=fnircbotbuilder, dcc=true,
> channeldcc=true)
> dccbot = mkircbotbuilder(parent=fndccbotbuilder,
> channels=["#ctcp-s"]).build()
> otherircbotbuilder = mkircbotbuilder(parent=fndccbotbuilder,
> network="irc.subluminal.net") # because we want this whole network
> otherbot = mkircbotbuilder(parent=otherircbotbuilder,
> channels=["#programming"]).build() # to use DCC and channel DCC
>
> But this would be cleaner:
>
> botbuilder =
> mkircbotbuilder().network("irc.freenode.net ").port(6697).ssl(true)
> mainbot = botbuilder.channels(["#bots"]).build()
> botbuilder .= dcc(true).channeldcc(true)
> dccbot = botbuilder.channels(["#ctcp-s"]).build()
> botbuilder .= network("irc.subluminal.net")
> otherbot = botbuilder.channels(["#programming"]).build()
I don't find the second example appreciably cleaner than the first.
But a bit of reformatting looks better to me:
# First create builders for the bots
fnircbotbuilder = mkircbotbuilder(
network="irc.freenode.net",
port=6697,
ssl=true)
fndccbotbuilder = mkircbotbuilder(
parent=fnircbotbuilder,
dcc=true,
channeldcc=true)
otherircbotbuilder = mkircbotbuilder(
parent=fndccbotbuilder,
network="irc.subluminal.net")
# Now create the actual bots
mainbot = mkircbotbuilder(
parent=fnircbotbuilder,
channels=["#bots"]).build()
dccbot = mkircbotbuilder(
parent=fndccbotbuilder,
channels=["#ctcp-s"]).build()
otherbot = mkircbotbuilder(
parent=otherircbotbuilder,
channels=["#programming"]).build()
And some API redesign (make the builders classes, and the parent
relationship becomes subclassing, and maybe make channels an argument
to build() so that you don't need fresh builders for each of the
actual bots, and you don't even need the "builder" in the name at this
point) makes the whole thing look far cleaner (to me, at least):
class FNIRCBot(IRCBot):
network="irc.freenode.net"
port=6697
ssl=True
class FNDCCBot(FNIRCBot):
dcc=True
channeldcc=True
class OtherIRCBot(IRCBot):
network="irc.subluminal.net"
mainbot = FNIRCBot(channels=["#bots"])
dccbot = FNDCCBot(channels=["#ctcp-s"])
otherbot = OtherIRCBot(channels=["#programming"])
Paul
------------------------------
Message: 3
Date: Mon, 23 Jan 2017 13:45:18 +0200
From: Serhiy Storchaka <storchaka@gmail.com>
To: python-ideas@python.org
Subject: Re: [Python-ideas] "Immutable Builder" Pattern and Operator
Message-ID: <o64qc9$k3q$1@blaine.gmane.org>
Content-Type: text/plain; charset=windows-1252; format=flowed
On 23.01.17 01:30, Soni L. wrote:
> On 22/01/17 08:54 PM, Serhiy Storchaka wrote:
>> On 23.01.17 00:45, Soni L. wrote:
>>> I've been thinking of an Immutable Builder pattern and an operator to go
>>> with it. Since the builder would be immutable, this wouldn't work:
>>>
>>> long_name = mkbuilder()
>>> long_name.seta(a)
>>> long_name.setb(b)
>>> y = long_name.build()
>>
>> I think the more pythonic way is:
>>
>> y = build(a=a, b=b)
>>
>> A Builder pattern is less used in Python due to the support of keyword
>> arguments.
>
> I guess you could do something like this, for an IRC bot builder:
>
> fnircbotbuilder = mkircbotbuilder(network="irc.freenode.net ", port=6697,
> ssl=true)
> mainbot = mkircbotbuilder(parent=fnircbotbuilder, # ???
> channels=["#bots"]).build()
> fndccbotbuilder = mkircbotbuilder(parent=fnircbotbuilder, dcc=true,
> channeldcc=true)
> dccbot = mkircbotbuilder(parent=fndccbotbuilder,
> channels=["#ctcp-s"]).build()
> otherircbotbuilder = mkircbotbuilder(parent=fndccbotbuilder,
> network="irc.subluminal.net") # because we want this whole network
> otherbot = mkircbotbuilder(parent=otherircbotbuilder,
> channels=["#programming"]).build() # to use DCC and channel DCC
>
> But this would be cleaner:
>
> botbuilder =
> mkircbotbuilder().network("irc.freenode.net ").port(6697).ssl(true)
> mainbot = botbuilder.channels(["#bots"]).build()
> botbuilder .= dcc(true).channeldcc(true)
> dccbot = botbuilder.channels(["#ctcp-s"]).build()
> botbuilder .= network("irc.subluminal.net")
> otherbot = botbuilder.channels(["#programming"]).build()
In Python you can save common options in a dict and pass them as
var-keyword argument. Or use functools.partial. In any case you don't
need a builder class with the build method and a number of configuring
methods. It can be just a function with optional keyword parameters.
A Builder pattern is often used in languages that don't support passing
arguments by keyword and partial functions. Python rarely needs the
purposed class implementing a Builder pattern. Actually a Builder
pattern is built-in in the language as a part of syntax.
------------------------------
Message: 4
Date: Mon, 23 Jan 2017 11:05:12 -0200
From: "Soni L." <fakedme+py@gmail.com>
To: python-ideas@python.org
Subject: Re: [Python-ideas] "Immutable Builder" Pattern and Operator
Message-ID: <e9f1547f-c5a6-045a-8716-7669a1662b32@gmail.com >
Content-Type: text/plain; charset=windows-1252; format=flowed
On 23/01/17 09:45 AM, Serhiy Storchaka wrote:
> On 23.01.17 01:30, Soni L. wrote:
>> On 22/01/17 08:54 PM, Serhiy Storchaka wrote:
>>> On 23.01.17 00:45, Soni L. wrote:
>>>> I've been thinking of an Immutable Builder pattern and an operator
>>>> to go
>>>> with it. Since the builder would be immutable, this wouldn't work:
>>>>
>>>> long_name = mkbuilder()
>>>> long_name.seta(a)
>>>> long_name.setb(b)
>>>> y = long_name.build()
>>>
>>> I think the more pythonic way is:
>>>
>>> y = build(a=a, b=b)
>>>
>>> A Builder pattern is less used in Python due to the support of keyword
>>> arguments.
>>
>> I guess you could do something like this, for an IRC bot builder:
>>
>> fnircbotbuilder = mkircbotbuilder(network="irc.freenode.net ", port=6697,
>> ssl=true)
>> mainbot = mkircbotbuilder(parent=fnircbotbuilder, # ???
>> channels=["#bots"]).build()
>> fndccbotbuilder = mkircbotbuilder(parent=fnircbotbuilder, dcc=true,
>> channeldcc=true)
>> dccbot = mkircbotbuilder(parent=fndccbotbuilder,
>> channels=["#ctcp-s"]).build()
>> otherircbotbuilder = mkircbotbuilder(parent=fndccbotbuilder,
>> network="irc.subluminal.net") # because we want this whole network
>> otherbot = mkircbotbuilder(parent=otherircbotbuilder,
>> channels=["#programming"]).build() # to use DCC and channel DCC
>>
>> But this would be cleaner:
>>
>> botbuilder =
>> mkircbotbuilder().network("irc.freenode.net ").port(6697).ssl(true)
>> mainbot = botbuilder.channels(["#bots"]).build()
>> botbuilder .= dcc(true).channeldcc(true)
>> dccbot = botbuilder.channels(["#ctcp-s"]).build()
>> botbuilder .= network("irc.subluminal.net")
>> otherbot = botbuilder.channels(["#programming"]).build()
>
> In Python you can save common options in a dict and pass them as
> var-keyword argument. Or use functools.partial. In any case you don't
> need a builder class with the build method and a number of configuring
> methods. It can be just a function with optional keyword parameters.
>
> A Builder pattern is often used in languages that don't support
> passing arguments by keyword and partial functions. Python rarely
> needs the purposed class implementing a Builder pattern. Actually a
> Builder pattern is built-in in the language as a part of syntax.
>
Yeah but the dotequals operator has many other benefits:
long_name .= __call__ # cast to callable
long_name .= wrapped # unwrap
etc
And it also looks neat.
------------------------------
Message: 5
Date: Mon, 23 Jan 2017 14:18:18 +0100
From: "M.-A. Lemburg" <mal@egenix.com>
To: "Soni L." <fakedme+py@gmail.com>, python-ideas@python.org
Subject: Re: [Python-ideas] "Immutable Builder" Pattern and Operator
Message-ID: <0654a27e-7200-c468-d4eb-17bef13b61d2@egenix.com >
Content-Type: text/plain; charset=windows-1252
On 23.01.2017 14:05, Soni L. wrote:
>
>
> On 23/01/17 09:45 AM, Serhiy Storchaka wrote:
>> On 23.01.17 01:30, Soni L. wrote:
>>> On 22/01/17 08:54 PM, Serhiy Storchaka wrote:
>>>> On 23.01.17 00:45, Soni L. wrote:
>>>>> I've been thinking of an Immutable Builder pattern and an operator
>>>>> to go
>>>>> with it. Since the builder would be immutable, this wouldn't work:
>>>>>
>>>>> long_name = mkbuilder()
>>>>> long_name.seta(a)
>>>>> long_name.setb(b)
>>>>> y = long_name.build()
>>>>
>>>> I think the more pythonic way is:
>>>>
>>>> y = build(a=a, b=b)
>>>>
>>>> A Builder pattern is less used in Python due to the support of keyword
>>>> arguments.
>>>
>>> I guess you could do something like this, for an IRC bot builder:
>>>
>>> fnircbotbuilder = mkircbotbuilder(network="irc.freenode.net ", port=6697,
>>> ssl=true)
>>> mainbot = mkircbotbuilder(parent=fnircbotbuilder, # ???
>>> channels=["#bots"]).build()
>>> fndccbotbuilder = mkircbotbuilder(parent=fnircbotbuilder, dcc=true,
>>> channeldcc=true)
>>> dccbot = mkircbotbuilder(parent=fndccbotbuilder,
>>> channels=["#ctcp-s"]).build()
>>> otherircbotbuilder = mkircbotbuilder(parent=fndccbotbuilder,
>>> network="irc.subluminal.net") # because we want this whole network
>>> otherbot = mkircbotbuilder(parent=otherircbotbuilder,
>>> channels=["#programming"]).build() # to use DCC and channel DCC
>>>
>>> But this would be cleaner:
>>>
>>> botbuilder =
>>> mkircbotbuilder().network("irc.freenode.net ").port(6697).ssl(true)
>>> mainbot = botbuilder.channels(["#bots"]).build()
>>> botbuilder .= dcc(true).channeldcc(true)
>>> dccbot = botbuilder.channels(["#ctcp-s"]).build()
>>> botbuilder .= network("irc.subluminal.net")
>>> otherbot = botbuilder.channels(["#programming"]).build()
>>
>> In Python you can save common options in a dict and pass them as
>> var-keyword argument. Or use functools.partial. In any case you don't
>> need a builder class with the build method and a number of configuring
>> methods. It can be just a function with optional keyword parameters.
>>
>> A Builder pattern is often used in languages that don't support
>> passing arguments by keyword and partial functions. Python rarely
>> needs the purposed class implementing a Builder pattern. Actually a
>> Builder pattern is built-in in the language as a part of syntax.
>>
> Yeah but the dotequals operator has many other benefits:
>
> long_name .= __call__ # cast to callable
> long_name .= wrapped # unwrap
> etc
>
> And it also looks neat.
I don't see this an being a particular intuitive way of writing
such rather uncommon constructs.
The syntax is not clear (what if you have an expression on the RHS)
and it doesn't save you much in writing (if long_name is too long
simply rebind it under a shorter name for the purpose of the code
block).
Also note that rebinding different objects to the same name
in the same block is often poor style and can easily lead to
hard to track bugs.
--
Marc-Andre Lemburg
eGenix.com
Professional Python Services directly from the Experts (#1, Jan 23 2017)
>>> Python Projects, Coaching and Consulting ... http://www.egenix.com/
>>> Python Database Interfaces ... http://products.egenix.com/
>>> Plone/Zope Database Interfaces ... http://zope.egenix.com/
____________________________________________________________ ____________
::: We implement business ideas - efficiently in both time and costs :::
eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48
D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg
Registered at Amtsgericht Duesseldorf: HRB 46611
http://www.egenix.com/company/contact/
http://www.malemburg.com/
------------------------------
Subject: Digest Footer
_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
------------------------------
End of Python-ideas Digest, Vol 122, Issue 81
*********************************************