Daniel Corona Daniel Corona - 10 months ago 53
Python Question

Reading .obj file and split lines

I made a simple code to read a .obj file that looks like this

g cube

v 0.0 0.0 0.0
v 0.0 0.0 1.0
v 0.0 1.0 0.0
v 0.0 1.0 1.0
v 1.0 0.0 0.0
v 1.0 0.0 1.0
v 1.0 1.0 0.0
v 1.0 1.0 1.0

f 1//2 7//2 5//2
f 1//2 3//2 7//2
f 1//6 4//6 3//6
f 1//6 2//6 4//6
f 3//3 8//3 7//3
f 3//3 4//3 8//3
f 5//5 7//5 8//5
f 5//5 8//5 6//5
f 1//4 5//4 6//4
f 1//4 6//4 2//4
f 2//1 6//1 8//1
f 2//1 8//1 4//1


And the python code looks like this

class objeto():
def __init__(self, obj = None):
if obj:
self.cargar_obj(obj)

def cargar_obj(self, archivo):
with open(archivo, 'r') as obj:
datos = obj.read()

lineas = datos.splitlines()
self.vertices = []
self.superficies = []

for linea in lineas:
elem = linea.split()
if elem:
if elem[0] == 'v':
v = vertice(float(elem[1]), float(elem[2]), float(elem[3]))
self.vertices.append(v)
elif elem[0] == 'f':
vs = []
for i in range(1, len(elem)):
vs.append(self.vertices[int(elem[i].split('/'))])

f = cara(vs)
self.superficies.append(f)
else:
pass


The problem appears to be this line:

vs.append(self.vertices[int(elem[i].split('/'))])


because when I try to run the code, the followed TypeError appears

int() argument must be a string, a bytes-like object or a number, not 'list'


I'm a newbie in Python, so I don't seem to get around this error, can somebody give me some advice? Thanks.

I'm using Python 3.x, and ipython to run .py files

Answer Source

Recreate your case with one line:

In [435]: line='f  1//2  7//2  5//2'
In [436]: elem = line.split()
In [437]: elem
Out[437]: ['f', '1//2', '7//2', '5//2']
In [438]: elem[0]
Out[438]: 'f'

split on / behaves as I expect:

In [439]: for i in range(1,len(elem)):
     ...:    print(elem[i].split('/'))
     ...:    
['1', '', '2']
['7', '', '2']
['5', '', '2']

Your code has problems applying int to that list of strings:

In [440]: for i in range(1,len(elem)):
     ...:    print(int(elem[i].split('/')))
     ...
TypeError: int() argument must be a string, a bytes-like object or a number, not 'list'

So we need to apply int() to the individual strings, not the list. But now the empty string is giving me problems.

In [441]: for i in range(1,len(elem)):
     ...:    print([int(e) for e in elem[i].split('/')])
     ...:        
ValueError: invalid literal for int() with base 10: ''

The rest is left as an exercise for the reader.

Couldn't resist:

[int(e) for e in elem[i].replace('//','/').split('/')]
[int(e) for e in elem[i].split('/') if e]