初始化期间为namedtuple字段键入转换

Pal*_*ndo 7 python namedtuple iterable-unpacking

我有一个几乎没有静态字段的类,并且可以从iterable初始化(比如输出csvreader).在__init__从字符串到数字对于他们中的一些进行类型转换:

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)
Run Code Online (Sandbox Code Playgroud)

我正在考虑将它转换为a namedtuple,因为它没有太多其他内容.但我想在初始化期间保持类型转换.有没有办法做到这一点namedtuple?(我没有注意到工厂方法__init__的详细输出中的namedtuple方法,这让我暂停了默认初始化程序的工作原理.)

Mar*_*nen 3

您可以使用 unpack 运算符将其解压csv_row,而不是像当前那样按原样传递。例如:*

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

这也适用于namedtuple,因为解包时将保留参数的顺序:

>>> 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)
Run Code Online (Sandbox Code Playgroud)

这不仅允许您使用namedtuple,这似乎是一个非常好的主意,而且还使您无需了解PerformanceTestResult有关 CSV 文件的任何信息!抽象是好的,因为现在无论数据来自哪里以及采用什么格式,您都可以使用同一个类。


如果您需要int()float()转换,则必须编写一个单独的转换函数。您可以PerformanceTestResult通过子类化将其构建到:

_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])
        )
Run Code Online (Sandbox Code Playgroud)

可以像这样使用:

>>> ptr = PerformanceTestResult.from_csv(your_csv_row)
Run Code Online (Sandbox Code Playgroud)

或者您可以创建一个单独的转换函数:

def parse_csv_row(row):
    return (row[0], int(row[1]), ...)
Run Code Online (Sandbox Code Playgroud)

现在使用它在解包之前转换行:

>>> ptr = PerformanceTestResult(*parse_csv_row(your_csv_row))
Run Code Online (Sandbox Code Playgroud)