[Python-ideas] Tulip / PEP 3156 - subprocess events

Greg Ewing greg.ewing at canterbury.ac.nz
Sat Jan 19 07:05:35 CET 2013


Glyph wrote:
> I think that some Python 
> programmers have an aversion to factories because a common path to 
> Python is flight from Java environments that over- or mis-use the 
> factory pattern.

I'm not averse to using the factory pattern when it genuinely
helps. I'm questioning whether it helps enough in this case
to be worth using.

> Guido mentioned one advantage already; you don't have to create the 
> protocol object if the connection fails, so your protocol objects are 
> real honest-to-goodness connections, not "well, maybe there's a 
> connection or maybe there'll be a connection later".

I would suggest that merely instantiating a protocol object
should be cheap enough that you don't normally care. Any
substantive setup work should be done in the connection_made()
method, not in __init__().

Transports are already a "maybe there's a connection" kind of
deal, otherwise why does connection_made() exist at all?

> if the client wants to issue 
> a client greeting, it should not have access to its half-formed 
> transport before that failure.  Of course, it's possible to present an 
> API that works around this by buffering writes issued before the 
> connection is established, and by the protocol waiting for the 
> connection_made callback before actually doing its work.

Which it seems to me is the way *all* protocols should be
written. If necessary, you could "encourage" people to write
them this way by having a transport refuse to accept any
writes until the connection_made() call has occurred.

> However, aside from the factory-or-not issue, the fact that 
> TCPTransport's name implies that it is both (1) a class and (2) the 
> actual transport implementation, is more problematic.

They don't have to be classes, they could be functions:

    create_http_protocol(create_tcp_transport("hammerme.seeificare.com", 80))

The important thing is that each function concerns itself
with just one step of the chain, and chains of any length
can be constructed by composing them in the obvious way.

> Your example is misleadingly named; surely you mean TCP*Client*, because 
> a TCP*Transport* would implicitly support both clients and servers - and 
> a server would start with a socket returned from accept(), not a host 
> and port.

Maybe. Or maybe the constructor could be called in more than one
way -- create_tcp_transport(host, port) on the client side and
create_tcp_transport(socket) on the server side.
> 
> create_connection will actually need to create multiple sockets 
> internally.  See <http://tools.ietf.org/html/rfc3493> covers this, in 
> part (for a more condensed discussion, see 
> <https://twistedmatrix.com/trac/ticket/4859>).

Couldn't all that be handled inside the transport?

> I've written layered protocols over and 
> over again in Twisted and never wanted to manually construct the bottom 
> transport for that reason.

So what does the code for setting up a multi-layer stack look
like? How does it make use of create_connection()?

Also, what does an implementation of create_connection() look
like that avoids creating the protocol until the connection is
made? It seems tricky, because the way you know the connection
is made is that it calls connection_made() on the protocol.

But there's no protocol yet. So you would have to install a
temporary protocol whose connection_made() creates the real
protocol. That sounds like it could be even more overhead than
just creating the real protocol in the first place, as long
as the protocol doesn't do any work until its connection_made()
is called.

-- 
Greg



More information about the Python-ideas mailing list