Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/361.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何创建月份迭代器_Python - Fatal编程技术网

Python 如何创建月份迭代器

Python 如何创建月份迭代器,python,Python,我想创建一个python函数,它允许我在几个月内从起点迭代到终点。例如,它看起来像 def months(start_month, start_year, end_month, end_year): 调用个月(2010年8月、2011年3月)将返回: ((8, 2010), (9, 2010), (10, 2010), (11, 2010), (12, 2010), (1, 2011), (2, 2011), (3, 2011)) 该函数可以只返回一个元组,但我希望将其视为一个生成器(即使用

我想创建一个python函数,它允许我在几个月内从起点迭代到终点。例如,它看起来像

def months(start_month, start_year, end_month, end_year):
调用
个月(2010年8月、2011年3月)
将返回:

((8, 2010), (9, 2010), (10, 2010), (11, 2010), (12, 2010), (1, 2011), (2, 2011), (3, 2011))
该函数可以只返回一个元组,但我希望将其视为一个生成器(即使用
yield

我检查了
日历
python模块,它似乎没有提供此功能。我可以为循环编写一个讨厌的
,这样做就足够容易了,但我很想看看专业人士可以多么优雅地完成它


谢谢。

也许可以改进此功能的优雅性或速度,但这是一个简单的解决方案:

def months(start_month, start_year, end_month, end_year):
    month, year = start_month, start_year
    while True:
        yield month, year
        if (month, year) == (end_month, end_year):
            return
        month += 1
        if (month > 12):
            month = 1
            year += 1
编辑:这里有一个不那么简单的方法,它甚至可以通过使用生成器来避免使用
yield

def months2(start_month, start_year, end_month, end_year):
    return (((m_y % 12) + 1, m_y / 12) for m_y in
            range(12 * start_year + start_month - 1, 12 * end_year + end_month))

日历是这样工作的

def month_year_iter( start_month, start_year, end_month, end_year ):
    ym_start= 12*start_year + start_month - 1
    ym_end= 12*end_year + end_month - 1
    for ym in range( ym_start, ym_end ):
        y, m = divmod( ym, 12 )
        yield y, m+1

所有多单元的事情都是这样工作的。英尺、英寸、小时、分钟、秒等等。唯一的简单的是月-天或月-周,因为月是不规则的。其他一切都是常规的,您需要在最细粒度的单元中工作。

这不像其他解决方案那么简单,但很容易理解。基本上,它有两个分支

  • 开始年份与结束年份相同
  • 开始年份与结束年份不同
后一种情况分为三个阶段:

  • 从起始月到起始年的12月
  • 从开始年份到结束年份之间的每年的每个月
  • 从1月到年底的月底
如果结束年是开始年之后的一年,则跳过上面的第二阶段(不需要显式测试,范围仅为空)


对于Python3.x,将
xrange
更改为
range

您的问题有点含糊不清,因为您需要一个迭代器,但随后显示一个返回元组元组的函数。这两个都是:

import calendar
import datetime

def months_iter(start_month, start_year, end_month, end_year):
    start_date = datetime.date(start_year, start_month, 1)
    end_date = datetime.date(end_year, end_month, 1)
    date = start_date
    while date <= end_date:
        yield (date.month, date.year)
        days_in_month = calendar.monthrange(date.year, date.month)[1]
        date += datetime.timedelta(days_in_month)

def months(start_month, start_year, end_month, end_year):
    return tuple(d for d in months_iter(start_month, start_year, end_month, end_year))

print months(8, 2010, 3, 2011)

# ((8, 2010), (9, 2010), (10, 2010), (11, 2010), (12, 2010), (1, 2011), (2, 2011), (3, 2011))
导入日历
导入日期时间
定义月份(开始月份、开始年份、结束月份、结束年份):
开始日期=日期时间.日期(开始年份,开始月份,1)
结束日期=日期时间.日期(结束年份,结束月份,1)
日期=开始日期

虽然date对Python内置迭代器有点兴趣,但肯定不是优雅的;)

从日期时间导入时间增量,日期

class MonthRange:
    def __init__ (self, date1, date2):
        self.start_date = date1 - timedelta(days=1)
        self.end_date = date2
        self.data = self.start_date
    def __iter__(self):
        return self
    def next(self):
        if self.data >= self.end_date.replace(day=1) + timedelta(days=32):
            raise StopIteration
        ret = self.data
        self.data = self.data + timedelta(days=32)
        return ret.replace(day=1)

for x in MonthRange(date.today(), date(2012, 11, 01)):
    print (x.year, x.month)

dfan方法的更简单版本,也是比s.Lott方法更简单的解决方案(无除法,无模):

def月数(开始月、开始年、结束月、结束年):
月,年=开始月,开始年
而(年、月)12:
月份=1
年份+=1

这种方法接近于如果他们必须手工操作的话所使用的方法。它的运行时间与S.Lott的相同(上面代码中的测试所花费的时间与除法和模的时间差不多)。

months
函数使用
dateutil
模块

from dateutil.rrule import rrule, MONTHLY
from datetime import datetime

def months(start_month, start_year, end_month, end_year):
    start = datetime(start_year, start_month, 1)
    end = datetime(end_year, end_month, 1)
    return [(d.month, d.year) for d in rrule(MONTHLY, dtstart=start, until=end)]
示例用法

print months(11, 2010, 2, 2011)
#[(11, 2010), (12, 2010), (1, 2011), (2, 2011)]
或者以迭代器的形式

def month_iter(start_month, start_year, end_month, end_year):
    start = datetime(start_year, start_month, 1)
    end = datetime(end_year, end_month, 1)

    return ((d.month, d.year) for d in rrule(MONTHLY, dtstart=start, until=end))
迭代器用法

for m in month_iter(11, 2010, 2, 2011):
    print m
    #(11, 2010)
    #(12, 2010)
    #(1, 2011)
    #(2, 2011)

由于其他人已经为生成器提供了代码,我想补充一点,Pandas有一个名为“”的方法,在本例中,该方法可以接受开始和结束、年份和月份,并返回适合迭代的周期索引

import pandas as pd

pr = pd.period_range(start='2010-08',end='2011-03', freq='M')

prTupes=tuple([(period.month,period.year) for period in pr])

#This returns: ((8, 2010), (9, 2010), (10, 2010), (11, 2010), (12, 2010), (1, 2011), (2, 2011), (3, 2011))

为什么专业人士不应该使用两个嵌套循环编写一些代码。可读性更好,代码更详细,而不是使用花哨的语言功能的密集而复杂的代码,这些功能在一天后很难理解。好的解决方案肯定会涉及至少一个for循环,但我能想到的唯一方法也包括各种if,即,
if start\u year==end\u year
如果结束年份-开始年份>1
等。。。似乎还有比这更漂亮的解决方案。
dateutil
模块在这里可能很有用,它可能是使月末成为独占的,比如范围。另见:同意,我只是在匹配问题陈述。这就是我所寻找的美。我绝对没有那样想过。非常感谢。回答得很好,但是所有常规的事情都不是这样的,因为月份是从1..12开始计算的,而不是从0..11(比如英尺和英寸)。@martineau:True。但是所有的事情都在它们最细粒度的单元中运行良好。(不定期的月份除外)。±1是一种编码上的细微差别,通常很明显。从你的评论中,我想这并不总是显而易见的。@martineau:这不是一个真正的“微妙之处”。但是谢谢。我肯定有人被序数和基数搞糊涂了。为了得到一个月的天数(包括闰年特例),Python有一个方便的函数。需要注意的是,它是一个第三方模块。
for m in month_iter(11, 2010, 2, 2011):
    print m
    #(11, 2010)
    #(12, 2010)
    #(1, 2011)
    #(2, 2011)
    for year in range(2014, 2018):
        for month in range(start_month_number, 13):
            this_month = datetime.date.today().replace(year=year, month=month, day=1)
import pandas as pd

pr = pd.period_range(start='2010-08',end='2011-03', freq='M')

prTupes=tuple([(period.month,period.year) for period in pr])

#This returns: ((8, 2010), (9, 2010), (10, 2010), (11, 2010), (12, 2010), (1, 2011), (2, 2011), (3, 2011))