我正在创建一个数据提供程序类,它将保存数据,执行转换并使其可用于其他类。
如果用户创建此类的实例并在实例化时传递一些数据,我想将其存储两次:一次用于所有转换,一次用作原始数据的副本。我们假设数据本身有一个copy
方法。
我正在使用attrs
包来创建类,但是也会对这方面的最佳方法感兴趣(也许有更好的方法来获取我所追求的内容?)
这是我到目前为止所做的:
@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所指出的,我需要更正上面的简单初始化方法来制作数据的实际副本:即self.data_copy = data.copy()
。否则,self.data
和self.data_copy
都会指向同一个对象。
答案 0 :(得分:1)
你可以在这做两件事。
您自己发现的第一个:您使用__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
,反之亦然。
答案 1 :(得分:0)
在查看the documentation a little more deeply(向右滚动到底部)之后,我发现有一种由__attrs_post_init__
创建的类的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]])
方法中可能要执行的更复杂的操作。
这是我最后的工作代码:
copy
为了加倍确定,我检查了两个属性是否引用了同一个对象。在这种情况下它们不是,这可能归功于NumPy数组上的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]])
方法。
--Number the rows
;with cte AS (
SELECT ROW_NUMBER() OVER(PARTITION BY companyname, city ORDER BY Address) AS counter_
, *
FROM #company
--convert the number 1's to blanks and subtract each number by 1 so the 2nd record has a 1 appended
), cte2 AS (
SELECT *,
CASE WHEN CAST(counter_ AS varchar(3)) = 1 THEN '' ELSE CAST(CAST(counter_ AS INT) - 1 AS VARCHAR(3)) END AS numberformatting
FROM CTE
)
--if the formatted number is a blank, dont append anything. If it is non-blank, append a hyphen and the number
SELECT DISTINCT CASE WHEN numberformatting = '' THEN companyname + '(' + city + ')' ELSE companyname + '(' + city + '-' + numberformatting + ')' END AS formattedName,
city,
companyname,
city,
address
FROM cte2