tkbe

June 14, 2007

emacs :: autocompletion and code-commenting

Filed under: python, emacs — tb @ 6:29 pm

I’m a believing member in the church of emacs, and in honor of the new release I went looking for solutions to a couple of outstanding issues I’ve had with my emacs installation.

Today’s first emacs find is M-; which, although undocumented, works excellently to comment and uncomment code blocks in Python (it had puzzled me for a while that the comment-block command on the Python menu was C-c # and that there was no mapping for the uncomment command). The M-; command works in a plethora of other modes as well to comment and uncomment blocks.

The second emacs treasure I found today was how to turn on autocompletion. Not the mind-numbingly annoying kind that some editors have that pops up and obscures half your program whenever you type a key, but rather cycling through options when pressing M-RET. To enable it, simply put this in your .emacs file:

(define-key global-map (read-kbd-macro "M-RET") 'hippie-expand)

Searching for some info on hippie-expand, I ran into dabbrev-expand which is bound to M-/. I couldn’t tell you what the difference is, but the ESC-Enter combination is easier to find blindfolded so that’s what I’m going with.

May 19, 2007

OpenID

Filed under: it — tb @ 5:26 pm

I was checking out a number of 37signals’ webapps today (Highrise, Basecamp, and a few others… well worth a look). When I discovered I could sign in with OpenID. After a little googling and watching an excellent screencast over at Simon Willisons weblog, I figured out what it was and managed to turn my other site into an OpenID for myself. I might take a stab at implementing OpenID login for the site I’m working on, although it might not be the right audience… So what is it, you ask? Go watch the screencast, it explains it better than I ever could :-)

April 18, 2007

Python :: property set

Filed under: python — tb @ 11:11 am

It looks like Python is getting tuples with named members in 2.6(http://www.oluyede.org/blog/2007/03/11/updates-from-python-svn-part-2/ and http://docs.python.org/dev/lib/named-tuple-factory.html). I suspect many of us have implemented similar functionality ourselves, e.g. Shannon -jj Behrens describes how he sometimes uses dictionaries to return composite polymorphic values (http://jjinux.blogspot.com/2007/03/python-returning-multiple-things-of.html). The problem with dictionaries is of course that they require too much excercise of your little finger in typing ['xx']. That's even worse for me since I'm using a keyboard layout that switches national characters onto those keys when I tap the caps-lock key, so I can use my American-keyboard touch typing skillz and eat my national characters as well (I'm looking forward to the Metaphor-off!)

It looks like the new Python NamedTuple type is going to limit the fields to those that are defined at creation time. It's based on a tuple, so I suppose that follows naturally, however it doesn't seem natural for the abstract-data-type of a container of named fields with iteration and indexing. I've called my implementation of this ADT a property set since most of the motivating use cases for this was returning returning values that had properties attached to them. The use is as follows...

You can assign to random fields, the only limitation is that they cannot start with an underscore, but public fields wouldn't have that anyway so it's not really a limitation (the limitation comes from the fact that the implementation overrides __setattr__ and being able to interpret fields starting with an underscore as internal to the implementation simplifies things quite a bit):

PYTHON:
  1. >>> p = pset()
  2. >>> p.a = 42
  3. >>> p.b = 'hello'
  4. >>> p.c = [p.a, p.b]
  5. >>> p
  6. pset(a=42, b='hello', c=[42, 'hello'])

You can iterate over the values:

PYTHON:
  1. >>> for key, value in p:
  2. ...     print key, value
  3. ...
  4. a 42
  5. b hello
  6. c [42, 'hello']

Notice that it maintains the insertion order, and you can also access by index:

PYTHON:
  1. >>> p[1]
  2. 'hello'

For technical reasons it is not possible to maintain the order when creating a pset from keyword arguments (I was hesitating to put this functionality in, but practicality beats purity, and it's turned out to be very practical). Equality does not require isomorphism, which means that as long as the sets have the same fields they compare equal:

PYTHON:
  1. >>> q = pset(a=42, b='hello', c=[42,'hello'])
  2. >>> q
  3. pset(a=42, c=[42, 'hello'], b='hello')
  4. >>> p == q
  5. True

You can keep the order given to the constructor by initializing with a list of tuples:

PYTHON:
  1. >>> list(p.items())
  2. [('a', 42), ('b', 'hello'), ('c', [42, 'hello'])]
  3. >>> r = pset(p.items())
  4. >>> r
  5. pset(a=42, b='hello', c=[42, 'hello'])

The example above does of course not mean that you can't create a pset from a pset directly (this also maintains order):

PYTHON:
  1. >>> s = pset(p)
  2. >>> s
  3. pset(a=42, b='hello', c=[42, 'hello'])

It's also extremely useful to be able to use field indexing notation as well:

PYTHON:
  1. >>> p
  2. pset(a=42, b='hello', c=[42, 'hello'])
  3. >>> p.b
  4. 'hello'
  5. >>> p[1]
  6. 'hello'
  7. >>> p['b']
  8. 'hello'
  9. >>> p['b'] = 'world'
  10. >>> p
  11. pset(a=42, b='world', c=[42, 'hello'])
  12. >>> p[1] = 'foo'
  13. >>> p
  14. pset(a=42, b='foo', c=[42, 'hello'])

Here's the code:

PYTHON:
  1. class pset(dict):
  2.     """This code is placed in the Public Domain.
  3.    
  4.        Property Set class.
  5.        A property set is an object where values are attached to attributes,
  6.        but can still be iterated over as key/value pairs.
  7.        The order of assignment is maintained during iteration.
  8.        Only one value allowed per key.
  9.         >>> x = pset()
  10.         >>> x.a = 42
  11.         >>> x.b = 'foo'
  12.         >>> x.a = 314
  13.         >>> x
  14.          pset(a=314, b='foo')
  15.     """
  16.     def __init__(self, items=(), **attrs):
  17.         object.__setattr__(self, '_order', [])
  18.         super(pset, self).__init__()
  19.         for k, v in items:
  20.             self.add(k, v)
  21.         for k, v in attrs.items():
  22.             self.add(k, v)
  23.  
  24.     def add(self, key, value):
  25.         if type(key) in (int, long):
  26.             key = self._order[key]
  27.         elif key not in self._order:
  28.             self._order.append(key)
  29.         dict.__setitem__(self, key, value)
  30.  
  31.     def __eq__(self, other):
  32.         """Equal iff they have the same set of keys, and the values for
  33.            each key is equal. Key order is not considered for equality.
  34.         """
  35.         if set(self._order) == set(other._order):
  36.             for key in self._order:
  37.                 if self[key] != other[key]:
  38.                     return False
  39.             return True
  40.         return False
  41.  
  42.     def __iadd__(self, other):
  43.         for k, v in other:
  44.             self.add(k, v)
  45.  
  46.     # should probably have an __radd__ method too...
  47.     def __add__(self, other):
  48.         tmp = self.__class__()
  49.         tmp += self
  50.         tmp += other
  51.         return tmp
  52.  
  53.     def __repr__(self):
  54.         vals = ', '.join('%s=%s' % (k, repr(v)) for (k,v) in self)
  55.         return '%s(%s)' % (self.__class__.__name__, vals)
  56.  
  57.     def __getattr__(self, key):
  58.         if key not in self:
  59.             raise AttributeError(key)
  60.         return self.get(key)
  61.  
  62.     def __getitem__(self, key):
  63.         if type(key) in (int, long):
  64.             key = self._order[key]
  65.         return self.get(key)
  66.    
  67.     __str__ = __repr__
  68.  
  69.    
  70.     def __iter__(self):
  71.         return ((k, self.get(k)) for k in self._order)
  72.  
  73.     def items(self):
  74.         return iter(self)
  75.  
  76.     def __setattr__(self, key, val):
  77.         if key.startswith('_'):
  78.             object.__setattr__(self, key, val)
  79.         else:
  80.             self.add(key, val)
  81.  
  82.     def __setitem__(self, key, val):
  83.         self.add(key, val)

« Previous PageNext Page »

Powered by WordPress