HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

String to (Multidimensional) List Conversion

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
conversionmultidimensionalliststring

Problem

Some background:

I'm writing a number of classes that ensure user input is properly validated, and is rejected if it does not conform to expected types (there's also some extra options such as setting bounds and finite sets that the values can come from). There are a number of basic types (Integral, Boolean, String, Double, Complex), and also an Array type that uses one of these types as a "base type" (so you might have an Array of Integers for example; in this case, every value in the array must be an Integer).

For the Array type, this checking is done by instantiating it with a given base type; all values for the Array are then checked with the base type. Conversions are done by setting the value property for the given base type, (so calling self._base_type.value = x will convert x to a given type, raising a ValueError if it fails).

These types above all inherit from a _Leaf class, but that can be fairly safely ignored for this code.

Finally, each element knows how to convert itself to an XML representation.

I'm aware that this is more work than what should be done in a property, but other project restrictions effectively force me to keep it this way. For a 1-D array [1,2,3] this might look like:


    1.0
    2.0
    3.0


For a 2D array [[1,2,3],[4,5,6]]:


    
        1.0
        2.0
        3.0
    
    
        4.0
        5.0
        6.0
    


I'm looking for anything that cleans this up a bit (or any other feedback). Note that the XML creation uses Qt, hence the camelCase method names.

```
import string

class ArrayLeaf(_Leaf):
'''Basic Leaf type for an Array. The array must be given its own
leaf type (for example, DoubleLeaf) to be used. There are a few extra
restrictions placed on an array type:
- For Double/Integral types, no min/max bounds can be set.
- For String types, no enumerations can be set.
'''
def __init__(self, base_leaf, name='ArrayLeaf', parent=None):
su

Solution

The name _convert_string_to_array is not intuitive: the name suggests a converter function that takes some input and returns converted output, but in this code it changes internal state. I'd call it _set_from_string or something similar.

try:
    self._base_type.value = d_val.strip(string.whitespace)
    d.append(self._base_type.value)
except ValueError as val_error:
    self._values = []
    self._dimension = 0
    raise val_error


Essentially you're catching the exception just to reset ._values and ._dimension in case they have been modified. It would be simpler to not modify them at all until the loop is finished, that way you won't need to catch anything:

self._values = []
self._dimension = 0
vals = vals.split(';')

new_values = []

for dimension in vals:
    dimension = dimension.split(',')
    d = []
    for d_val in dimension:
        self._base_type.value = d_val.strip(string.whitespace)
        d.append(self._base_type.value)
    new_values.append(d)

self._values = new_values
self._dimension = len(vals)


The loops inside the if-else are crying for extraction to a common method:

if self._dimension == 1:
    for val in self._values:
        value_element = document.createElement('value')
        value = document.createTextNode(str(val))
        value_element.appendChild(value)
        elem.appendChild(value_element)
else:
    for dim in self._values:
        dimension = document.createElement('dimension')
        for val in dim:
            value_element = document.createElement('value')
            value = document.createTextNode(str(val))
            value_element.appendChild(value)
            dimension.appendChild(value_element)
        elem.appendChild(dimension)


Minor things:

  • There should be a blank line before the @value.setter (before every method definition)



  • It seems to me that .strip(string.whitespace) is equivalent to .strip(). Unless I'm overlooking something, I'd use the simplest way.

Code Snippets

try:
    self._base_type.value = d_val.strip(string.whitespace)
    d.append(self._base_type.value)
except ValueError as val_error:
    self._values = []
    self._dimension = 0
    raise val_error
self._values = []
self._dimension = 0
vals = vals.split(';')

new_values = []

for dimension in vals:
    dimension = dimension.split(',')
    d = []
    for d_val in dimension:
        self._base_type.value = d_val.strip(string.whitespace)
        d.append(self._base_type.value)
    new_values.append(d)

self._values = new_values
self._dimension = len(vals)
if self._dimension == 1:
    for val in self._values:
        value_element = document.createElement('value')
        value = document.createTextNode(str(val))
        value_element.appendChild(value)
        elem.appendChild(value_element)
else:
    for dim in self._values:
        dimension = document.createElement('dimension')
        for val in dim:
            value_element = document.createElement('value')
            value = document.createTextNode(str(val))
            value_element.appendChild(value)
            dimension.appendChild(value_element)
        elem.appendChild(dimension)

Context

StackExchange Code Review Q#62704, answer score: 2

Revisions (0)

No revisions yet.