0

I have implemented a class BasicForm, containing also a method __str__ to be able to print stuff. I also have a function stringToBasicForm(string) converting certain types of strings to BasicForm objects.

Later in my program, I have an array array of allowed strings, and I do the following:

for i in xrange(len(array)): array[i] = stringToBasicForm(array[i]) 

My problem is that, after this, array appears to contain objects of type str and not of type BasicForm as I would have expected. I think that Python is automatically converting my BasicForms to strings using __str__ for some reason.

What is happening? How can I make it so that my array contains the good type of objects at the end (without creating an auxiliary array)?

Any help will be greatly appreciated.

Remark: I'm using Python 2.7


Here's a small-ish working example:

from fractions import * from numpy import * class BasicForm: def __init__(self,n,coeff,I): if shape(I)[1] != n + 1: print "Error: illegal I." return if not all([isinstance(f,Fraction) for f in coeff]): print "Error: coefficients must be of class Fraction." return self.n = n vect = zeros(2**(n+1)-1,dtype = Fraction) for i in xrange(len(I)): if not any(I[i]): print "Error: the empty set doesn't code any basic form." return vect[subsetToIndex(n,I[i])] = coeff[i] self.vect = vect def __str__(self): if not any(self.vect): return "0" s = "" first = True for i in xrange(2**(self.n+1)-1): if self.vect[i] == 0: continue if self.vect[i] < 0: s += "-" if not first: s = s[:-3] + "- " if self.vect[i] != 1: s += str(abs(self.vect[i])) + "*" s += "(" I = indexToSubset(self.n,i) for k in xrange(self.n+1): if I[k]: s += str(k) s += ") + " first = False return s[:-2] def stringToBasicForm(n,string): out = BasicForm(n,[Fraction(0)],[ones(n+1,dtype = bool)]) return out 

Now for the weird part. If I run this with

n = 1 array = ["(01)"] for i in xrange(len(array)): array[i] = stringToBasicForm(n,array[i]) print isinstance(array[i],BasicForm), isinstance(array[i],str) 

everything works as expected (output: True False). But if I run it with

def opPBT(n,LPBT,BF_array): tree = copy(LPBT) array = copy(BF_array) # Convert basic forms to elements to the Sullivan algebra (injection). for i in xrange(len(array)): if isinstance(array[i],str): array[i] = stringToBasicForm(n,array[i]) print isinstance(array[i],BasicForm), isinstance(array[i],str) elif array[i].n != n: print "Error: basic form of wrong dimension." return array[i] = basicToSullivan(array[i]) return n = 2 forms = ["(01)"] lcomb = [] opPBT(n,lcomb,forms) 

which is what I would like to do, then the output is False True, and I have absolutely no clue of what I'm doing wrong (it's probably some stupid error but I'll be damned if I can see it...)

11
  • What does stringToBasicForm do? Commented Jun 14, 2016 at 14:32
  • No, Python would never do that conversion by itself with a for loop like that. We'd like a look at your stringToBasicForm function. Commented Jun 14, 2016 at 14:33
  • @timakro It converts certain strings to 'BasicForm's. It works without problems and returns the correct data type. Commented Jun 14, 2016 at 14:34
  • @RemcoGerlich Ok, I've posted the code. Commented Jun 14, 2016 at 14:35
  • As @RemcoGerlich said, if stringToBasicForm returns objects of type BasicForm the list will be filled with those, python does no conversion by itself. Commented Jun 14, 2016 at 14:35

2 Answers 2

3

Numpy arrays are strongly typed:

>>> x = np.empty((3,), dtype=np.float64) >>> x[0] = 1 # I put an int in... >>> x[0] # And get a float out ! 1.0 

Usually, the array will try to convert values you pass in (which is typically what you want, cf the example above, where you wouldn't want the whole thing to crash because you forgot a . after the 1). Since you have a convenient __str__, it will use that to ensure that your array is consistent.

What does that have to do with your problem ? I suspect the copy you're using is the numpy copy:

>>> from numpy import copy >>> copy([1,2,3]) # List in, array out... array([1, 2, 3]) 

Which would explain your automatic coercion; normal Python lists do not operate like that:

>>> foo = ['a', 'b', 'c'] >>> class A(object): ... def __str__(self): ... return "converted !" ... >>> bar = copy(foo) >>> bar[0] = A() >>> foo[0] = A() >>> type(foo[0]) __main__.A >>> type(bar[0]) numpy.string_ >>> isinstance(bar[0], str) True 
Sign up to request clarification or add additional context in comments.

1 Comment

That was the problem. Thanks you, I would never have found out by myself.
0

Regarding your stringToBasicForm function the return value must be None or a BasicForm instance ...

Can you just check with type() ?

class BasicForm: def __init__(self, s): pass def __str__(self): return "PLOP" array = ['toto', 'tata', 'tutu'] print([type(elem) for elem in array]) for i, elem in enumerate(array): array[i] = BasicForm(elem) print([type(elem) for elem in array]) 

output:

[<class 'str'>, <class 'str'>, <class 'str'>] [<class '__main__.BasicForm'>, <class '__main__.BasicForm'>, <class '__main__.BasicForm'>] 

1 Comment

Yes, in my example above the output is [<type 'instance'>] for the first version, and [<type 'numpy.string_'>]for the second one.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.