Python使用日期时间片作为字典键

时间:2014-12-02 16:54:53

标签: python dictionary python-datetime

是否可以使用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

2 个答案:

答案 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,       ......}

    
  

dictslice的{​​{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键,我建议你只需将dictdict放在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