Favorite non-python language trick?

Bengt Richter bokr at oz.net
Sat Jun 25 19:08:10 EDT 2005


On Sun, 26 Jun 2005 04:08:31 +1000, Steven D'Aprano <steve at REMOVETHIScyber.com.au> wrote:

>On Fri, 24 Jun 2005 15:47:45 -0700, James Stroud wrote:
>
>> On Friday 24 June 2005 05:58 am, Steven D'Aprano wrote:
>>> with colour do begin
>>> red := 0; blue := 255; green := 0;
>>> end;
>>>
>>> instead of:
>>>
>>> colour.red := 0; colour.blue := 255; colour.green := 0;
>>>
>>> Okay, so maybe it is more of a feature than a trick, but I miss it and it
>>> would be nice to have in Python.
How do you like the following?
 >>> color = type('',(),{})() # an instance that will accept attributes
 >>> vars(color)
 {}

The single line replacing
     """
     with colour do begin
     red := 0; blue := 255; green := 0;
     end;
     """
follows:
 >>> vars(color).update(red=0, blue=255, green=0)

which sets all the attributes:
 >>> vars(color)
 {'blue': 255, 'green': 0, 'red': 0}
 >>> color.blue
 255
 >>> color.red
 0
 >>> color.green
 0

Of course, I defined a class on the fly above, so I could have given it defaults
as class variables (using English spelling ;-) :

 >>> colour = type('Colour',(),dict(red=0,blue=255,green=0))() # an instance with defaults
 >>> vars(colour)
 {}
Which don't show up in the instance dict, but do show up as attributes:
 >>> colour.red
 0
 >>> colour.green
 0
 >>> colour.blue
 255

Then we can update the instance dict that holds its attributes:
>>> vars(colour).update(red=111,green=222,blue=333)

And they show up, shadowing the class vars
>>> vars(colour)
{'blue': 333, 'green': 222, 'red': 111}

You can do one attribute this way:
>>> vars(colour).update(red='RED')
>>> vars(colour)
{'blue': 333, 'green': 222, 'red': 'RED'}

though this is obviously more concise:
>>> colour.green = 'GREEN'
>>> vars(colour)
{'blue': 333, 'green': 'GREEN', 'red': 'RED'}
>>>

The class vars are still there, even though we don't have a local name binding for the class:

 >>> map(vars(type(colour)).__getitem__, 'red green blue'.split())
 [0, 0, 255]

The instance is separate:
 >>> vars(colour)
 {'blue': 333, 'green': 'GREEN', 'red': 'RED'}

We can clear those attributes from the instance dict:
>>> vars(colour).clear()
>>> vars(colour)
{}

And then they don't shadow the class vars, so getting attributes make the class vars show again:
>>> [getattr(colour, c) for c in 'red green blue'.split()]
[0, 0, 255]

Or:
 >>> map(colour.__getattribute__, 'red green blue'.split())
 [0, 0, 255]

Actually, you could make that a few characters shorter using a temporary short name to make
a kind of with inside a list comprehension:
 >>> [[c.red, c.green, c.blue] for c in [colour]][0]
 [0, 0, 255]

Though list comprehensions leak bindings:
 >>> c
 <__main__.Colour object at 0x02F8FFCC>

Which generator expressions don't:
 >>> del c
 >>> list(([c.red, c.green, c.blue] for c in [colour]))[0]
 [0, 0, 255]
 >>> c
 Traceback (most recent call last):
   File "<stdin>", line 1, in ?
 NameError: name 'c' is not defined


Or we can get the pairs and build a dict:
>>> [(c,getattr(colour, c)) for c in 'red green blue'.split()]
[('red', 0), ('green', 0), ('blue', 255)]
>>> dict([(c,getattr(colour, c)) for c in 'red green blue'.split()])
{'blue': 255, 'green': 0, 'red': 0}

Of course, rgb is usually ordered, so why not

 >>> colour = type('Colour',(),dict(rgb=(0,255,0)))() # an instance with default rgb
 >>> vars(colour)
 {}
 >>> colour.rgb
 (0, 255, 0)
 >>> colour.rgb = 111,222,333
 >>> vars(colour)
 {'rgb': (111, 222, 333)}
 >>> colour.rgb
 (111, 222, 333)
 >>> type(colour).rgb
 (0, 255, 0)


>> 
>> class color:        # americanized
>>   red = 0
>>   blue = 255
>>   green = 0
>
>The problem is, you have made colour (returning to English spelling
>instead of foreign) into a class. If you need two colour variables, you
>have to duplicate the code for the class (perhaps only changing the
>numeric constants. You can't even make instances from the class, because
>they all share the same RGB values, which is pretty useless if they are
>meant to represent different colours.
>
> 
>> Less typing than pascal. 
>
>You have missed the point. I'm not comparing Python vs Pascal for
>creating records representing RBG values. I'm talking about a Pascal
>feature that reduced typing by allowing you to use an implicit record.
>Here is one possible way you might use such a feature as a Python idiom,
>letting "with" specify an implicit object. Instead of doing this:
>
># read a class attribute
>print myobject.__class__.myattribute  
># set an instance attribute
>myobject.widget.datapoints[myobject.collector] \
>= myobject.dispatcher(myobject.widget.current_value)
>
>you might do this:
>
>with myobject:
>    # read a class attribute
>    print .__class__.myattribute
>    # set an instance attribute
>    .widget.datapoints[.collector] = .dispatcher(.widget.current_value)
>

def mywith(o=myobject):
     # read a class attribute
     print o.__class__.myattribute
     # set an instance attribute
     o.widget.datapoints[o.collector] = o.dispatcher(o.widget.current_value)
mywith()

Or if we had a lambda-replacing anonymous def permitting full suites:
(def(o=myobject):
     # read a class attribute
     print o.__class__.myattribute
     # set an instance attribute
     o.widget.datapoints[o.collector] = o.dispatcher(o.widget.current_value)
)()

Is a one-character prefix to the dot objectionable?

>> Also avoids those stupid little colons.
>
>Using := and = for assignment and equality is precisely as stupid as using
>= and == for assignment and equality. Perhaps less stupid: why do we use
>== for equals, but not ++ for plus and -- for minus?
>
I agree, but I think := would be nice in python for RE-binding an existing
binding, wherever it is seen from the local context. Thus you could
write

    def foo(): x:=123

and
   x = 456
   def bar():
       x = 789
       foo()  # finds and rebinds local x
       print x
   bar() # -> 123
   print x # -> 456
   foo()      # finds and rebinds the global x
   print x # -> 123

but
   del x
   foo()  #-> NameError exception, can't find any x to rebind

hm, wandered a bit OT there, ;-/

Regards,
Bengt Richter



More information about the Python-list mailing list