为什么不同数字格式的转换在Python中无法正常工作?

时间:2017-08-01 22:06:21

标签: python python-3.x type-conversion

这有效:

[IN]  int(str(8))
[OUT] 8

这不起作用:

[IN]  int(bin(8))
[OUT] ValueError: invalid literal for int() with base 10: '0b1000'

[IN]  int(hex(8))
[OUT] ValueError: invalid literal for int() with base 10: '0x8'

这也很奇怪:

[IN]  bin(str(8))
[OUT] TypeError: 'str' object cannot be interpreted as an integer 
# What are you telling me, Python?! You just did it with int()!

可是:

[IN]  float(str(8))
[OUT] 8.0

更糟糕的是:

[IN]  int(8.5)
[OUT] 8
[IN]  int(str(8.5))
[OUT] ValueError: invalid literal for int() with base 10: '8.5'
[IN]  float(str(8.5))
[OUT] 8.5           # IT WORKS??!

这会使int(some_string)成为一个糟糕的选择,而应该首选int(float(some_string))

或者:

[IN]  hex(hex(8))
[OUT] TypeError: 'str' object cannot be interpreted as an integer

错误设计:将对象转换为其所属类型的方法应始终接受其自己的类型作为有效输入。 (我知道类型是str,但无论如何)。

[IN]  complex(str(complex(8)))
[OUT] (8+0j)
# What are the rules again?
[IN]  int(abs(complex(str(8.5))))
[OUT] 8
# OK... I guess?

这对我来说似乎非常反Pythonic。是否存在设计上的原因,为什么这些非常直观的转换不起作用,或者仅仅是没有人想到并且需要改进的东西?或者我可能做错了吗?

我找到的唯一解决方案是

[IN]  eval(hex(8))
[OUT] 8
[IN]  eval(bin(8))
[OUT] 8

3 个答案:

答案 0 :(得分:1)

int构造函数接受第二个参数来指定应该解释第一个字符串参数的基础。因此,如果您指定了base {binhex,那么您的示例将起作用{分别为{1}}和2。 Python不会使用数字上的前缀来为你猜测基数,除非你指定“特殊”基数16,它告诉它使用前缀来确定基数(否则会忽略适当的前缀和无效的前缀)引起例外)。您可以在异常消息中看到您的问题与基础相关,具体说输入值无效“for base()with base 10”。

类似地,Python在创建0时不会隐式截断小数值的字符串表示的小数部分。如果要将字符串int转换为整数"8.5",则需要先将字符串解析为float(例如8),然后将该值转换为整数,丢弃小数部分(例如val = float("8.5"))。您当然可以将它们链接在一起(int_val = int(val)),但Python不会自动为您执行组合操作。

答案 1 :(得分:1)

我认为你在这里有一些基本的误解。让我们来看看你提到的各种功能。首先,让我们看看int,然后尝试运行help

>>> help(int)
class int(object)
 |  int(x=0) -> int or long
 |  int(x, base=10) -> int or long
 |  
 |  Convert a number or string to an integer, or return 0 if no arguments
 |  are given.  If x is floating point, the conversion truncates towards zero.
 |  If x is outside the integer range, the function returns a long instead.
 |  
 |  If x is not a number or if base is given, then x must be a string or
 |  Unicode object representing an integer literal in the given base.  The
 |  literal can be preceded by '+' or '-' and be surrounded by whitespace.
 |  The base defaults to 10.  Valid bases are 0 and 2-36.  Base 0 means to
 |  interpret the base from the string as an integer literal.
 |  >>> int('0b100', base=0)
 |  4

所以int(foo)将字符串或数字类型转换为整数。似乎是合理的。

>>> help(bin)
bin(...)
    bin(number) -> string

    Return the binary representation of an integer or long integer.

此处bin(foo)将整数转换为字符串(例如:"0b1010111"

请注意,python中的数字不是binhex - 这些是基数。它们是数字,可以存储为intfloatlong等。为了方便您,翻译很乐意转换为1e621.40x120777分别代表相应的数字,但这并不意味着这些数字具有" string"作为本机格式,或者给出表示的数字的基数与值一起存储。

您混淆的根源似乎是您将str作为第一类对象 - 也许是因为这是用于键入代码的内容?句子(强调我的):

  

错误设计:将对象转换为其所属类型的方法应始终接受其自己的类型作为有效输入。 (我知道类型是str,但无论如何)

突出显示此根。

假设bin适用于字符串以及python中的整数有点傻,就像预期的int("the smallest prime larger than the population of florida")有点傻一样。他们按照他们的记录去做。

像Wolfram Alpha这样松散的语言可能会大步采取这些措辞,而像Haskell这样的严格语言可能会嘲笑甚至允许同一函数使用多种类型和参数计数的概念。

为了完整性:

  • bin('8')hex('0x8')#正确拒绝非整数
  • int('0b1000')int('0x8')int('8.5')#正确拒绝非整数字符串
  • int('0b1000', base=0)int('0x8', base=0)#根据字符串基础正确执行较慢的解释
  • int('8.5', base=0)#仍然正确拒绝非整数字符串
  • int(8.5)#正确'将浮点数截断为0'
  • eval(foo)#请避免使用eval,此函数没有常见的正确应用

强调Alan Leuthard的评论:

  

有两个不同的int()函数。一个人接受一个输入   并且非常快。另一个是较慢的,允许铸造   不同的基础。经常使用的内置功能的效率是   缺乏你想要的功能的原因。

答案 2 :(得分:0)

我们在这里看到:

  

这有效:

[IN]  int(str(8))
[OUT] 8 This does not work:

[IN]  int(bin(8))
[OUT] ValueError: invalid literal for int() with base 10: '0b1000'

[IN]  int(hex(8))
[OUT] ValueError: invalid literal for int() with base 10: '0x8'

没有内置的十六进制或二进制对象,只有内置函数创建的字符串表示。如果您愿意,您可以随时创建它们。因此,您不是从int转换为bin到int,而是从str转换为int。期望内置的int()函数识别数字的每个字符串表示有点多。

编辑:我有所纠正,还有第二个输入基础。所以int(hex(8), 16)会给你8,int(bin(8), 2)也会给你8。想象一下!那些Pythonistas想到了一切......现在我也学到了一点!

  

这也很奇怪:

[IN]  bin(str(8))
[OUT] TypeError: 'str' object cannot be interpreted as an integer 
# What are you telling me, Python?! You just did it with int()!

bin()不接受字符串。只有整数。如果需要,请自己写。它也只输出格式化的字符串。

  

可是:

[IN]  float(str(8))
[OUT] 8.0

呀。 Float接受整数的字符串表示。 bin()不像float()

那样有用或无处不在
  

更糟糕的是:

[IN]  int(8.5)
[OUT] 8
[IN]  int(str(8.5))
[OUT] ValueError: invalid literal for int() with base 10: '8.5'
[IN]  float(str(8.5))
[OUT] 8.5           # IT WORKS??! 
     

这会使int(some_string)成为一个糟糕的选择,而应该首选int(float(some_string))

单个函数中的双重转换(从字符串到浮点数)有点问题。它需要int()接受内置函数的太多输入。字符串必须已经是int的表示。简单明了。是的,如果您的字符串可能是浮点数,则首先将其转换为浮点数,然后转换为int。没有太多的工作。你也可以随时捕捉异常!

  

或者:

[IN]  hex(hex(8))
[OUT] TypeError: 'str' object cannot be interpreted as an integer Bad design: A method that converts an object to the type it belongs to
     

应始终接受自己的类型作为有效输入。 (我知道这种类型   是str,但无论如何。)

hex()创建一个字符串。你是在自问自答。如果你想要一个Hex对象,我相信有几个包可以实现它们。

[IN]  complex(str(complex(8)))
[OUT] (8+0j)
# What are the rules again?
[IN]  int(abs(complex(str(8.5))))
[OUT] 8
# OK... I guess?

complex()将复合体的字符串表示形式作为有效输入。这一点似乎并不奇怪。 int取复合体的绝对值也不奇怪(因为它所要做的就是忽略虚部)。在这里,我们看到实现实际对象的效果。复数在内置环境中完全实现。 Hex和Bin不是。

  

这对我来说似乎非常反Pythonic。有设计理由吗?   这些非常直观的转换不起作用,或者只是简单的转换   没有人想过的东西需要改进吗?要么   也许我做错了?

     

我找到的唯一解决方案是

[IN]  eval(hex(8))
[OUT] 8
[IN]  eval(bin(8))
[OUT] 8

您可以认为Hex和Bin应该是内置环境中完全实现的对象。但是,目前,他们不是。找到一个包,或编写自己的对象。