Python 类型转换/强制转换语法差异



我想知道以下两个代码片段有什么区别:

float_var = 1234.5678
a = int(float_var)
b = (int)(float_var)

它们都成功地将变量转换为整数(至少在 Python 3.6 中,我不知道 2.7 是否支持这种行为),但在语法上存在明显差异。此外,以下代码段失败:

c = (int)float_var

这让我相信变量名称(或文字,因为它可能是)必须括在括号中。

从我可以收集到的两个示例中的区别是,第一个通过将参数传递到其__init__方法来创建类的新实例。而在第二个示例中,由于 int 对象定义了一个方法__float__,因此它可以将任何浮点数"强制转换"到 int 的实例。

我这样想对吗?另外,为什么第三个示例失败了?我不明白为什么需要括号来包围"转换"的值。

没有区别。

Python 类型是对象,可以像函数一样调用。int(foo)语法可能由Python和C共享,但相似之处到此为止。

在您的代码中,int == (int) == ((int))都以相同的方式相等1 + 1 == (1 + 1) == ((1 + 1)).如果你看一下字节码,Python对两者的处理方式相同:

In [42]: dis.dis(lambda: (int)(a))
1           0 LOAD_GLOBAL              0 (int)
3 LOAD_GLOBAL              1 (a)
6 CALL_FUNCTION            1
9 RETURN_VALUE
In [43]: dis.dis(lambda: int(a))
1           0 LOAD_GLOBAL              0 (int)
3 LOAD_GLOBAL              1 (a)
6 CALL_FUNCTION            1
9 RETURN_VALUE

第三个例子失败了,因为Python不是C。你得到一个SyntaxError,因为它不是有效的 Python 代码。

我这样想对吗?

不。括号把你甩开了。这两种方法是等效的。这:

(int)(float_var)

与此相同:

int(float_var)

这不是一些特殊的"强制转换"语法。它只是一个名字周围的括号。Python 语法允许这样做:

atom: ('(' [yield_expr|testlist_comp] ')' |
'[' [testlist_comp] ']' |
'{' [dictorsetmaker] '}' |
NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False')
testlist_comp: (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] )
trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME

解析器为每个方法返回一个等效的抽象语法树:

>>> import ast
>>> ast.dump(ast.parse('(int)(float_var)'))
"Module(body=[Expr(value=Call(func=Name(id='int', ctx=Load()), args=[Name(id='float_var', ctx=Load())], keywords=[]))])"
>>> ast.dump(ast.parse('int(float_var)'))
"Module(body=[Expr(value=Call(func=Name(id='int', ctx=Load()), args=[Name(id='float_var', ctx=Load())], keywords=[]))])"

但是,Python 语法不允许使用第三种方法。如上所述,名称周围的括号没什么特别的。无论哪种方式,它都会转换为函数调用。因此,虽然int周围的括号是可选的,但末尾的括号不是。

a和b之间没有区别,说它们不同就像说2(2)是不同的。第三个示例失败,因为不能在没有括号的情况下调用函数。例如,int 5将不起作用,因为参数周围没有括号。

最新更新