Taming Skype on Snow Leopard

After upgrading to Snow Leopard, Skype stopped working (even with latest version of Skype). I've realized in these situations the best thing is just to nuke everything and start fresh. To do this:

  1. Delete /Applications/Skype.app
  2. Open Terminal.app and type the following
    rm -r Library/Application\ Support/Skype
    rm -r Library/Preferences/com.skype.skype.plist

  3. Re-install Skype.app

Ruby's Symbol#to_proc in Python (Partial Implementation)

Ruby is a great little language, and when I'm not programming in Ruby, I sometimes miss some of its syntactic sugar. Recently I was doing some Python work and wanted to call a method on every element in a list.

In Ruby you would do something like

lst = ["foo", "bar", "baz"]
lst.map(&:capitalize)
# ["Foo", "Bar", "Baz"]

The magical &:capitalize is a bit of shorthand that basically says "Take the symbol 'capitalize' and convert it into a Proc (like a lambda in Python)" It is essentially the same thing as

lst = ["foo", "bar", "baz"]
lst.map{|item| item.capitalize}
# ["Foo", "Bar", "Baz"]

In Python, you would do something like

lst = ['foo', 'bar', 'baz']
map(lambda item: item.title, lst)
# ["Foo", "Bar", "Baz"]

But since I do this fairly often, I created a wrapper around map to behave more like ruby

def mapattr(attr, lst):
  "creates a lambda for attr and maps it over items in lst"
  return map(lambda item: getattr(item, attr)(), lst)

lst = ['foo', 'bar', 'baz']
mapattr('title', lst)
# ["Foo", "Bar", "Baz"]

This will work in the case where you are calling a function, but sometimes you want to access a field on a class

class Person:
  def __init__(self, first, last):
    self.first_name = first
    self.last_name = last

people = [Person("Gary", "Player"), Person("Sam", "Snead"), Person("Ben", "Hogan")]
mapattr('last_name', people)
# TypeError: 'str' object is not callable

Since class fields are accessed directly and not as function calls, we need to modify mapattr

def mapattr(attr, lst):
  "creates a lambda for attr and maps it over items in lst"
  def helper(item):
    attribute = getattr(item, attr)
    if callable(attribute):
      return attribute()
    else: return attribute
  return map(helper, lst)

mapattr('last_name', people)
# ['Player', 'Snead', 'Hogan']

Awesome. One problem, I now have to remember to use mapattr. What would really be nice is if I could change the behaviour of map itself and let map take in a lambda or an attribute as its first argument. I was told this was not possible in the #python irc chat room, but if there is a will there is a way.

import __builtin__
__builtin__.old_map = map

def map(lambda_or_attr, sequences):
    import types
    fun = lambda_or_attr
    if type(lambda_or_attr) is types.StringType:
        def helper(item):
            attribute = getattr(item, lambda_or_attr)
            if callable(attribute):
                return attribute()
            else:
                return attribute
        fun = helper
    return old_map(fun, sequences)

__builtin__.map = map
     
lst = ['foo', 'bar', 'baz']
map('title', lst)
# ['Foo', 'Bar', 'Baz']
map(lambda item: item.title(), ['foo', 'bar', 'baz'])
# ['Foo', 'Bar', 'Baz']
                                                   
people = [Person("Gary", "Player"), Person("Sam", "Snead"), Person("Ben", "Hogan")]

map('last_name', people)
# ['Player', 'Snead', 'Hogan']


This isn't a complete implementation since the function signature for the built in map is a bit different, but it is a start.