转移到namedtuple的好方法

时间:2018-03-13 19:07:49

标签: python collections namedtuple

我正在编写一个函数,它将元组或一对参数转换为带有int字段的namedtuple。

from collections import namedtuple

EPS = 0.00000001

def point(*cont: 'tuple or pair of args') -> namedtuple('Point', 'x y'):
    """Make an int named pair (Point)"""
    if len(cont) == 1:
        res = namedtuple('Point', 'x y')
        if abs(int(cont[0][0])-cont[0][0]) < EPS:
            res.x = int(cont[0][0])
        else:
            res.x = cont[0][0]
        if abs(int(cont[0][1])-cont[0][1]) < EPS:
            res.y = int(cont[0][1])
        else:
            res.y = cont[0][1]
    else:
        res = namedtuple('Point', 'x y')
        if abs(int(cont[0])-cont[0]) < EPS:
            res.x = int(cont[0])
        else:
            res.x = cont[0]
        if abs(int(cont[1])-cont[1]) < EPS:
            res.y = int(cont[1])
        else:
            res.y = cont[1]
    return res

有更好的方法吗?

1 个答案:

答案 0 :(得分:1)

您的代码的一个主要缺陷是它实际上并非使用 namedtuple,您只是在namedtuple类上设置属性。如果要将namedtuple('Point', 'x y')替换为允许添加属性的任何其他对象,则代码的行为不会有任何不同:

>>> from collections import namedtuple
>>> Point = namedtuple('Point', 'x y')
>>> Point.x = 5
>>> Point.y = 5
>>> Point.z = 5  # uh oh
>>> Point
<class '__main__.Point'>
>>> point = Point(1, 2)  # how it should work
>>> point
Point(x=1, y=2)
>>> isinstance(Point, tuple)
False
>>> isinstance(point, tuple)
True

一旦你解决了这个问题,请按照我的方式简化你的代码:

Point = namedtuple('Point', 'x y')

def maybe_floor_int(n, epsilon=0.00000001):
    if abs(int(n) - n) < epsilon:
        return int(n)
    else:
        return n

def create_point(*args: 'tuple or pair of args') -> Point:
    """Make an int named pair (Point)"""

    if len(args) == 1:
        x, y = args
    else:
        x, y = args[0]

    return Point(maybe_floor_int(x), maybe_floor_int(y))

由于您的point函数正在创建Point元组的实例,并且您最终可能希望覆盖point的运算符(例如能够使用乘法缩放它们) ),你也可以创建一个专门的Point类。