Reputation: 393
I'm wondering what the difference between the following two snippets of code is:
float_var = 1234.5678
a = int(float_var)
b = (int)(float_var)
They both successfully convert the variable to an integer (at least in Python 3.6, I don't know if this behaviour is supported in 2.7) but there's an obvious difference in syntax. Furthermore, the following snippet fails:
c = (int)float_var
Which leads me to believe that the variable name (or literal, as it may be) must be enclosed in parentheses.
From what I can gather the difference in the two examples is that the first one creates a new instance of a class by passing a parameter into its __init__ method. Whereas in the second example, since the int object defines a method __float__, it can "cast" any float to an instance of int.
Am I correct in thinking this? Also, why does the third example fail? I don't understand why parentheses are required to surround the value being "cast".
Upvotes: 2
Views: 246
Reputation: 298156
There is no difference.
Python types are objects and can be called like functions. The int(foo)
syntax may be shared by Python and C, but the similarities end there.
In your code, int == (int) == ((int))
all are equal in the same way 1 + 1 == (1 + 1) == ((1 + 1))
. If you look at the bytecode, Python treats both identically:
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
The third example fails because Python isn't C. You get a SyntaxError
because it's not valid Python code.
Upvotes: 6
Reputation: 22953
Am I correct in thinking this?
No. The parenthesis are throwing you off. The two methods are equivalent. This:
(int)(float_var)
Is the same as this:
int(float_var)
It's not some special "casting" syntax. It's just parenthesis around a name. The Python grammar allows this:
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
The parser returns an equivalent abstract syntax tree for each method:
>>> 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=[]))])"
However, the third method is not allowed by the Python grammar. As said above, parenthesis around a name is nothing special. It's translated to a function call either way. So while the parenthesis around int
are optional, the parenthesis at the end are not.
Upvotes: 5
Reputation: 6748
There is no difference between a and b. Saying they are different is like saying 2
and (2)
are different. The third example fails because a function cannot be called without parenthesis. For example, int 5
will not work because there are no parenthesis surrounding the parameter.
Upvotes: 2