Cut-rate cascades [was Re: While everyone is saying what they want in Python :)]
Nick Mathewson
nickm at mit.edu
Mon Feb 5 12:03:02 EST 2001
On Mon, 05 Feb 2001 00:10:39 -0500, Peter Hansen <peter at engcorp.com> wrote:
>Dan Parisien wrote:
>>
>> Peter Hansen wrote:
>>
>> > Jay O'Connor wrote:
>> > >
>> > > Smalltalk-style cascade operations would be *very* cool
>> > >
>[snip]
>> >
>> > Why? 'Cause it saves a bit of typing?
>>
>> YES!!!
>>
>> That is not a good enough reason not to add a feature like this :)
>
>Absolutely not. Look at http://www.pauahtun.org/TYPython/PythonWay.html
>for some concise reasons why (scroll to the bottom).
>
>As Erik Max wrote in another response, clarity of code is more
>important than quantity of keystrokes.
OTOH, if you really want cascades, you can do something like this:
from types import StringType
def with1(obj, *commands):
for command in commands:
if type(command) == StringType:
attribute, arguments = command, ()
else:
attribute, arguments = command[0], command[1:]
getattr(obj, attribute).(*arguments)
return obj
win = with1(GtkWindow(),
('connect', "destroy", mainquit),
('set_name', "window"),
('set_title', "My Window"),
('set_location', 100, 100),
('add', with1(GtkHBox(),
('add', with1(GtkLabel("Hi There"),
("show"))),
('add', with1(GtkButton("Push Me"),
("connect","clicked",buttonClicked))),
('show'))),
('show'))
===================================
Or, if you absolutely _must_ evaluate all the withs in order:
class lazy:
pass
class lazywith(lazy):
def __init__(self, initializer, *commands):
self.initializer = initializer
self.commands = commands
def __call__(self):
if type(self.initializer) == ClassType:
obj = self.initializer()
else:
obj = self.initializer[0](initializer[1:])
for command in commands:
if type(command) == StringType:
attribute, arguments = command, ()
else:
attribute, arguments = command[0], command[1:]
arguments = [ isinstance(arg, lazy) and arg() or arg
for arg in arguments ]
getattr(obj, attribute).(*arguments)
return obj
win = lazywith(GtkWindow,
('connect', "destroy", mainquit),
('set_name', "window"),
('set_title', "My Window"),
('set_location', 100, 100),
('add', lazywith(GtkHBox,
('add', lazywith( (GtkLabel, "Hi There"),
("show"))),
('add', lazywith( (GtkButton, "Push Me"),
("connect","clicked",buttonClicked))),
('show'))),
('show')) ()
===================================
Or, if you think a pretty syntax is important:
class _LazyCall(lazy):
def __init__(self,func, *args, **kwargs):
self.func = func
self.args = args
self.kwargs = kwarfs
def __call__(self, target):
func = getattr(target, self.func)
args = []
for arg in self.args:
if isinstance(arg, lazy):
args.append(arg())
else:
args.append(arg)
for key, val in self.kwargs.items():
if isinstance(val, lazy):
self.kwargs[key] = val()
return func(*args, **self.kwargs)
class WithFunction
def __init__(self,func):
self.func = func
def __call__(self,*args,**kwargs):
return _LazyCall(self.func, *args, **kwargs)
class WithWrapper:
def __getattr__(self, attr):
return WithFunction(attr)
class with3(lazy):
def __init__(self, initializer, *commands):
self.initializer = initializer
self.commands = commands
def __call__(self):
if isinstance(self.initializer, lazy):
obj = self.initializer()
else:
obj = self.initializer
for command in commands:
assert isinstance(command, _LazyCall)
command(obj)
return obj
W = WithWrapper()
win = with3(W.GtkWindow(),
W.connect("destroy", mainquit),
W.set_name("window"),
W.set_title("My Window"),
W.set_location(100,100),
W.add( with3( W.GtkHBox(),
W.add( with3( W.GtkLabel("Hi There"),
W.show())),
W.add( with3( W.GtkButton("Push Me"),
W.connect("clicked", buttonClicked),
W.show())),
W.show())),
W.show()) ()
===================================
Rewrite-with-nested-scopes-for-extra-credit-ly Y'rs,
--
Nick Mathewson <nickm at alum dot mit dot edu>
More information about the Python-list
mailing list