Welcome, guest | Sign In | My Account | Store | Cart

This toy module shows a way to define symbols inside functions, using a decorator. Idea derived from recipe 303057 by Shai Berger.

Python, 100 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
"""
symbols.py -- by bearophile, V.1.0 Jan 23 2007

This module is probably an useless toy to manage symbols with CPython.

The symbol 'car' can be defined with as  Symbol('s_car')  or they are
  automatically instantiated inside functions/methods with the help
  of the  @withsymbols  decorator.

Some ideas come from Pythologic.py by Shai Berger, Cookbook recipe n.303057
"""

class Symbol:
    """Symbol class. A symbol 'car' has to be defined as:
      Symbol('inprefixcar')
    Where inprefix is a class attribute that's usually s_
    Or you can use the @withsymbols decorator."""
    inprefix = "s_"
    outprefix = "$"
    def __init__(self, inname):
        inname = str(inname)
        if not inname or not inname.startswith(Symbol.inprefix):
            raise TypeError("Symbol names must be defined with a starting "
                            + Symbol.inprefix)
        self.__name = Symbol.outprefix + inname[len(Symbol.inprefix):]
        self.__hash = hash(self.__name)

    def __eq__(self, other):
        if not isinstance(other, self.__class__):
            return False
        return self.__name == other.__name

    def __ne__(self, other):
        if not isinstance(other, self.__class__):
            raise True
        return self.__name != other.__name

    def __cmp__(self, other):
        if not isinstance(other, self.__class__):
            raise TypeError("Symbols can be compared only with other Symbols")
        return cmp(self.__name, other.__name)

    def __hash__(self):
        return self.__hash

    def __nonzero__(self):
        return True

    def __repr__(self): # this may become __str__
        return self.__name

    def getrepr(self): # this may become __repr__
        return "%s('%s%s')" % (self.__class__.__name__, Symbol.inprefix,
                               self.__name[len(Symbol.outprefix):])
    repr = property(getrepr)


def withsymbols(func):
    """decorator, if applied to a function, allows it to use Symbols,
    creating them when needed when the function is defined. A symbol
    name must start with inprefix (usually s_)."""
    # Ideas derived from Pythologic.py  by Shai Berger
    # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/303057
    try:
        code = func.func_code
    except:
        raise TypeError, "function or method argument expected"
    names = code.co_names
    locally_defined = code.co_varnames
    globally_defined = func.func_globals
    defined = set(locally_defined).union(globally_defined)
    undefined = set(names) - defined

    # Update the global scope of the function func, add definitions
    # for all undefined names starting with inprefix
    for name in undefined:
        if name.startswith(Symbol.inprefix):
            func.func_globals[name] = Symbol(name)
    return func


if __name__ == '__main__':
    @withsymbols
    def symbols_demo():
        print "Symbols demo:"
        print "  {s_a:5, s_b:6, s_c:s_a}:", {s_a:5, s_b:6, s_c:s_a}
        print "  Symbol('s_bar'):", Symbol('s_bar')
        some_symbols = set([(s_a, s_b), s_c, s_d])
        print "  some_symbols:", some_symbols
        print "  s_car == s_car:", s_car == s_car
        print "  s_car is s_car:", s_car is s_car
        print "  s_car, repr(s_car), s_car.repr:", s_car, repr(s_car), s_car.repr
        print "  s_b > s_a, s_b >= s_c:", s_b > s_a, s_b >= s_c
        print '  "|" + str(s_car) + "|":', "|" + str(s_car) + "|"
        print "  sorted([s_d, s_a, s_c, s_f, s_e]):", sorted([s_d, s_a, s_c, s_f, s_e])
        s_hello = 5 # s_name names can be defined anyway in the normal way
        print "  s_hello:", s_hello


    symbols_demo()

I have no idea if such symbols may become useful for something in Python, they may be just a toy.

Created by bearophile - on Mon, 22 Jan 2007 (PSF)
Python recipes (4591)
bearophile -'s recipes (15)

Required Modules

  • (none specified)

Other Information and Tasks