How could I improve the speed of my algorithm, even by the slightest amount

╄→гoц情女王★ 提交于 2021-01-28 14:00:44

问题


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

回答1:


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:

  1. No side effects: nothing in 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.
  2. Use isinstance(), not if type(x) == y (just a good habit, no particular advantage here with base types).
  3. Use list and dict comprehensions; far simpler, no fear of changing the original, and essentially pythonic.
  4. No need to handle the case where dict keys would be bytes: use your own function instead.
  5. tuple([x for x in list_]) is slightly faster than tuple(x for x in list_), I learned recently.

Some alternatives:

  1. If you prefer 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
  1. Fastest (but a bit opaque):
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)
  1. Most extensible (you can add various .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])


来源:https://stackoverflow.com/questions/65555973/how-could-i-improve-the-speed-of-my-algorithm-even-by-the-slightest-amount

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!