Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/.htaccess/6.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:如果三件事中有一件以上是真的,则返回false_Python_Django - Fatal编程技术网

Python:如果三件事中有一件以上是真的,则返回false

Python:如果三件事中有一件以上是真的,则返回false,python,django,Python,Django,我正在写一个django模型,它允许我的网站有优惠券 优惠券可以有三种类型:终身账户凭证、特定期间的月凭证、特定数量的美元凭证 为了简单起见,我只允许优惠券具有三个可能值中的一个(即,优惠券不能为10美元和5个月)。但我想检查优惠券何时被保存,以确保这条规则是正确的 目前我有: true_count = 0 if self.months: true_count += 1 if self.dollars: true_count += 1 if self.lifetime:

我正在写一个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")  
我知道有更好的方法可以做到这一点,但我没有看到它(称之为编码块)

非常感谢你的帮助

如果需要,三种类型是int、int和bool

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)
编辑:

我用卡诺图做了一个快速的电路模拟(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:如果有人感兴趣,这里有K地图

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 |
     -----------------

我不知道这是否对你更有利,但这样做会奏效:

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

bool
int
的一个子类,因为Python最初缺少
bool
,使用
int
表示布尔值,因此:

if self.months + self.dollars + self.lifetime > 1:
    ...

这是因为
False==0
True==1
都是真的。

您的代码看起来不错。原因如下:

1.)是你写的,你是描述逻辑的人。你可以使用各种各样的语法技巧来减少代码行数(如果self.months else 0,那么true_count+=1,如果self.months else 0,那么巨大的if语句,等等),但我认为你的方法是完美的,因为这是你在试图描述逻辑时首先想到的

留下可爱的代码来迎接编程挑战,这是真实的世界


2.)如果您决定需要添加另一种类型的息票价值类型,您完全知道您需要做什么:添加另一种If语句。在一个复杂的if语句中,完成这项任务会更加困难。

将数量保留在单个字段中,并将类型设置为使用
选项的单独字段。
您还可以使用列表comp来过滤假值:

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


我认为将其扩展到几行就可以了——如果将来有更多的属性需要测试,那么维护起来就更容易了。使用
len
sum
感觉有点太模糊了

# Ensure that only one of these values is set
true_count = 0
true_count += bool(self.months)
true_count += bool(self.dollars)
true_count += bool(self.lifetime)

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

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")  

现在更容易添加新的优惠券类型,以检查在未来

比以前更好的解决方案,使用
组合
任意
全部
。 假设您在一个名为
attributes
的序列中拥有所有要测试的属性:

from itertools import combinations
any(map(all, combinations(attributes, 2)))
在英语中,它是这样写的

任何长度为2的属性组合都是真的吗

此解决方案适用于任意数量的属性,可以修改以测试任意数量的属性是否为真


尽管承认它效率很低,但我认为它很可爱,可读性也很好。

如果你有Python2.7或更新版本的话

from collections import Counter
items_to_test = (self.months, self.dollars, self.lifetime)
true_count = Counter(map(bool, items_to_test))[True]
怎么样

if len(filter([self.months, self.dollars, self.lifetime])) > 1:
...


我发现它与带有
if
子句的列表理解一样可读,而且更简洁。

虽然代码行数较少,但它使代码更难理解。我会在更少的代码行上增加可读性。请查看我编辑的答案。它更容易阅读,也是我能想到的最有效的算法。当潜在值的数量达到4时,它是如何扩展的?也就是说,如果业务需求发生变化,并且凭证也适用于整数数量的小马,则凭证将变为6
s,由逻辑
s分隔。它可以像任何具有多个输入的逻辑电路一样扩展,就像K-Map思想一样;我认为我对它的实现(如下)更具可读性,因为它的功能性很差,而且扩展性更好。如果self.months为2,这将给出一个假阳性。在求和之前,你需要将变量转换成布尔值。在我发布之后,我一直在考虑这个可能的解决方案。我想知道您提出的方法或当前的方法是否具有更好的容错性。我认为这里的主要问题是“数量”字段需要存储不同的类型。一个float可以存储所有这些,但是您真的想在float字段中存储布尔值吗?然而,我赞成另一个明确列出类型的字段,因此我使用+1。无论如何,不应该将钱存储在浮点数中。把它改为整数美分。将货币存储为整数美分和浮点的基本原理是什么?在某些应用程序中(不是这一个),有部分美分需要跟踪。无需担心-快速访问谷歌找到了答案。谢谢。这个解决方案让我有点发笑——如果没有一个包含列表理解的解决方案,这将不是一个python问题。
sum(bool(x)代表x in(self.months,self.dollars,self.life))
我不同意这种观点,我认为OP希望改进他的代码是件好事。一旦你有超过几个像这样的if语句,它就会开始看起来很混乱。一个更优雅的解决方案是可能的,而不会失去清晰度。还有一些其他的解决方案(包括我的)是非常清楚的,并且在将来更容易扩展。我也不同意。虽然有可能变得过于聪明,但它非常清晰易懂,而且易于扩展。在问了9个深思熟虑的答案后1小时,这就是为什么我喜欢StackOverflow。这会让许多程序员在手册页上停留半小时或更长时间,所以我不能说它在大多数商店都是可维护的。但是我必须同意,这很可爱。@Ted:哈哈,是的,对于建设性的批评+1,但我确实认为如果你对代码进行了很好的注释,即使是新手程序员也可能理解su背后的逻辑
from collections import Counter
items_to_test = (self.months, self.dollars, self.lifetime)
true_count = Counter(map(bool, items_to_test))[True]
if len(filter([self.months, self.dollars, self.lifetime])) > 1:
...