2017-06-18 2 views
4

J'ai une classe qui a peu de champs statiques et qui est initialisée à partir de itérable (comme la sortie de csvreader).Conversion de types pour les champs namedtuple lors de l'initialisation

class PerformanceTestResult(object): 
    def __init__(self, csv_row): 
     # csv_row[0] is just an ordinal number of the test - skip that 
     self.name = csv_row[1]   # Name of the performance test 
     self.samples = int(csv_row[2]) # Number of measurement samples taken 
     self.min = int(csv_row[3])  # Minimum runtime (ms) 
     self.max = int(csv_row[4])  # Maximum runtime (ms) 
     self.mean = int(csv_row[5])  # Mean (average) runtime (ms) 
     self.sd = float(csv_row[6])  # Standard deviation (ms) 

Je pense à la conversion à être juste un namedtuple, car il n'y a pas grand-chose d'autre à: le pour certains d'entre eux __init__ effectue la conversion du type de chaînes en nombres. Mais je voudrais maintenir la conversion de type lors de l'initialisation. Y at-il un moyen de le faire avec namedtuple? (Je ne l'ai pas remarqué méthode __init__ dans la sortie verbeuse de namedtuple méthode d'usine, ce qui me fait réfléchir sur le fonctionnement de l'initialiseur par défaut.)

+0

Avez-vous un exemple de la façon dont vous voulez que votre namedtuple ressemble? – user1767754

Répondre

0

Au lieu de passer dans le csv_row comme-est, comme vous le faites actuellement, vous pourriez décompresser en utilisant l'opérateur déballer *. Par exemple:

>>> def f(a, b): 
...  return a + b 
... 
>>> csv_row = [1, 2] 
>>> f(*csv_row) # Instead of your current f(csv_row) 

Cela fonctionne également avec namedtuple, puisque l'ordre des arguments sera conservé à déballer:

>>> from collections import namedtuple 
>>> PerformanceTestResult = namedtuple('PerformanceTestResult', [ 
...  'name', 
...  'samples', 
...  'min', 
...  'max', 
...  'mean', 
...  'sd', 
... ]) 
>>> test_row = ['test', '123', 2, 5, 3, None] # from your csv file 
>>> ptr = PerformanceTestResult(*test_row) 
>>> ptr 
PerformanceTestResult(name='test', samples='123', min=2, max=5, mean=3, sd=None) 

Non seulement cela vous permet d'utiliser namedtuple, qui semble vraiment bonne idée ici, mais il supprime également le besoin de votre PerformanceTestResult pour savoir quelque chose sur le fichier CSV! L'abstraction est bonne, puisque maintenant vous pouvez utiliser cette même classe indépendamment de l'endroit où les données proviennent et dans quel format.


Si vous avez besoin int() et float() conversions, vous allez devoir écrire une fonction de conversion séparée. Vous pouvez le construire dans le PerformanceTestResult par subclassing:

_PerformanceTestResult = namedtuple('PerformanceTestResult', [...]) 

class PerformanceTestResult(_PerformanceTestResult): 
    @classmethod 
    def from_csv(cls, row): 
     return cls(
      row[0], 
      int(row[1]), 
      int(row[2]), 
      int(row[3]), 
      int(row[4]), 
      int(row[5]), 
      float(row[6]) 
     ) 

qui peut être utilisé comme ceci:

>>> ptr = PerformanceTestResult.from_csv(your_csv_row) 

Ou vous pouvez créer une fonction de conversion séparée:

def parse_csv_row(row): 
    return (row[0], int(row[1]), ...) 

Et maintenant utilisez ceci pour convertir la rangée avant le déballage:

>>> ptr = PerformanceTestResult(*parse_csv_row(your_csv_row))