我创建了这个程序来计算给定文件的 sha256 或 sha512 哈希值并将计算摘要为十六进制。
它由 5 个文件组成,其中 4 个是自定义模块,1 个是主模块。
我在不同的模块中有两个函数,但这些函数的唯一区别是一个变量。见下图:
来自sha256.py
def get_hash_sha256():
global sha256_hash
filename = input("Enter the file name: ")
sha256_hash = hashlib.sha256()
with open(filename, "rb") as f:
for byte_block in iter(lambda: f.read(4096),b""):
sha256_hash.update(byte_block)
# print("sha256 valule: \n" + Color.GREEN + sha256_hash.hexdigest())
print(Color.DARKCYAN + "sha256 value has been calculated")
color_reset()
来自sha512.py
def get_hash_sha512():
global sha512_hash
filename = input("Enter the file name: ")
sha512_hash = hashlib.sha512()
with open(filename, "rb") as f:
for byte_block in iter(lambda: f.read(4096),b""):
sha512_hash.update(byte_block)
# print("sha512 valule: \n" + Color.GREEN + sha512_hash.hexdigest())
print(Color.DARKCYAN + "sha512 value has been calculated")
color_reset()
这些函数在我的 simple_sha_find.py 文件中调用:
def which_hash():
sha256_or_sha512 = input("Which hash do you want to calculate: sha256 or sha512? \n")
if sha256_or_sha512 == "sha256":
get_hash_sha256()
verify_checksum_sha256()
elif sha256_or_sha512 == "sha512":
get_hash_sha512()
verify_checksum_sha512()
else:
print("Type either sha256 or sha512. If you type anything else the program will close...like this.")
sys.exit()
if __name__ == "__main__":
which_hash()
如您所见,将调用的函数基于用户输入。如果用户输入 sha256,则会触发 sha256.py 中的函数,但如果用户输入 sha512,则会触发 sha512.py 中的函数
该应用程序可以工作,但我知道我可以减少它的冗余,但我不知道如何做。
如何定义一次 get_hash_sha---() 和 verify_checksum_sha---() 函数,并根据用户选择 sha256 还是 sha512 执行适当的计算?
我对该程序进行了一些编码变体。
我已将其创建为一个文件,并创建不同的模块并从这些模块调用函数。
无论哪种情况,我都会重复,但我知道这往往会违背自动化的目的。
您可以将这两个函数合并为一个函数:
import hashlib
def get_hash(hash_type):
if hash_type == 'sha256':
hash_obj= hashlib.sha256()
elif hash_type == 'sha512':
hash_obj = hashlib.sha512()
else:
print("Invalid hash type.Please choose 'sha256'or'sha512'")
return
filename = input("Enter the fileename: ")
try:
with open(filename,"rb") as f:
for byte_block in iter(lambda: f.read(4096), b""):
hash_obj.update(byte_block)
print(Color.DARKCYAN + f"{hash_type} value has been calculated")
color_reset()
except FileNotFoundError:
print(f"File '{filename}' not found.")
def which_hash():
sha_type =input("Which hash do you want to calculate: sha256 or sha512? \n").lower()
if sha_type in ['sha256', 'sha512']:
get_hash(sha_type)
verify_checksum(sha_type)
else:
print("Type sha256 or sha512. If you type anything else program will close. .")
sys.exit()
if __name__ == "__main__":
which_hash()
使用 Enum 而不是纯文本也是最佳实践:
from enum import Enum
class HashType(Enum):
SHA256 = 'sha256'
SHA512 = 'sha512'
所以你可以改变
if hash_type == HashType.SHA256:
hash_obj = hashlib.sha256()
elif hash_type == HashType.SHA512:
hash_obj = hashlib.sha512()
def which_hash():
sha_type_input = input("Which hash do you want to calculate: sha256 or sha512? \n").lower()
try:
sha_type = HashType(sha_type_input)
get_hash(sha_type)
verify_checksum(sha_type)
except ValueError:
print("Type either sha256 or sha512. If you type anything else the program will close.")
sys.exit()
您可以通过传递相关哈希函数作为参数来概括生成哈希的函数。
类似这样的:
from hashlib import sha256, sha512
from typing import Callable
HASH_MAP: dict[str, Callable] = {"sha256": sha256, "sha512": sha512}
CHUNK = 4096
def make_hash(filename: str, hash_function: Callable) -> str:
hf = hash_function()
with open(filename, "rb") as data:
while buffer := data.read(CHUNK):
hf.update(buffer)
return hf.hexdigest()
def main():
filename = input("Enter filename: ")
func = input(f"Enter hash type {tuple(HASH_MAP)}: ")
if hfunc := HASH_MAP.get(func):
print(make_hash(filename, hfunc))
else:
print("Invalid hash type selection")
if __name__ == "__main__":
main()
如果您随后想要添加更多哈希算法,您只需适当编辑 HASH_MAP 字典即可。不需要更改其他代码
您可以重构函数,使哈希类型成为参数。可能还避免使用全局变量,并将任何交互式 I/O 留给调用代码。
我还更改了代码以在出现问题时引发错误。对于非常简单的程序来说,仅仅打印一条错误消息就可以了,但是可重用的代码需要正确区分成功和失败。
def get_hash(hash_type, filename):
if hash_type == 'sha256':
hash_obj = hashlib.sha256()
elif hash_type == 'sha512':
hash_obj = hashlib.sha512()
else:
raise ValueError("Invalid hash type.Please choose 'sha256'or'sha512'")
# Don't trap the error
with open(filename,"rb") as f:
for byte_block in iter(lambda: f.read(4096), b""):
hash_obj.update(byte_block)
def which_hash():
sha_type = input("Which hash do you want to calculate: sha256 or sha512? \n").lower()
if sha_type in ['sha256', 'sha512']:
filename = input("File name: ")
hash = get_hash(sha_type, filename)
print(f"{Color.DARKCYAN}{hash_type} value has been calculated")
color_reset()
verify_checksum(hash, sha_type, filename)
else:
raise ValueError("Type sha256 or sha512")
这种“案例和调用”正是面向对象编程旨在避免的,但也许在您的编程之旅中解决该主题还为时过早。
您可以将算法名称作为字符串提供给
hashlib.file_digest
。
import hashlib
options = 'sha256', 'sha512'
# Choose algorithm
opts = ' or '.join(options)
alg = input(f"Which hash do you want to calculate: {opts}? \n")
if alg not in options:
print(f"Type either {opts}. If you type anything else the program will close...like this.")
sys.exit()
# Choose file and hash it
filename = input("Enter the file name: ")
with open(filename, "rb") as f:
digest = hashlib.file_digest(f, alg)
print(f"{alg} value has been calculated")