【问题标题】:Python - If not statement with 0.0Python - 如果不是 0.0 的语句
【发布时间】:2016-06-05 00:06:08
【问题描述】:

我对@9​​87654322@ 中的if not 语句有疑问。

我已经编写了一些代码并使用了if not 语句。在我编写的代码的一部分中,我引用了一个函数,该函数包含一个if not 语句来确定是否输入了可选关键字。

它工作正常,除非0.0 是关键字的值。我理解这是因为0 是被认为是“不”的事物之一。我的代码可能太长,无法发布,但这是一个类似的(尽管是简化的)示例:

def square(x=None):
    if not x:
        print "you have not entered x"
    else:
        y=x**2
        return y

list=[1, 3, 0 ,9]
output=[]


for item in list:
    y=square(item)
    output.append(y)

print output

但是,在这种情况下,我得到了:

you have not entered x
[1, 9, None, 81]    

我想去哪里:

[1, 9, 0, 81]

在上面的示例中,我可以使用列表推导,但假设我想使用该函数并获得所需的输出,我该怎么做呢?

我的一个想法是:

def square(x=None):
    if not x and not str(x).isdigit():
        print "you have not entered x"
    else:
        y=x**2
        return y

list=[1, 3, 0 ,9]
output=[]


for item in list:
    y=square(item)
    output.append(y)

print output

这可行,但似乎有点笨拙。如果有人有另一种很好的方式,我将非常感激。

【问题讨论】:

  • 你可以通过 type "if type(x) != int:" 来查看
  • 但是如果0 不是其中之一,您要过滤掉哪些值?您不能明确检查这些值吗?
  • 0 在布尔上下文中计算为 False。试试“如果 x 不是无”。
  • 按参数类型重载的函数充其量只是一个可读性问题。更好的是def square(x):def square_vizier():,后者可能会调用前者。假设您阅读了y = square() 行,现在您必须阅读 square 的定义才能看到它在您评论时确实使用了 query.vizier。显式优于隐式。
  • 我只想指出output=[]; for x in input: output.append(fn(x) 模式几乎总是表明您应该使用map 或理解。您的代码减去 square 函数只能是 print map(square, [1, 3, 0, 9])print [square(x) for x in [1,3,0,9]]

标签: python python-2.7 if-statement control-structure


【解决方案1】:

如果您可以识别所有输入都必须兼容的单一类型,那么您可以转换它并处理异常:

def square(x=None):
    try:
        return float(x)**2
    except TypeError:
        print "You did not enter a real number"
        return None # Explicit is better than implicit

这有几个优点。

  • 它强制用户发送给您的任何内容都与float 兼容。这可以是任何数字、包含数字 ('5.0') 的字符串,或者可以转换为 float 的任何其他内容。 (float 实例原封不动地返回。)
  • 很简单。你的方法没有奇怪的魔法。你没有打破鸭子打字。您只是在执行您的要求以使事情正常运行。
  • 它不容易受到与实际检查类型有关的陷阱的影响。您的来电者可以告诉您他们的自定义类型如何转换为float。 Python 提供了__float__ 魔术方法,所以如果你的用户有奇异的类型并且需要使用你的函数,他们不会沉没。
  • 这是惯用的。有经验的 Python 程序员会期待这种代码;它遵循“请求原谅比许可更容易”的原则。

旁白(也许):

如果None 是无效值,请不要将其设为默认值。只需强制调用者提供输入:

def square(x):
    try:
        return float(x)**2
    except TypeError:
        print "You did not enter a real number"
        return None

【讨论】:

    【解决方案2】:

    问题

    你没看错。 not 0(以及not 0.0)在Python 中返回True。可以做个简单的测试看看:

    a = not 0
    print(a)
    
    Result: True
    

    因此,问题得到了解释。这一行:

    if not x:
    

    必须改成别的东西。


    解决方案

    有几种方法可以解决这个问题。我将列出它们,从我认为最好的解决方案到最后可能的解决方案:


    1. 处理所有可能的有效情况

      由于square 应该自然期望一个排除复数的数字输入,否则return 应该出错,我认为最好的解决方案是使用if not isinstance(x, numbers.Number) or isinstance(x, numbers.Complex): 进行评估

      def square(x=None):
          if not isinstance(x, numbers.Number) or isinstance(x, numbers.Complex): # this sums up every number type, with the exclusion of complex number
              print ("you have not entered x")
          else:
              y=x**2
              return y
      
      list=[1, 3, 0 ,9]
      output=[]
      
      for item in list:
          y=square(item)
          output.append(y)
      
      print (output)
      

      numbers.Number 抽象类,用于检查参数 x 是否为数字(感谢 Copperfield 指出这一点)。

      摘自Python Standard Library Documentation 解释了只是你需要什么 - 除了复数:

      numbers.Number

      数字层次结构的根。如果你只是想检查一个 参数x是一个数字,不管是什么,使用isinstance(x, 数)

      但是,您不希望输入是复数。因此,只需使用 or isinstance(x, numbers.Complex) 省略它

      这样,你写squaredefinition 完全你的方式 想要它。我认为这个解决方案是 best 解决方案 它的全面性


    1. 只处理您想要处理的数据类型

      如果您有一个有效的 inpug 数据类型列表,您也可以只列出您想要处理的那些特定数据类型。也就是说,您不想处理您指定的数据类型以外的情况。例子:

      if not instance(x, int): #just handle int
      if not instance(x, (int, float)): #just handle int and float
      if not instance(x, (numbers.Integral, numbers.Rational)): #just handle integral and rational, not real or complex
      

      您可以针对不同的数据轻松地更改/扩展上述条件 您想要包含或排除的类型 - 根据您的 需要。我认为这个解决方案是第二好的,因为它的 对其有效性检查的自定义

      (如cat 建议的那样,上面的代码以更Pythonical 的方式完成)


    1. 不处理不可能的情况:您知道用户会输入什么内容

      如果您知道 - 不是像第二种解决方案那样要处理的数据类型 - 而是用户将 放置的数据类型,那么可以更宽松地考虑一下,那么您可以有更宽松的条件像这样检查:

      if not isinstance(x, numbers.Number): # this is ok, because the user would not put up complex number
      

      我认为,这个解决方案是第三好的,因为它是一个 最简单但功能强大的检查

      此解决方案的唯一缺点是您不处理复杂类型。因此,由于用户不会有复数作为输入,因此只能通过实现。


    1. 仅处理可能导致错误的已知输入错误

      例如,如果您知道 x 总是 intNone - 因此唯一可能的输入错误是 None - 那么我们可以简单地编写逻辑来避免 y 被评估 只有当xNone 像这样:

      def square(x=None):
          if x is None:
              print ("you have not entered x")
          else:
             y=x**2
             return y
      
      list=[1, 3, 0 ,9]
      output=[]
      
      for item in list:
          y=square(item)
          output.append(y)
      
      print (output)
      

      此解决方案的优点是最简单

      ...然而最危险被使用如果你不知道确切用户会为输入提供什么.否则,这个解决方案很好,也是最简单的。

      你的解决方案,我觉得或多或少属于这一类。你知道用户会给出什么输入,用户不会给出什么。因此,使用此解决方案或您自己的解决方案:

      if not x and not str(x).isdigit():
      

      没问题,只是示例解决方案更简单


    根据您的情况,您可以使用上述任何解决方案来获得:

     [1, 9, 0, 81]
    

    (旁注:为了便于阅读,我尝试将解决方案格式化为“规范解决方案”。这样,那些有相同问题并在未来访问此页面的人可能能够找到更全面、更易读的解决方案)

    【讨论】:

    • 第二个条件是自给自足。为什么我们还需要“not x”?
    • 检查类型是个坏主意,因为您必须检查每种可能的类型。对于初学者,您在标准库中有 complex 类型,然后您也永远无法知道是否有人继承了任何标准类型。
    • @Ian 如果你使用if not isinstance(x, (int, float)):,它会更干净,更pythonic
    • isinstance 也更好,因为它知道type 不是的继承和派生类型
    • 另一种方法是使用正确的Abstract Base Classes 来检查是否是正确的实例,在这种情况下它可以是isinstance(x,numbers.Number) 这样您就不需要包括所有可能的实现,如int、float , long 等,只要检查是否是一个数字,如果这是你需要的。对于其他 ABC 检查collections-abstract-base-classes
    【解决方案3】:

    你可以在这里处理异常。编写这样的代码

    def square(x):
        if not x:
            print "you have not entered x"
        else:
            try:
                int(y)=x**2
                return y
            except TypeError:
                pass
    
    
    list=[1, 3, 0 ,9]
    output=[]
    

    【讨论】:

    • 感谢您的选择。我认为这也是一个不错的选择,但是对于我的需要,其他选项已经足够并且更简单了。
    【解决方案4】:
    if x is None:
       print 'x is None'
    

    【讨论】:

    • 感谢您的选择。我最终选择了这个
    【解决方案5】:

    据我了解,您想捕捉没有输入的情况:

    if x is None:
        ...
    

    以及它不是数字的情况。对于第二个,您最终会遇到很多问题,因为您可能希望将来允许 numpy-ndarrays 或其他东西,通常我只是建议不要打扰排除其他类,但如果您只想允许intfloat 然后使用

    if isinstance(x, (int, float, ...)):
        ...
    

    ... 代表其他允许的类(可能是DecimalFractions)。

    所以你可以写成:

    if x is not None and isinstance(x, (int, float)):
         return x**2
    else:
         print "you have not entered x"
    

    因为None 既不是int 也不是float 你也可以省略第一个条件并写成:

    if isinstance(x, (int, float)):
         ...
    

    【讨论】:

    • 感谢您的回答,非常感谢。我确实喜欢第二种选择,但第一种就足够了。很难只选择一个答案!
    【解决方案6】:

    由于您使用None 来表示“未设置此参数”,那么这正是您应该使用is 关键字检查的内容:

    def square(x=None):
        if x is None:
            print "you have not entered x"
        else:
            y=x**2
            return y
    

    检查类型很麻烦且容易出错,因为您必须检查所有可能的输入类型,而不仅仅是int

    【讨论】:

    • 并且在None 的情况下,不应返回无声的None。通常抛出异常,或者显式返回一个标记值。
    • 感谢您的回答!它确实解决了我的问题,并且很容易被接受。我选择了另一个,因为它做了同样的事情并添加了另一个解决方案。对不起
    • @kxr:同意。不过,我不想让这个例子变得复杂。
    猜你喜欢
    • 1970-01-01
    • 2016-03-26
    • 2013-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-08
    相关资源
    最近更新 更多