【问题标题】:Accessing attributes on literals work on all types, but not `int`; why? [duplicate]访问文字上的属性适用于所有类型,但不适用于 `int`;为什么? [复制]
【发布时间】:2016-01-08 08:16:16
【问题描述】:

我读到 python 中的所有东西都是一个对象,因此我开始尝试不同的类型并在它们上调用 __str__ — 起初我感到非常兴奋,但后来我糊涂了。

>>> "hello world".__str__()
'hello world'
>>> [].__str__()
'[]'
>>> 3.14.__str__()
'3.14'
>>> 3..__str__()
'3.0'
>>> 123.__str__()
  File "<stdin>", line 1
    123.__str__()
              ^
SyntaxError: invalid syntax
  • 为什么<em>something</em>.__str__() 对除了int 之外的“一切”都有效?
  • 123 不是int 类型的对象

【问题讨论】:

  • 查看消息内容:invalid syntax。这表明这与构造的含义无关,仅与您如何写下来有关。
  • @Rusian 两个不同的问题,有自己的答案,被合并了;这就是时间戳看起来有点奇怪的原因。

标签: python python-2.7 python-3.x language-lawyer


【解决方案1】:

你需要括号:

(4).__str__()

问题是词法分析器认为“4”。将是一个浮点数。

另外,这可行:

x = 4
x.__str__()

【讨论】:

  • 我更喜欢在这里使用括号而不是空格。
  • 其他语言也是如此,比如 Javascript。
  • @Bergi 你读过这个该死的问题了吗?
【解决方案2】:

所以你认为你可以跳舞浮点数?

1233.14 一样是一个对象,“问题”在于语言的语法规则;解析器认为我们将要定义一个 float——而不是一个带有尾随方法调用的 int

如果我们将数字括在括号中,我们将得到预期的行为,如下所示。

>>> (123).__str__()
'123'

或者如果我们只是在123之后添加一些空格:

>>> 123 .__str__()
'123'


它不适用于123.__str__() 的原因是123 后面的 被解释为小数点一些部分声明的浮点

>>> 123.__str__()
  File "", line 1
    123.__str__()
              ^
SyntaxError: invalid syntax

解析器尝试将__str__() 解释为数字序列,但显然失败了——我们得到一个SyntaxError,基本上说解析器偶然发现了一些它没有预料到的东西。



细化

当查看123.__str__() 时,python 解析器可以使用 3 个字符并将这些 3 个字符解释为一个 整数或者它可以使用 4 个字符并将这些字符解释为 浮点开始

123.__str__()
^^^ - int
123.__str__()
^^^^- start of floating-point

就像小孩子想要盘子里尽可能多的蛋糕一样,解析器也很贪婪,想要一次吞下尽可能多的东西——即使这并不总是最好的想法——因为选择后一种(“更好”)替代方案。

当它后来意识到__str__() 决不能被解释为浮点小数时,已经太迟了; 语法错误

注意

 123 .__str__() # works fine

在上面的 sn-p 中,123 (注意空格)必须被解释为 整数,因为没有 数字 可以包含空格。这意味着它在语义上等同于(123).__str__()

注意

 123..__str__() # works fine

上述方法也有效,因为一个数字最多可以包含一个小数点,这意味着它等价于(123.).__str__()



对于语言律师

本节包含相关文字的词法定义。

Lexical analysis - 2.4.5 Floating point literals

floatnumber   ::=  pointfloat | exponentfloat
pointfloat    ::=  [intpart] fraction | intpart "."
exponentfloat ::=  (intpart | pointfloat) exponent
intpart       ::=  digit+
fraction      ::=  "." digit+
exponent      ::=  ("e" | "E") ["+" | "-"] digit+

Lexical analysis - 2.4.4 Integer literals

integer        ::=  decimalinteger | octinteger | hexinteger | bininteger
decimalinteger ::=  nonzerodigit digit* | "0"+
nonzerodigit   ::=  "1"..."9"
digit          ::=  "0"..."9"
octinteger     ::=  "0" ("o" | "O") octdigit+
hexinteger     ::=  "0" ("x" | "X") hexdigit+
bininteger     ::=  "0" ("b" | "B") bindigit+
octdigit       ::=  "0"..."7"
hexdigit       ::=  digit | "a"..."f" | "A"..."F"
bindigit       ::=  "0" | "1"

【讨论】:

    【解决方案3】:

    4后面加一个空格:

    4 .__str__()
    

    否则,词法分析器会将此表达式拆分为标记"4.""__str__""("")",即第一个标记被解释为浮点数。词法分析器总是尝试构建尽可能长的标记。

    【讨论】:

    • 好的,但是为什么词法分析器会尝试构建像 4. 这样的最长标记,为什么 4. 在 python 中是一个数字?
    • @Abderrahimben:大多数编程语言的词法分析器通过构建尽可能长的标记来工作。具有歧义标记化的情况通常很少见,应该避免,并且尝试自动解决歧义会使词法分析器显着复杂化。 4. 是一个有效的浮点数,它适用于我所知道的所有编程语言,包括 Python。
    • @SvenMarnach 目前一种例外的编程语言是 C#。它使4 成为int 类型的有效文字,4.0 成为double 类型的有效文字,但4. 是两个单独的标记。这样,double d = 4.; 是不允许的,但用户可以简单地写double d = 4.0;。这样,string s = 4.ToString(); 被允许的。 (您确实说过“[您] 知道的所有编程语言”,所以如果您不了解 C#,您并没有错,但这对其他人来说可能是一个有用的补充。)
    【解决方案4】:

    实际上(增加不可读性...):

    4..hex()
    

    也是有效的。它给出了'0x1.0000000000000p+2'——但它是一个浮点数,当然......

    【讨论】:

      猜你喜欢
      • 2020-03-03
      • 2021-12-24
      • 1970-01-01
      • 2020-03-09
      • 2014-09-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-21
      相关资源
      最近更新 更多