A symbol in the programming language Lisp is a primitive data structure that has a name. Symbols can be used as identifiers. Symbols are unique in a namespace (called package in Common Lisp). Symbols can be tested for equality with the function EQ. Lisp programs can generate new symbols at runtime. When Lisp reads data that contains textual represented symbols, existing symbols are referenced. If a symbol is unknown, the Lisp reader creates a new symbol.
I'm not overly familiar with Lisp, however I have done some work with Scheme; and an explicit Symbol type is something that I sometimes miss in Python. Do you ever find yourself defining classes to be used as global constants, so that you can use the identity operator? Perhaps something like this:
Symbols offer a better alternative to this, so I decided to implement a Symbol type in Python, which offered some of the features of a Lisp Symbol.
class START: pass
class QUIT: pass
if something() is QUIT: exit()
import sysHow is this module intended to be used? Try this:
class Symbols(object):
def __init__(self, name):
self.name = name
self._symbols = {}
def __repr__(self):
return "<SYM %s>"%(self.name)
def __getattr__(self, name):
s = self._symbols[name] = self.__class__(name)
self.__dict__[name] = s
return s
def __getitem__(self, name):
return getattr(self, name)
s = sys.modules["symbols"] = Symbols("Root")
>>> import symbolsThe symbols module contains every possible Symbol, and can be used as simple set of constants... but it can also do more than that.
>>> symbols.START is symbols.QUIT
False
>>> symbols.START is symbols.START
True
>>>
>>> symbols["START"] is symbols.STARTSymbols can be accessed by a string name, which lets you use different characters in a Symbol name, and provides a convenient method for creating new Symbols at runtime.
True
>>>
The last requirement is for Symbols to be unique within their own namespace. Our symbols module can support this too.
>>> symbols.Foo.Bar.Foo is symbols.FooThis feature allows you to have an nested set of Symbols which retain their identity wherever they're used in your program.
False
>>> symbols.Foo.Bar.Foo is symbols.Foo.Bar.Foo
True
>>>
7 comments:
One of the nice things in lisp is that your program is made of symbols, not strings -- and that would be a bit hard to transplant into Python :-)
class DotDict(dict):
def __getattr__(self, attr):
return self.get(attr, None)
__setattr__ = dict.__setitem__
__delattr__ = dict.__delitem__
I use the DotDict for the same purpose.
http://code.google.com/p/gnafu/source/browse/src/xtypes.py
I think your implementation is missing a few things.
On top of identity, symbols can be bound to a function, have a value, and store a plist (essentially in a way, a dictionary).
They're also aware of the package they originate in and can be exported to other packages.
For a full definition according to the Common Lisp spec, see:
http://www.lispworks.com/documentation/HyperSpec/Body/t_symbol.htm#symbol
IMHO defining symbol-like classes, as with START and QUIT above, is a code smell. When I find myself doing this, I look at why those aren't real classes. That is, instead of representing a value that a "master program" uses to switch code paths, if you put the implementation of the different code paths in those classes, your code is cleaner/more object oriented.
This is something that has long griped me about python, and I do like your implementation. Simple but also powerful. Well done, Simon.
Just FYI, Phillip J. Eby created a SymbolType quite a while a go and it's listed on PyPi:
http://pypi.python.org/pypi/SymbolType
It seems like a pretty complete implementation.
For identity checks you can use plain objects instead of classes:
START = object()
QUIT = object()
Post a Comment