[英]Representing a Range of values in Python
我有兴趣在Python中表示一个类似于Guava的Range
类型的Range
。 具体来说,它应该有一个起点和终点,并且代表两者之间的所有值(作为第一步,我很好,只代表标准的开闭范围,即[5,10)
,但是任何开路的正确表示/ closed range是一个合理的功能)。
我知道内置的range()
,但我的目的是支持任意类型(对于我的用例,具体来说是日期)。
从Python的类型层次结构看 ,似乎从逻辑上看,范围可以是Sequence
或Set
类型,但我不确定哪个更有意义,如果最好是不将我的类放到该层次结构中并简单地实现我的行为,想。
按Sequence
:
[0,+∞)
,所以上面的可能不正确。 作为一Set
:
作为单独的结构:
range.slice()
方法) Range
不能从Collection API扩展的事实似乎支持了这一论点。 我很好奇这里似乎是最Pythonic的东西,以及是否有人自己制作了这样的数据结构。
这是到目前为止我提出的实现。 Range
对象表示任意的openClosed范围,并且可以哈希,包含和迭代,但是既不是序列也不是集合。 DateRange
子类表示日期范围,主要是只需timedelta(days=1)
增量参数定义为timedelta(days=1)
而不是简单的1
。
class Range:
'''
Represents a range, in the spirit of Guava's Range class.
Endpoints can be absent, and (presently) all ranges are openClosed.
There's little reason to use this class directly, as the range()
builtin provides this behavior for integers.
'''
def __init__(self, start, end, increment=1):
if start and end and end < start:
raise ValueError("End date cannot be before start date, %s:%s" % (start,end))
self.start = start
self.end = end
self.increment = increment
def __repr__(self):
return '[%s\u2025%s)' % (
self.start or '-\u221E',
self.end or '+\u221E'
)
def __eq__(self, other):
return self.start == other.start and self.end == other.end
def __hash__(self):
return 31*hash(self.start) + hash(self.end)
def __iter__(self):
cur = self.start
while cur < self.end:
yield cur
cur = cur + self.increment
def __contains__(self, elem):
ret = True
if self.start:
ret = ret and self.start <= elem
if self.end:
ret = ret and elem < self.end
return ret
class DateRange(Range):
'''A range of dates'''
one_day = timedelta(days=1)
@staticmethod
def parse(daterange):
'''Parses a string into a DateRange, useful for
parsing command line arguments and similar user input.
*Not* the inverse of str(range).'''
start, colon, end = daterange.partition(':')
if colon:
start = strToDate(start) if start else None
end = strToDate(end) if end else None
else:
start = strToDate(start)
end = start + DateRange.one_day
return DateRange(start, end)
def __init__(self, start, end):
Range.__init__(self, start, end, DateRange.one_day)
def strToDate(date_str):
'''Parses an ISO date string, such as 2014-2-20'''
return datetime.datetime.strptime(date_str, '%Y-%m-%d').date()
一些用法示例:
>>> DateRange(datetime.date(2014,2,20), None)
[2014-02-20‥+∞)
>>> DateRange(datetime.date(2014,1,1), datetime.date(2014,4,1))
[2014-01-01‥2014-04-01)
>>> DateRange.parse(':2014-2-20')
[-∞‥2014-02-20)
>>> DateRange.parse('2014-2-20:2014-3-22')
[2014-02-20‥2014-03-22)
>>> daterange = DateRange.parse('2014-2-20:2014-3-2')
>>> daterange
[2014-02-20‥2014-03-02)
>>> datetime.date(2014,1,25) in daterange
False
>>> datetime.date(2014,2,20) in daterange
True
>>> list(daterange)
[datetime.date(2014, 2, 20), datetime.date(2014, 2, 21), datetime.date(2014, 2, 22),
datetime.date(2014, 2, 23), datetime.date(2014, 2, 24), datetime.date(2014, 2, 25),
datetime.date(2014, 2, 26), datetime.date(2014, 2, 27), datetime.date(2014, 2, 28),
datetime.date(2014, 3, 1)]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.