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