# [译] 人人都应该用的 Python 开源库

·  阅读 5607

``class Point3D(object):复制代码``

``````class Point3D(object):
def __init__(self, x, y, z):

``````class Point3D(object):
def __init__(self, x, y, z):
self.x

``````class Point3D(object):
def __init__(self, x, y, z):
self.x = x

… 为 `x` ？嗯，很明显

``````class Point3D(object):
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z

… 现在我必须为每个属性做一次，所以实际上这个 尺度 真的把握的很糟糕吗？我一定要每个属性都这样输入 3 次吗 ？！

``````class Point3D(object):
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def __repr__(self):

``````class Point3D(object):
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def __repr__(self):
return (self.__class__.__name__ +
("(x={}, y={}, z={})".format(self.x, self.y, self.z)))

``````class Point3D(object):
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def __repr__(self):
return (self.__class__.__name__ +
("(x={}, y={}, z={})".format(self.x, self.y, self.z)))
def __eq__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
return (self.x, self.y, self.z) == (other.x, other.y, other.z)

7 次?!

``````class Point3D(object):
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def __repr__(self):
return (self.__class__.__name__ +
("(x={}, y={}, z={})".format(self.x, self.y, self.z)))
def __eq__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
return (self.x, self.y, self.z) == (other.x, other.y, other.z)
def __lt__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
return (self.x, self.y, self.z) < (other.x, other.y, other.z)

9 次?!

``````from functools import total_ordering
@total_ordering
class Point3D(object):
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def __repr__(self):
return (self.__class__.__name__ +
("(x={}, y={}, z={})".format(self.x, self.y, self.z)))
def __eq__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
return (self.x, self.y, self.z) == (other.x, other.y, other.z)
def __lt__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
return (self.x, self.y, self.z) < (other.x, other.y, other.z)

``````from unittest import TestCase
class Point3DTests(TestCase):

## `namedtuple` 救援（不是真正意义上的）。

• 他们通过编号指标进行访问无论您是否希望这样做。除此之外，这意味着你不能有私有属性，因为他们通过明显的公共接口 `__getitem__` 暴露出来。
• 它比较相等的值相同的原始 `tuple` ，所以很容易陷入离奇的类型混乱，特别是如果你想用它来使用 `tuple``list` 进行迁移。
• 这是一个元组，所以它 总是 一成不变的。
至于最后一点，你可以像它这样使用：
``````Point3D = namedtuple('Point3D', ['x', 'y', 'z'])

``````class Point3D(namedtuple('_Point3DBase', 'x y z'.split()])):
pass

## 键入 `attr`

``````import attr
@attr.s复制代码``````

``````import attr
@attr.s
class Point3D(object):

``````import attr
@attr.s
class Point3D(object):
x = attr.ib()

``````import attr
@attr.s
class Point3D(object):
x = attr.ib()
y = attr.ib()
z = attr.ib()

``````>>> Point3D(1, 2, 3)
Point3D(x=1, y=2, z=3)

``````>>> Point3D(1, 2, 3) == Point3D(1, 2, 3)
True
>>> Point3D(3, 2, 1) == Point3D(1, 2, 3)
False
>>> Point3D(3, 2, 3) > Point3D(1, 2, 3)
True

``````>>> attr.asdict(Point3D(1, 2, 3))
{'y': 2, 'x': 1, 'z': 3}

``````>>> import pprint
>>> pprint.pprint(attr.fields(Point3D))
(Attribute(name='x', default=NOTHING, validator=None, repr=True, cmp=True, hash=True, init=True, convert=None),
Attribute(name='y', default=NOTHING, validator=None, repr=True, cmp=True, hash=True, init=True, convert=None),
Attribute(name='z', default=NOTHING, validator=None, repr=True, cmp=True, hash=True, init=True, convert=None))

1. 它允许您定义简洁的类型，而不是相当冗长的 `def __init__...` 。类型无需键入。
2. 它可以让你说你 直接声明的意思 ，而不是拐弯抹角的表达它。用「我有一个类型，他被称为 MyType ，它具有 `a` 的属性和行为，可以直接得到，而不必通过逆向工程猜测它的行为（例如，运行 `dir` 的实例，或寻找`self.__class__.__dict__`）。」来代替「我有一个类型，它被称为 MyType ，它有一个构造函数，我分配属性 ‘A’ 到参数 ‘A’ 。」
3. 提供了有用的默认行为，而不是 Python 的有时有用但是经常向后的默认值。
4. 它增添了一个让你 稍后更严格的执行 ，简单的开始。

## 逐步增强

``````import attr
from attr.validators import instance_of
@attr.s
class Point3D(object):
x = attr.ib(validator=instance_of(float))
y = attr.ib(validator=instance_of(float))
z = attr.ib(validator=instance_of(float))

``````class Bag:
def __init__(self, contents=[]):
self._contents = contents
self._contents.append(something)
def get(self):
return self._contents[:]
a复制代码``````

``````class Bag:
def __init__(self, contents=None):
if contents is None:
contents = []
self._contents = contents

`contents` 不经意间成为这里的一个全局变量，使所有的 `Bag` 对象没有设置不同的列表共享相同的列表。有了 `attrs` 这个代替变为：

``````@attr.s
class Bag:
_contents = attr.ib(default=attr.Factory(list))
self._contents.append(something)
def get(self):
return self._contents[:]

## Python 的未来

1. 在这里缺乏引用是因为属性暴露给 `__caller__` 没有意义，他们只是被公开的命名而已。这种模式，它完全摆脱了私有方法并且只拥有唯一的私有属性，可以很好的应对它自己传递的参数。 ↩

2. 我们尚未得到真正令人兴奋的东西：构造时的类型认证，可变的默认值… ↩