madCode
madCode

Reputation: 3903

Is multiple type-casting in python bad?

Say I have a variable in python called my_boolean = False I want an end result to be: my_bool = "0" The only way i can think of doing this is. my_bool = str(int(my_boolean)), a double type-casting.

Is there a better way of doing this? Disadvantages? Advantages? What happens internally?

Upvotes: 1

Views: 1590

Answers (4)

Bakuriu
Bakuriu

Reputation: 101929

Never assume performances of operations. Profile and benchmark:

In [7]: value = False

In [8]: %%timeit bool_dict = {False: '0', True: '1'}
   ...: my_boolean = bool_dict[value]
   ...: 
10000000 loops, best of 3: 47.7 ns per loop

In [9]: %timeit my_boolean = str(int(value))
1000000 loops, best of 3: 420 ns per loop

In [10]: %timeit my_boolean = '0' if value is False else '1'
10000000 loops, best of 3: 50 ns per loop

In [11]: %timeit my_boolean = '01'[value]
10000000 loops, best of 3: 52.1 ns per loop

As you can see the str(int(value)) is much slower than the rest because function calls have high overhead.

Note how the branching operation is mostly equal to the dictionary look-up[try it a few times and you'll see the two versions exchange timings], but it's more readable, so use it.

I personally find the conditional expression version easier to read than the original str(int(value)), even though there isn't anything inherently wrong with using two conversions, and in other situations this may be the easier solution.

The version '01'[value] is the fastest, but I believe you should prefer readability over performances, especially if you did not prove that this conversion is the bottleneck.

Note that using an identifier instead of the explicit constant False I discovered that this:

'01'[False]

Is optimized by the interpreter to the expression "0":

In [14]: import dis
In [16]: def test():
    ...:     a = '01'[False]

In [17]: dis.dis(test)
  2           0 LOAD_CONST               3 ('0') 
              3 STORE_FAST               0 (a) 
              6 LOAD_CONST               0 (None) 
              9 RETURN_VALUE  

Hence the benchmark I did before wasn't correct.

Upvotes: 1

arshajii
arshajii

Reputation: 129507

You could try

my_bool = '01'[my_boolean]

There seems to be a time difference between your approach and what is above:

>>> from timeit import timeit
>>> timeit("'01'[b]", "b = False")
0.10460775769296968
>>> timeit("str(int(b))", "b = False")
0.8879351199904466

Is it something to lose sleep over? Definitely not. I'm sure there are people who would call your current approach more Pythonic and prefer that over this. In other words, no, there is nothing wrong with what you're doing.

Upvotes: 3

Houdini
Houdini

Reputation: 3542

Could use a dictionary mapping like this:

bool_dict = { False : '0', True : '1' }
my_boolean = bool_dict[False]

Not sure if it is more efficient, I would imagine so since it is just hash look up in a map, generally an O(1) operation.

Upvotes: 1

Asterlune
Asterlune

Reputation: 59

You could use the ternary operator:

'1' if my_boolean else '0'

Upvotes: 1

Related Questions