使用“attrs”包将传递的数据存储在对象中两次
Storing passed data in object twice with `attrs` package
我正在创建一个数据提供程序 class,它将保存数据、执行转换并使其可供其他 classes 使用。
如果用户创建此 class 的实例并在实例化时传递一些数据,我想将其存储两次:一次用于所有转换,一次作为原始数据的副本。假设数据本身有一个 copy
方法。
我正在使用 attrs
包来创建 classes,但也对通常的最佳方法感兴趣(也许有更好的方法来获得我想要的东西? )
这是我目前的情况:
@attr.s
class DataContainer(object):
"""Interface for managing data. Reads and write data, acts as a provider to other classes.
"""
data = attr.ib(default=attr.Factory(list))
data_copy = data.copy()
def my_func(self, param1='all'):
"""Do something useful"""
return param1
这不起作用:AttributeError: '_CountingAttr' object has no attribute 'copy'
我也无法调用 data_copy = self.data.copy()
,我收到错误消息:NameError: name 'self' is not defined
。
没有 attrs
包的等效工作是:
class DataContainer(object):
"""Interface for managing data. Reads and write data, acts as a provider to other classes.
"""
def __init__(self, data):
"Init method, saving passed data and a backup copy"
self.data = data
self.data_copy = data
编辑:
正如@hynek 所指出的,我上面的简单 init 方法需要更正以制作数据的实际副本:即 self.data_copy = data.copy()
。否则 self.data
和 self.data_copy
将指向同一个对象。
在查看 the documentation a little more deeply(向右滚动到底部)后,我发现有一种 post-init 钩子 类 是由 attrs
创建的.
您可以只包含一个特殊的 __attrs_post_init__
方法,它可以在 __init__
方法中完成人们可能想做的更复杂的事情,而不仅仅是简单的赋值。
这是我的最终工作代码:
In [1]: @attr.s
...: class DataContainer(object):
...: """Interface for managing data. Reads and write data,
...: acts as a provider to other classes.
...: """
...:
...: data = attr.ib()
...:
...: def __attrs_post_init__(self):
...: """Perform additional init work on instantiation.
...: Make a copy of the raw input data.
...: """
...: self.data_copy = self.data.copy()
In [2]: some_data = np.array([[1, 2, 3], [4, 5, 6]])
In [3]: foo = DataContainer(some_data)
In [4]: foo.data
Out[5]:
array([[1, 2, 3],
[4, 5, 6]])
In [6]: foo.data_copy
Out[7]:
array([[1, 2, 3],
[4, 5, 6]])
为了加倍确定,我检查了这两个属性是否引用了同一个对象。在这种情况下,它们不是,这可能要归功于 NumPy 数组上的 copy
方法。
In [8]: foo.data[0,0] = 999
In [9]: foo.data
Out[10]:
array([[999, 2, 3],
[ 4, 5, 6]])
In [11]: foo.data_copy
Out[12]:
array([[1, 2, 3],
[4, 5, 6]])
你可以在这里做两件事。
您自己找到的第一个:您使用 __attr_post_init__
。
第二个是默认值:
>>> import attr
>>> @attr.s
... class C:
... x = attr.ib()
... _x_backup = attr.ib()
... @_x_backup.default
... def _copy_x(self):
... return self.x.copy()
>>> l = [1, 2, 3]
>>> i = C(l)
>>> i
C(x=[1, 2, 3], _x_backup=[1, 2, 3])
>>> i.x.append(4)
>>> i
C(x=[1, 2, 3, 4], _x_backup=[1, 2, 3])
JFTR,你是
的榜样
def __init__(self, data):
self.data = data
self.data_copy = data
是错误的,因为您将同一个对象赋值两次,这意味着修改 self.data
也会修改 self.data_copy
,反之亦然。
我正在创建一个数据提供程序 class,它将保存数据、执行转换并使其可供其他 classes 使用。
如果用户创建此 class 的实例并在实例化时传递一些数据,我想将其存储两次:一次用于所有转换,一次作为原始数据的副本。假设数据本身有一个 copy
方法。
我正在使用 attrs
包来创建 classes,但也对通常的最佳方法感兴趣(也许有更好的方法来获得我想要的东西? )
这是我目前的情况:
@attr.s
class DataContainer(object):
"""Interface for managing data. Reads and write data, acts as a provider to other classes.
"""
data = attr.ib(default=attr.Factory(list))
data_copy = data.copy()
def my_func(self, param1='all'):
"""Do something useful"""
return param1
这不起作用:AttributeError: '_CountingAttr' object has no attribute 'copy'
我也无法调用 data_copy = self.data.copy()
,我收到错误消息:NameError: name 'self' is not defined
。
没有 attrs
包的等效工作是:
class DataContainer(object):
"""Interface for managing data. Reads and write data, acts as a provider to other classes.
"""
def __init__(self, data):
"Init method, saving passed data and a backup copy"
self.data = data
self.data_copy = data
编辑:
正如@hynek 所指出的,我上面的简单 init 方法需要更正以制作数据的实际副本:即 self.data_copy = data.copy()
。否则 self.data
和 self.data_copy
将指向同一个对象。
在查看 the documentation a little more deeply(向右滚动到底部)后,我发现有一种 post-init 钩子 类 是由 attrs
创建的.
您可以只包含一个特殊的 __attrs_post_init__
方法,它可以在 __init__
方法中完成人们可能想做的更复杂的事情,而不仅仅是简单的赋值。
这是我的最终工作代码:
In [1]: @attr.s
...: class DataContainer(object):
...: """Interface for managing data. Reads and write data,
...: acts as a provider to other classes.
...: """
...:
...: data = attr.ib()
...:
...: def __attrs_post_init__(self):
...: """Perform additional init work on instantiation.
...: Make a copy of the raw input data.
...: """
...: self.data_copy = self.data.copy()
In [2]: some_data = np.array([[1, 2, 3], [4, 5, 6]])
In [3]: foo = DataContainer(some_data)
In [4]: foo.data
Out[5]:
array([[1, 2, 3],
[4, 5, 6]])
In [6]: foo.data_copy
Out[7]:
array([[1, 2, 3],
[4, 5, 6]])
为了加倍确定,我检查了这两个属性是否引用了同一个对象。在这种情况下,它们不是,这可能要归功于 NumPy 数组上的 copy
方法。
In [8]: foo.data[0,0] = 999
In [9]: foo.data
Out[10]:
array([[999, 2, 3],
[ 4, 5, 6]])
In [11]: foo.data_copy
Out[12]:
array([[1, 2, 3],
[4, 5, 6]])
你可以在这里做两件事。
您自己找到的第一个:您使用 __attr_post_init__
。
第二个是默认值:
>>> import attr
>>> @attr.s
... class C:
... x = attr.ib()
... _x_backup = attr.ib()
... @_x_backup.default
... def _copy_x(self):
... return self.x.copy()
>>> l = [1, 2, 3]
>>> i = C(l)
>>> i
C(x=[1, 2, 3], _x_backup=[1, 2, 3])
>>> i.x.append(4)
>>> i
C(x=[1, 2, 3, 4], _x_backup=[1, 2, 3])
JFTR,你是
的榜样def __init__(self, data):
self.data = data
self.data_copy = data
是错误的,因为您将同一个对象赋值两次,这意味着修改 self.data
也会修改 self.data_copy
,反之亦然。