Reputation: 141
How can I improve the speed of my algorithm, even by the slightest amount. For the reason I made this I don't actually care about speed in the slightest, but I'm wondering what I could change if I did. Even more than pointing out specific things to change, what I really want to know is how you know that there's a more efficient way and how that way works. Basically, what is the track to follow if you want to learn how the low level stuff works so that you can write better code at the higher level.
def decode_all(ob):
if(type(ob)==list):
for i in range(len(ob)):
ob[i] = decode_all(ob[i])
if(type(ob)==dict):
for i in ob.copy():
ob[i] = decode_all(ob[i])
if(type(i)==bytes):
ob[i.decode()] = ob[i]
ob.pop(i)
if(type(ob)==tuple):
new_ob = []
for i in ob:
new_ob.append(decode_all(i))
ob = tuple(new_ob)
if(type(ob)==bytes):
return ob.decode()
return ob
Upvotes: 1
Views: 300
Reputation: 26221
Modified code:
def decode_all(ob):
if isinstance(ob, list):
return [decode_all(e) for e in ob]
if isinstance(ob, dict):
return {decode_all(k): decode_all(v) for k, v in ob.items()}
if isinstance(ob, tuple):
return tuple([decode_all(e) for e in ob])
if isinstance(ob, bytes):
return ob.decode()
return ob
Usually, I agree with the use of if ... elif ... elif ...
, but in this case, it's simpler to just return the result right away.
Some notes:
ob
or any of its components (at whatever depth) is modified; all new collections and elements are returned, at some (slight) performance cost for their allocation.isinstance()
, not if type(x) == y
(just a good habit, no particular advantage here with base types).tuple([x for x in list_])
is slightly faster than tuple(x for x in list_)
, I learned recently.Some alternatives:
if ... elif ...
:def decode_all(ob):
if isinstance(ob, list):
ob = [decode_all(e) for e in ob]
elif isinstance(ob, dict):
ob = {decode_all(k): decode_all(v) for k, v in ob.items()}
elif isinstance(ob, tuple):
ob = tuple(decode_all(e) for e in ob)
elif isinstance(ob, bytes):
ob = ob.decode()
return ob
def _fun_bytes(ob):
return ob.decode()
def _fun_list(ob):
return [decode_all(e) for e in ob]
def _fun_dict(ob):
return {decode_all(k): decode_all(v) for k, v in ob.items()}
def _fun_tuple(ob):
return tuple([decode_all(e) for e in ob])
def _identity(ob):
return ob
fun_dict = {
bytes: _fun_bytes,
list: _fun_list,
dict: _fun_dict,
tuple: _fun_tuple,
}
def decode_all(ob):
return fun_dict.get(type(ob), _identity)(ob)
.register
in various areas in your codebase, e.g. to handle new types):from functools import singledispatch
@singledispatch
def decode_all(ob):
return ob
@decode_all.register
def _(ob: bytes):
return ob.decode()
@decode_all.register
def _(ob: list):
return [decode_all(e) for e in ob]
@decode_all.register
def _(ob: dict):
return {decode_all(k): decode_all(v) for k, v in ob.items()}
@decode_all.register
def _(ob: tuple):
return tuple([decode_all(e) for e in ob])
Upvotes: 4