Python 使用 'AND' 运算符的 While 循环

Python While Loop with 'AND' Operator

我不明白为什么下面的代码 return 设置了错误的值。

理想情况下,它应该 return 从今天开始的下一个星期二。相反,它 return 是今天的日期,'2021-08-17':

import datetime

def tue_the_fourth():
    this_d = datetime.date.today()
    if this_d.weekday() ==1 and this_d.day ==4:
        return this_d.strftime("%Y-%m-%d")
    else:
        while (this_d.weekday() is not 1) and (this_d.day is not 4):
            this_d=this_d + datetime.timedelta(days=1)
            print(this_d)
    return this_d.strftime("%Y-%m-%d")

我暂时忽略 is not 的错误使用,让我们关注核心问题:你的 while 测试 几乎总是错误的。当然,您的目标条件是错误的:

>>> (1 is not 1) and (4 is not 4)
False

想想看:

  • 1 is not 1为False,因为1等于1,所以和你测试相反
  • 4 is not 4为False,因为4等于4,所以也和你测试相反

但是,如果您在测试中更改了这些值中的 一个 ,您将 仍然 得到 False:

  • 1 is not 1 为假,
  • 17 is not 4 为真,

但是如果 两个 测试都是真的,你的 while 只循环 运行s,因为你使用了 and。由于今天是星期二,但日期是该月的 17 日,因此 while 循环不会 运行。在其他日子里,它会 运行 直到当前日期之后的第一个星期二,或者当它到达一个月的 4 号时,以先到者为准。

你想 运行 循环是 一个或另一个 是真的,所以你想在这里使用 or,但见下文以获得更好的选择。

注意 correct test for integer inequality, is !=,所以你想使用:

while this_d.weekday() != 1 or this_d.day != 4:

但这样说可能更容易:

while not (this_d.weekday() == 1 and this_d.day == 4):

您可能从 this_d.weekday() == 1 and this_d.day == 4 开始并试图反转该测试,但您不能仅将 not 添加到这些测试并让它通过。您掉进了经典的布尔反转陷阱并想了解 De Morgan's laws:

  • not (A or B) = (not A) and (not B)
  • not (A and B) = (not A) or (not B)

A and B 的倒数是 (not A) or (not B)。但是,有时保持 not (A and B) 测试原样会更清楚。

进一步说明:

  • 您不需要第一个 if 测试。当条件也满足时,循环不会运行,所以整个if分支是多余的。
  • 您可以使用 this_d += datetime.timedelta(days=1) 而不是 this_d = this_d + datetime.timedelta(days=1)。查看增广赋值,这里更简单也更短。
  • 我 return date 对象。这将使您的函数在更多情况下可重用。有时您不需要立即格式化日期对象!

所以,我会写成:

def tue_the_fourth():
    this_d = datetime.date.today()
    while not (this_d.weekday() == 1 and this_d.day == 4):
        this_d += datetime.timedelta(days=1)
    return this_d

并且只有在必须将日期转换为字符串时才格式化日期,越晚越好。

如果我正确理解了您的目标,我会这样写:

def tue_the_fourth():
    d = datetime.date.today()
    while (d.weekday() != 1) or (d.day != 4):
        d = d + datetime.timedelta(days=1)
    print(d)
    return d.strftime("%Y-%m-%d")

有什么变化,为什么?

  1. 使用 is not 作为逻辑 != 是不好的做法并且不准确。

  2. 我将 while 更改为对条件执行逻辑 or 而不是 and,基本上这是获得所需答案的方法。只要我们得到的一天是星期二或 4 号,而不是两者都是,使用答案就会停止。

  3. 整体清洁。不需要 if - else 语句,如果今天是 4 号星期二,则 while 不会 运行 一次,并且返回今天。

两期:

  • 不要将原始值与 isis not 进行比较,而是与 ==!= 进行比较。
  • while条件(错误)不是if条件(正确)的否定

我还会更改算法,这样它就不会一次只执行一天,因为很明显第 4 天不是星期二,none 接下来的几天都是星期二月将是一场比赛。您不妨将日期加一个月,然后再试一次。

此外,您可以创建一个通用函数来查找某个月中的某一天,即某个工作日。

下面是这个想法的实现:

import datetime

def next_month(dt, day, month_count=1):
    try:
        return datetime.datetime(dt.year + int(dt.month + month_count > 12),
                                 (dt.month + month_count - 1) % 12 + 1, day)
    except ValueError:  # invalid day in this month (like 30 February)
        return next_month(dt, day, month_count+1)

def find_next(day, weekday):
    this_d = datetime.date.today()
    this_d = next_month(this_d, day, int(this_d.day > day))
    while this_d.weekday() != weekday:
        this_d = next_month(this_d, day)
    return this_d.strftime("%Y-%m-%d")

# find next 4th on a Tuesday
print(find_next(4, 1))  # 2022-01-04 (when run on 2021-08-17)