Python: 如果三个条件中有多个为真,则返回假

12 投票
11 回答
5867 浏览
提问于 2025-04-16 21:28

我正在写一个django模型,让我的网站可以使用优惠券。

优惠券可以有三种类型:终身账户券、特定月份的券和特定金额的券。

为了简单起见,我只允许优惠券有这三种可能的值中的一种(也就是说,一个优惠券不能同时是10美元和5个月的券)。但是我想在保存优惠券的时候检查一下,确保这个规则是正确的。

目前我有:

true_count = 0
if self.months:
    true_count += 1
if self.dollars:
    true_count += 1
if self.lifetime:
    true_count += 1    

if true_count > 1:
    raise ValueError("Coupon can be valid for only one of: months, lifetime, or dollars")  

我知道有更好的方法来做到这一点,但我现在想不出来(可以说是程序员的瓶颈)。

非常感谢任何帮助。

如果有用的话,这三种类型分别是整数、整数和布尔值。

months = models.IntegerField(default=0)
cents = models.IntegerField(default=0)
#dollars = models.FloatField(default=0.00)
#dollars replaced with integer cents per advice of group
lifetime = models.BooleanField(default=False)

11 个回答

2
if (self.months && (self.dollars || self.lifetime))  || (self.dollars && (self.months || self.lifetime)) || (self.lifetime && (self.dollars || self.months))
    raise ValueError("Coupon can be valid for only one of: months, lifetime, or dollars") 

编辑:

我用卡诺图(Karnaugh map)做了个快速的电路简化(可以参考这个链接:http://en.wikipedia.org/wiki/Karnaugh_map)。最后得出的结果是,这个是用布尔逻辑能得到的最小函数:

if((self.months && self.dollars) || (self.dollars && self.lifetime) || (self.lifetime && self.months))
    raise ValueError("Coupon can be valid for only one of: months, lifetime, or dollars") 

从逻辑上讲,我的两个说法是等价的,但第二个在技术上更快/更高效。

编辑 #2:如果有人感兴趣,这里是卡诺图的结果

A | B | C | f(A, B, C)
----------------------
0 | 0 | 0 |     0
----------------------
0 | 0 | 1 |     0
----------------------
0 | 1 | 0 |     0
----------------------
0 | 1 | 1 |     1
----------------------
1 | 0 | 0 |     0
----------------------
1 | 0 | 1 |     1
----------------------
1 | 1 | 0 |     1
----------------------
1 | 1 | 1 |     1

简化为:

   C\AB
     -----------------
     | 0 | 0 | 1 | 0 |     
     -----------------      OR      AB + BC + AC
     | 0 | 1 | 1 | 1 |
     -----------------
5

你也可以用列表推导式来过滤掉那些假的值:

if len([x for x in [self.months, self.dollars, self.lifetime] if x]) > 1:
    raise ValueError()

或者可以参考一下MRAB的回答来进行扩展:

if sum(map(bool, [self.months, self.dollars, self.lifetime])) > 1:
    raise ValueErrro()
13

在类似的情况下,我做过的一件事是这样的:

coupon_types = (self.months, self.dollars, self.lifetime,)

true_count =  sum(1 for ct in coupon_types if ct)
if true_count > 1:
    raise ValueError("Coupon can be valid for only one of: months, lifetime, or dollars")  

现在将来添加新的优惠券类型来检查变得简单多了!

撰写回答