Compreensões de listas com objetos de classe

Nov 26 2020

Eu tenho uma classe chamada StrucData em subfile.py

class StrucData:  
def __init__(self, name):
    self.name=name

def loadData(self, size=1, cost=1):
    self.size=size  
    self.cost=cost

No arquivo principal I:

  1. chame o subarquivo,
  2. crie uma lista de nomes de dados
  3. percorrer a lista para instanciar os objetos; e
  4. carregar dados usando o método 'loadData' para cada objeto (estou usando o mesmo 'tamanho' e 'custo' para tornar este exemplo fácil.)
    from subfile import StrucData 

    listIndex=['data1','data2','data3']

    # Create a list of objects
    listObjects=[]

    # Iterate through the list of objects
    for i in range(3):
        data=StrucData(listIndex[i])
        data.loadData(size=3, cost=4)
        listObjects.append(data)

O que estou tentando fazer é fazer a mesma coisa usando a compreensão de lista, para obter

listObjects=[object1, object2, object3]

e eu tentei algo como

listObjects=[[StrucData(listIndex[i]) for k in range(3)] listObjects[i].loadData(size=3, cost=4) for i in range(3)]]

o que não funciona, é claro, mas não sei como fazer direito.

Posso ter conselhos sobre meu código para obter os resultados desejados usando uma compreensão de lista?

Respostas

1 BillHuang Nov 26 2020 at 19:00

Se você estiver livre para acrescentar return selfà última linha de StrucData.loadData()dentro subfile.py, pode ser simplificado assim:

# in the main file
listObjects = [StrucData(idx).loadData(size=3, cost=4) for idx in listIndex]

Caso contrário, você terá que fazer isso separadamente porque loadData()não retornará nada para uma expressão de compreensão de lista.

listObjects = [StrucData(idx) for idx in listIndex]
for i in range(3):
    listObjects[i].loadData(size=3, cost=4)
2 DavidFrancosCuartero Nov 26 2020 at 19:26

Complementando a resposta de Bill Huang, se você não está livre para alterar o objeto e não deseja iterar duas vezes, pode adicionar uma função auxiliar:

def load_data(idx, size, cost):
    result = StructData(idx)
    result.loadData(size, cost)
    return result

[load_data(x, size=3, cost=4) for x in range(3)]

Como uma observação lateral, se você realmente não precisa que a instância tenha o nome e loadData separados, você pode usar apenas um namedtuple:

from collections import namedtuple

StructData = namedtuple('StructData', ['name', 'size', 'cost'])
print([StructData(name=x, size=3, cost=4) for x in range(3)])

Que retornaria:

[StructData(name=0, size=3, cost=4), 
 StructData(name=1, size=3, cost=4), 
 StructData(name=2, size=3, cost=4)]

Finalmente, vendo que você tem nomes como "dados1", "dados2", você pode querer ter isso como nomes de classe, você pode fazer isso com namedtuple, desde que os nomes sejam identificadores de classe válidos:

from collections import namedtuple

list_index = ['data1', 'data2', 'data3']
print([namedtuple(name, ['size', 'cost'])(3, 4) for name in list_index])

Resultado:

[data1(size=3, cost=4), data2(size=3, cost=4), data3(size=3, cost=4)]