[英]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.