patternpythonMinor
Functions with mutable and non-mutable named tuples
Viewed 0 times
nonwithtuplesnamedandfunctionsmutable
Problem
I am making some functions within a function for learning which when passed information about a named tuple: it returns a reference to a class object from which we can construct instances of the specified named tuple. Is there any way to make the code a bit cleaner? Any help would be great. The function
Here is my current functioning code:
```
import re, traceback, keyword
from goody import type_as_str
def pnamedtuple(type_name, field_names, mutable=False):
'''Passed information about a named tuple: it returns a reference to a class
object from which we can construct instances of the specified named tuple.'''
def show_listing(s):
for i, l in enumerate(s.split('\n'), 1):
print('{num: >3} {text}'.format(num=i, text=l.rstrip()))
def unique_list(l):
ulist = []
for thing in l:
if thing not in ulist:
ulist.append(thing)
return ulist
regex = re.compile('^([a-zA-Z]{1}\w*)$')
resplit = re.compile('[ ,]')
if re.match(regex, str(type_name)) == None:
raise SyntaxError('Illegal type name: ' + str(type_name))
if type(field_names) not in (list, str):
raise SyntaxError('Field names cannot be extracted: improper typing.' + str(field_names) + 'are not a list or a str, but instead: ' + type_as_str(field_names))
if type(field_names) is str:
fields = re.split(resplit, field_names)
fields = [f for f in fields if f not in (None, '')]
if type(field_names) is list:
fields = field_names
fields = unique_list(fields)
for field in fields:
if field in keyword.kwlist:
raise SyntaxError('Field name: (' + str(field) + ') is a keyword and cannot be used.')
if field[0].lower() not in 'abcdefghijklmnopqrstuvwxyz':
raise SyntaxError('Field name: (' + str(field) + ') doesn\'t start with a letter')
def init(field_names, mutable):
'''has al
pnamedtuple has other functions defined in it.Here is my current functioning code:
```
import re, traceback, keyword
from goody import type_as_str
def pnamedtuple(type_name, field_names, mutable=False):
'''Passed information about a named tuple: it returns a reference to a class
object from which we can construct instances of the specified named tuple.'''
def show_listing(s):
for i, l in enumerate(s.split('\n'), 1):
print('{num: >3} {text}'.format(num=i, text=l.rstrip()))
def unique_list(l):
ulist = []
for thing in l:
if thing not in ulist:
ulist.append(thing)
return ulist
regex = re.compile('^([a-zA-Z]{1}\w*)$')
resplit = re.compile('[ ,]')
if re.match(regex, str(type_name)) == None:
raise SyntaxError('Illegal type name: ' + str(type_name))
if type(field_names) not in (list, str):
raise SyntaxError('Field names cannot be extracted: improper typing.' + str(field_names) + 'are not a list or a str, but instead: ' + type_as_str(field_names))
if type(field_names) is str:
fields = re.split(resplit, field_names)
fields = [f for f in fields if f not in (None, '')]
if type(field_names) is list:
fields = field_names
fields = unique_list(fields)
for field in fields:
if field in keyword.kwlist:
raise SyntaxError('Field name: (' + str(field) + ') is a keyword and cannot be used.')
if field[0].lower() not in 'abcdefghijklmnopqrstuvwxyz':
raise SyntaxError('Field name: (' + str(field) + ') doesn\'t start with a letter')
def init(field_names, mutable):
'''has al
Solution
Argh, code generation in Python. Well, in this case it seems safe as
you're not dealing with user code except for the variable names.
So a few suggestions then:
literal; it would matter if you were to use
functions, because then you'd have to construct the string from a list
(probably) in many cases.
written more cleanly with
keys themselves with the
an error instead of you having to deal with
Feature requests (I probably won't use it, but these seem like obvious
additions to me):
you'd have to specify them as strings I guess, but having e.g.
default value for a vector tuple would be nice.
about what happens with old instances (or you just throw an error
instead).
itself could use a hint like
All in all a nice application of metaprogramming, although I'm still not
a huge fan (cue the meme) of a string-based approach.
you're not dealing with user code except for the variable names.
So a few suggestions then:
- I'd typically expect that
field_namesas a list instead of a string
literal; it would matter if you were to use
pnamedtuple from otherfunctions, because then you'd have to construct the string from a list
(probably) in many cases.
- The dance with commas and string concatenation in
preprcan be
written more cleanly with
join as you already did in init.- And if you're on that, why not use
formatall the time as well.
get_fieldnamestrikes me as very ugly. I'd really prefer just the
keys themselves with the
@property annotation.- I think that specifying multiple fields with the same name should be
an error instead of you having to deal with
unique_list.Feature requests (I probably won't use it, but these seem like obvious
additions to me):
- Default values for fields. They would need to be literal values, or
you'd have to specify them as strings I guess, but having e.g.
0 asdefault value for a vector tuple would be nice.
- Deal with redefinition. This is a tricky one as you'd have to think
about what happens with old instances (or you just throw an error
instead).
- Generate some documentation for the new class. At least the class
itself could use a hint like
"This class was automagically generated
by pnamedtuple (at somefile.py:1234)."All in all a nice application of metaprogramming, although I'm still not
a huge fan (cue the meme) of a string-based approach.
Context
StackExchange Code Review Q#79752, answer score: 2
Revisions (0)
No revisions yet.