是否可以使用datetime
slice
作为字典键?
示例:
st = datetime.datetime(2010, 12, 31, 0, 0)
en = datetime.datetime(2011, 12, 28, 0, 0)
b = []
b[slice(st,en)] = 'some_random_value_could_be_anything' # Error!
发生以下两个错误之一:
在单字典中:
TypeError: slice indices must be integers or None or have an __index__ method
在嵌套字典中:
TypeError: unhashable type
答案 0 :(得分:3)
免责声明:这个答案主要是说明Python允许您做的事情之一。此外,您可能 NOT 想要以这种方式做事(事实上可以做事情并不意味着你应该)
这就是getitem(self, key)州的文件:
对于序列类型,接受的键应该是整数和切片 对象。
这意味着任何想要模仿 sequence type 行为的类(例如列表)都必须准备好实现__getitem__
,其中key可以是输入slice。那种(有点)解释(或者至少,某种程度上与之相关)为什么在你的词典中,当你尝试TypeError: unhashable type
时,你得到b[slice(st,en)] = 'bla '
:这是因为它试图使用{{ 1}}实例作为字典键。 slice(st, en)
个对象不可清除,因此不能用作slice
个键。 dict
类型 NOT 是一种序列类型,因此尝试切片字典没有任何意义。
假设你有:
{ ......'foo':1, ......'酒吧':2, ......'baz':3, ......}
从dict
到slice
的{{1}}是什么意思?你会按照输入的顺序返回一组键吗? ('foo','bar','baz')? Python不知道这一点。会是他们的'foo'
吗?这是内部的,当它如此切割时毫无意义。
所有这些都说,这是一件非常非常糟糕的事情......但是“有效”:
'bar'
输出:
__hash__
但是糟糕,坏的...... import datetime
class DatetimeDict(dict):
def __getitem__(self, key):
if isinstance(key, slice):
sliced = {}
start_dt = key.start
stop_dt = key.stop
step = key.step or 1
internal_keys = sorted(self.keys())
if start_dt is None:
start_index = 0
else:
start_index = internal_keys.index(start_dt)
end_index = internal_keys.index(stop_dt)
for i in range(start_index, end_index, step):
sliced.update({internal_keys[i]: self[internal_keys[i]]})
return sliced
else:
return super(DatetimeDict, self).__getitem__(key)
def __setitem__(self, key, val):
return super(DatetimeDict, self).__setitem__(key, val)
a = DatetimeDict()
a[datetime.datetime.strptime('2014/01/01', '%Y/%m/%d')] = 'foo',
a[datetime.datetime.strptime('2014/01/02', '%Y/%m/%d')] = 'bar',
a[datetime.datetime.strptime('2014/01/03', '%Y/%m/%d')] = 'baz',
a[datetime.datetime.strptime('2014/01/04', '%Y/%m/%d')] = 'bla',
from_dt = datetime.datetime.strptime('2014/01/02', '%Y/%m/%d')
to_dt = datetime.datetime.strptime('2014/01/04', '%Y/%m/%d')
print a[from_dt:to_dt]
变成了一个奇怪的构造,它是一个字典,但同时表现得像一个序列类型... 坏强>
你实际上并没有尝试切片{
datetime.datetime(2014, 1, 2, 0, 0): ('bar',),
datetime.datetime(2014, 1, 3, 0, 0): ('baz',)
}
,你在哪里?在我学会阅读的那一天,我将征服世界...... :-D
如果你想要的是使用一系列日期时间作为DatetimeDict
键,我建议你只需将dict
和dict
放在start
中:
end
Weeeelllll ......至少我学会了切片和那种东西...... LoL ......
答案 1 :(得分:2)
您可以从两个日期时间创建slice
对象。
你可以试着用它切片。但是如果开始或结束是对象,则list
通过调用这些对象的__index__
将此对象解析为整数值here。这是你得到的第一个错误。
您遇到的第二个错误是因为您无法为hash
对象创建slice
。 Python总是为关键对象生成hash
值,因为字典类似于哈希列表。切片字典是不可能的,你可以阻止辅助函数以某种方式模拟该行为。另一个apporach将使用元组作为字典键,以便您可以避免使用slice
。元组是hashables。
您可以尝试使用建议的方法为扩展日期时间类实现__index__
方法。
class MyDateTime(datetime.datetime):
def __index__(self):
# in your case return number of minutes (in this case since 1970/1/1)
return int((self-datetime.datetime(1970,1,1)).total_seconds()/60)
st = MyDateTime(2010, 12, 31, 0, 0)
en = MyDateTime(2011, 12, 28, 0, 0)
b = []
b[slice(st,en)] = [100]
在此示例中,您将使用与分钟对应的最小公倍数。这将是最有用的,但更大的步骤也可能适合您。
但我不建议用slice
和列表实现一些日期时间间隔。我打赌你会遇到性能或复杂性等其他问题。
您还没有添加您尝试解决的问题。我可能是对的,你想检查DateTimeIntervals是否有重叠等等。如果是,请查看DateTimeInterval。