【问题标题】:A weird string literal identity issue in DjangoDjango 中一个奇怪的字符串文字标识问题
【发布时间】:2016-07-22 16:13:02
【问题描述】:

我正在处理的 Django 项目中有一个 API,用于向设备发送命令。 API 需要一个 POST 请求,其中包含类似{"command": "activate"} 的数据。几分钟前,我在 API 的视图函数中发现了这段代码

...为简洁起见,省略 DRF 视图集类 def ... def 命令(自我,请求): 如果 request.data 和 request.data['command'] 中的“命令”不是“激活”: ...做我们需要做的事情来发送激活命令...

我发现有人(很可能是我自己)犯了一个逻辑错误并将其修复为request.data['command'] is 'activate',但立即意识到 API 确实可以正常工作。就是这个 if 语句评估为 True 并且即使它明确指出 request.data['command'] is not 'activate'

也会发送命令

于是我开始调试,最终发现request.data['command'] != 'activate' 按预期返回 False 并破坏了代码,但 request.data['command'] is not 'activate' 返回 True。据我所知,is not!= 之间的区别在于is not 比较身份,而!= 比较值。但是,据我所知,文字应该具有相同的身份,无论它们来自哪里。在 ipython 中的快速测试似乎证实了这一点

在 [1] x = {'command': 'activate'} 在 [2] 中,x['command'] 是 'activate' 出[2]真 在 [3] 中,x['command'] 不是“激活” 出[3] 假

这到底是怎么回事?为什么它在视图中不起作用?

【问题讨论】:

  • 文字无论来自哪里都应该具有相同的标识,这并不完全正确。这严格依赖于实现

标签: python django


【解决方案1】:

在任何情况下都不要依赖于通过身份进行字符串比较。它有时会起作用的事实是由于CPython的一个实现细节称为字符串实习。管理给定字符串是否将被保留的规则非常复杂,并且如有更改,恕不另行通知。

例如,对您的原始示例稍作修改,我们可以改变行为:

>>> x = {'command': 'activate.'}
>>> x['command'] is 'activate.'
False

使用==!= 进行字符串比较。

【讨论】:

    【解决方案2】:

    但是,据我所知,文字应该具有相同的标识,无论它们来自哪里。

    首先,事实并非如此。与 Java 不同,Python 不保证文字是否被实习:

    In [1]: x = 'a b'
    
    In [2]: x is 'a b'
    Out[2]: False
    

    其次,request.data['command'] 中的 'activate' 来自已解析的网络请求,而不是字符串文字。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-16
      • 2011-07-27
      • 1970-01-01
      • 2018-08-13
      • 1970-01-01
      相关资源
      最近更新 更多