Daniel Robert-Nicoud - 9 months ago 23

Python Question

I have implemented a class

`BasicForm`

`__str__`

`stringToBasicForm(string)`

Later in my program, I have an array

`array`

`for i in xrange(len(array)):`

array[i] = stringToBasicForm(array[i])

My problem is that, after this,

`array`

`str`

`BasicForm`

`__str__`

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.

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`

`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`

Answer

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
```