Simply Kiwi
Simply Kiwi

Reputation: 393

Python Type Conversion/Casting Syntax Differences

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

Answers (3)

Blender
Blender

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

Chris
Chris

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

whackamadoodle3000
whackamadoodle3000

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

Related Questions