Home > Software engineering >  Less redundant way of if else statements
Less redundant way of if else statements

Time:05-08

I have the code:

bytedata = decompressed_data

guid, sha1_hash = (
    x.to_bytes(length=1, byteorder="big")
    for x in get_resource_descriptor(head_revision)
)

for i in list(zip(resource_references, replace_with)):
    replace, replace_with = i[0], i[1]

    if replace.startswith("g"):
        if use_compressed_integers(compression_flags):
            replace = guid   varint.encode(int(replace[1:]))
        else:
            replace = guid   struct.pack(">I", int(replace[1:]))

    elif replace.startswith("h"):
        replace = sha1_hash   int(replace[1:]).to_bytes(length=20, byteorder="big")

    if replace_with.startswith("g"):
        replace_with = struct.pack(">I", replace_with[1:])

    elif replace_with.startswith("h"):
        replace_with = sha1_hash   int(replace_with[1:]).to_bytes(
            length=20, byteorder="big"
        )

    bytedata = bytedata.replace(replace, replace_with)

return bytedata

Is there a less redundant way of writing the same code? There's so many if else statements, and it looks ugly and redundant.

CodePudding user response:

The new Python 3.10 Structural Pattern Matching (released in PEP 636) introduces the match/case statements and handles the excess of if/elif nicely.

Your for statement will look like that:

for i in list(zip(resource_references, replace_with)):
        replace, replace_with = i[0], i[1]

        match replace[0]:
            case "g":
                if use_compressed_integers(compression_flags):
                    replace = guid   varint.encode(int(replace[1:]))
                else:
                    replace = guid   struct.pack(">I", int(replace[1:]))

            case "h":
                replace = sha1_hash   int(replace[1:]).to_bytes(length=20, byteorder="big")

        match replace_with[0]:
            case "g":
                replace_with = struct.pack(">I", replace_with[1:])

            case "h":
                replace_with = sha1_hash   int(replace_with[1:]).to_bytes(
                length=20, byteorder="big"
            )

        bytedata = bytedata.replace(replace, replace_with)

CodePudding user response:

since Python (before 3.10) lacks asswitch/case statement, i find myself often using dictionaries that map my input data to functions.

like so:

fun2 = {
 'g': lambda x: struct.pack(">I", x),
 'h': sha1_hash   int(x).to_bytes(length=20, byteorder="big"),
}
# ...
replace_with = fun2[replace[0]](replace_with[1:])

or, if you don't like lambdas and prefer local functions instead:

bytedata = decompressed_data

guid, sha1_hash = (
    x.to_bytes(length=1, byteorder="big")
    for x in get_resource_descriptor(head_revision)
)

def handle_g(x, compressed=False, prefix=b''):
  if compressed:
    return prefix   varint.encode(int(x[1:]))
  else:
    return prefix   struct.pack(">I", int(x[1:]))
def handle_h(x, compressed=False, prefix=b''):
  return sha1_hash   int(x[1:]).to_bytes(length=20, byteorder="big")
def handle_default(x, compressed=False, prefix=b''):
  return x
handles = {
 'g': handle_g,
 'h': handle_h,
}

do_compress = use_compressed_integers(compression_flags)


for i in zip(resource_references, replace_with):
    replace, replace_with = i[0], i[1]

    replace = handles.get(replace[0], handle_default)(replace, do_compress, guid)
    replace_with = handles.get(replace_with[0], handle_default)(replace_with)

    bytedata = bytedata.replace(replace, replace_with)

sidenote: there is typically no use for using for _ in list(zip(...)): the list() will just add overhead (as the iterable has to be expanded to a full list first) for no obvious gain. much better to just use for _ in zip(...)

  • Related