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

The make statement from PEP 359 is implemented using decorators and function definitions.

The make statement:

make <callable> <name> <tuple>:
    <block>

is implemented this way:

@make(<callable>, <tuple>)
def <name>():
    <block>

The code also has some examples, using the make decorator to create a namespace and a class.

Python, 93 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
import dis, new

def bytecode(fun):
    co = fun.func_code
    code = co.co_code
    names = co.co_names
    n = len(code)
    i = 0
    while i < n:
        end = i
        c = code[i]
        op = ord(c)
        i += 1
        oparg = None
        if op >= dis.HAVE_ARGUMENT:
            oparg = ord(code[i]) + ord(code[i+1])*256
            i += 2
        yield (end, op, oparg)
    return


def code_all_variables_dynamic(fun):
    co = fun.func_code
    len_co_names = len(co.co_names)
    new_co_names = co.co_names + co.co_varnames
    new_co_flags = co.co_flags & ~0x02
    new_code = ''
    for end, op, arg in bytecode(fun):
        if dis.opname[op] == 'STORE_FAST':
            new_arg = arg + len_co_names
            new_code += chr(dis.opmap['STORE_NAME']) + \
                        chr(new_arg % 256) + \
                        chr(new_arg // 256)
        elif dis.opname[op] == 'LOAD_FAST':
            new_arg = arg + len_co_names
            new_code += chr(dis.opmap['LOAD_NAME']) + \
                        chr(new_arg % 256) + \
                        chr(new_arg // 256)
        else:
            if arg is None:
                new_code += chr(op)
            else:
                new_code += chr(op) + chr(arg % 256) + chr(arg // 256)
    func_co = new.code(co.co_argcount, co.co_nlocals, co.co_stacksize,
                       new_co_flags, new_code, co.co_consts, new_co_names,
                       co.co_varnames, co.co_filename, co.co_name,
                       co.co_firstlineno, co.co_lnotab,
                       co.co_freevars, co.co_cellvars)
    return func_co


# This is how make statement is implemented:
#
# make <callable> <name> <tuple>:
#     <block>
#
# @make(<callable>, <tuple>)
# def <name>():
#     <block>

def make(callable, args=()):
    def _make(fun):
        namespace = {}
        code = code_all_variables_dynamic(fun)
        eval(code, fun.func_globals, namespace)
        return callable(fun.func_name, args, namespace)
    return _make

# from PEP 359
class namespace(object):
    def __init__(self, name, args, kwargs):
        self.__dict__.update(kwargs)

@make(namespace)
def d():
    a = 10
    a = a + 1
    b = '10'
    @make(namespace)
    def e():
        w = 'xxx'


# creating a class without using the class keyword
@make(type, (dict,))
def mydict():
    def __init__(self, *args, **kwargs):
        print '__init__'
        dict.__init__(self, *args, **kwargs)

    def __setitem__(self, i, y):
        print '__setitem__(%s, %s, %s)' % (repr(self), repr(i), repr(y))
        dict.__setitem__(self, i, y)

Add a comment

Sign in to comment

Created by Nilton Volpato on Sat, 4 Nov 2006 (PSF)
Python recipes (4239)
Nilton Volpato's recipes (1)

Required Modules

Other Information and Tasks