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(...)