On Sat, 13 Aug 2016 08:09 pm, BartC wrote: > (The way I deal with records elsewhere is so ridiculously simple that it > almost makes me want to cry when I see what most dynamic languages have > to do. Example: > > record date= # define the record > var day, month, year > end > > d := date(25,12,2015) # create an instance > d.year := 1999 # change a field > println d # show "(25,12,1999)"
Sure. But you've put most of the work into the compiler. Since you wrote the compiler, you still had to do the work. Python has gone over 20 years with no syntax or built-in function for creating "records", because they're not really needed. We have tuples, namedtuples and objects, which are much more powerful. But out of curiosity, I thought I'd write something to define a record as you would have it. A couple of tricky bits: - Since I'm not writing a compiler, I'm limited to syntax as allowed by Python. That means I have to give the record name twice: once as the binding target, and once as an argument to the "record" function. - The trickiest bit is defining the record class' __init__ method, since I don't know how many arguments it will need. Nevertheless, here you go. This was about 5 minutes work. Not too bad for a first draft. def record(name, fieldnames, verbose=False): if isinstance(fieldnames, str): fieldnames = fieldnames.split() class Inner(object): __slots__ = fieldnames def __str__(self): fields = ', '.join([repr(obj) for obj in self._fields]) return "record %s(%s)" % (type(self).__name__, fields) __repr__ = __str__ @property def _fields(self): return [getattr(self, name) for name in fieldnames] Inner.__name__ = name ns = {} template = "def __init__(self, %s):\n" % ', '.join(fieldnames) for name in fieldnames: template += ' self.%s = %s\n' % (name, name) if verbose: print("Using __init__ template:") print(template) exec(template, ns, ns) Inner.__init__ = ns['__init__'] return Inner py> date = record('date', 'year month day') py> x = date(2016, 8, 14) py> x record date(2016, 8, 14) py> x.year = 1999 py> x record date(1999, 8, 14) > I don't know how exec works. Is the 'value' name a local if this is in a > function, or a global if outside a function? exec takes a string, and executes it as Python code. You can specify the name spaces to use for globals and locals; by default they use globals() and locals(). Exec of a string on its own is like executing code at the top level of the module: exec("spam = 1") is like: spam = 1 in the module scope. You can specify another namespace: import math exec("spam = 1", vars(math)) is like executing "spam = 1" in the top level of the math module. ns = {} exec("spam = cos(pi)", vars(math), ns) print(ns['spam']) will print -1.0. It is equivalent to executing the line "spam = cos(pi)" inside an imaginary function running inside the math module. That imaginary function's local variables (in this case, there's only one, "spam") is recorded in the dictionary "ns" for later retrieval. > If your example was in a function, wouldn't 'value' be assumed to be a > global anyway, if it wasn't assigned to anywhere else in the function? Maybe. The rules for running exec inside a function in Python 2 are awfully complex, as it interact with the CPython optimization of using a table for locals instead of a dict. In Python 3, you cannot call exec() inside a function unless you explicitly specify a namespace to use. -- Steve “Cheer up,” they said, “things could be worse.” So I cheered up, and sure enough, things got worse. -- https://mail.python.org/mailman/listinfo/python-list