我已经创建了一个模拟RAID 4配置的Python3程序,使用列表作为模拟的
。
a = RAID4()创建类RAID4的一个变量。a.convert_to("string to make raided", 4):convert_to需要一个字符串输入和许多HDD来创建。然后,它将字符串转换为字节,并在HDD之间均匀地分割比特,使奇偶HDD保持为空。然后生成奇偶校验并存储HDD。返回一个RAID4类对象。一旦完成了这个任务,您可以:
a.remove_hdd(2)损坏或破坏的硬盘。a.repair()修复RAID配置。print(a)打印HDD表。str = a.convert_from()从HDD获取字符串。奖励问题(对于了解RAID的人):
如有任何其他意见,敬请见谅。
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import types
class RAID4(object):
def __init__(self, input_str=None, hdd_num=3):
if input_str:
self.convert_to(input_str, hdd_num)
class HDDNotExist(Exception):
pass
class NotEnoughHDDs(Exception):
pass
def __str__(self):
"""Returns the HDDs in a visual format."""
# top border
print_str = "====" * len(self.hdds) + "=\n"
# columns headings
for i in range(len(self.hdds) - 1):
print_str += "|{:^3}".format(i)
print_str += "|XOR|\n"
print_str += "|" + "---+" * (len(self.hdds) - 1) + "---|\n"
# for every row
for i in range(len(max(self.hdds, key=len))):
# print each column
for j in range(len(self.hdds)):
print_str += "| " + str(self.hdds[j][i]) + " "
print_str += ("|\n")
# bottom border
print_str += "====" * len(self.hdds) + "="
return print_str
def xor(self, *to_xor):
"""Performs XOR on parameters, from left to right."""
# if passed a list as it's only argument, xor everything in it
if len(to_xor) == 1 and \
isinstance(to_xor[0], (list, tuple, types.GeneratorType)):
to_xor = to_xor[0]
x = 0
for i in to_xor:
x ^= i
return x
def convert_to(self, input_str, hdd_num=3):
"""Converts a string into a set number of HDDs."""
if hdd_num < 3:
raise NotEnoughHDDs(
"RAID 5 requires a minimum of three hard drives to operate.")
# convert every character into a byte (8x bits)
input_bin = ''.join(format(ord(x), 'b').zfill(8) for x in input_str)
# add a 1, this, and every 0 after it will be removed when
# converting back into the string
input_bin += "1"
# number of bits required for each HDD to have a full byte
bits_per_hdd_byte = 8 * (hdd_num - 1)
# next lowest multiple of bits for each
# HDD to have a whole number of bytes
next_lowest_multiple = len(input_bin) // bits_per_hdd_byte + 1
# make each HDD have a whole number of bytes when input is evenly split
input_bin += "0" * (
next_lowest_multiple * bits_per_hdd_byte - len(input_bin))
# make blank hdds
self.hdds = [[] for _ in range(hdd_num)]
# split data into hdds, with one hdd left for parity
for i, x in enumerate(input_bin):
self.hdds[i % (hdd_num - 1)].append(int(x))
# xor every row
for i in range(max(len(x) for x in self.hdds)):
# append the row's xor
self.hdds[-1].append(self.xor(
self.hdds[j][i] for j in range(hdd_num - 1)
))
def convert_from(self):
"""Converts HDDs into the string."""
self.repair()
# combine HDDs into a single list
# zip(hdds). for i in zip. for j in i. str(j)
output_bin = (str(j) for i in zip(*self.hdds[:-1]) for j in i)
output_bin = ''.join(output_bin)
# remove the last 1, and following 0s (padding)
output_bin = output_bin.rsplit("1", 1)[0]
# split into bytes (8x bits), one for each character
output_bytes = [output_bin[i:i+8] for i in range(0, len(output_bin), 8)]
# decode bytes into characters, join and return
return ''.join(chr(int(x, 2)) for x in output_bytes)
def remove_hdd(self, index_to_remove):
"""Remove a HDD, simulating a destroyed HDD in a RAID system."""
try:
# sets HDD to empty list so we know theres supposed to be a HDD here
# (instead of deleting the HDD)
self.hdds[index_to_remove] = []
except IndexError:
raise HDDNotExist(
"The HDD to remove does not exists. HDDs are 0-indexed.")
def repair(self):
"""Creates a new HDD to replace the missing one."""
# if a HDD is missing, repair it
if [] in self.hdds:
# get index (so we XOR in the right order)
empty_hdd_index = self.hdds.index([])
# delete the empty HDD and create the replacement
del self.hdds[empty_hdd_index]
new_hdd = []
# for every data row in the HDD
for i in range(len(self.hdds[0])):
# get the row (one bit from each HDD)
row = [self.hdds[j][i] for j in range(len(self.hdds) - 1)]
# insert a 0 into the missing HDD's spot
row.insert(empty_hdd_index, 0)
# add a 1 or 0 to the replacement HDD depending on whether
# having a 0 created a matching XOR result
new_hdd.append(0 if self.xor(row) == self.hdds[-1][i] else 1)
# insert the replacement HDD where it belongs
self.hdds.insert(empty_hdd_index, new_hdd)
# if there are no HDDs missing, check that there are no corruptions
else:
# for every data row in the HDD
for i in range(len(self.hdds[0])):
# get the row (one bit from each HDD)
row = [self.hdds[j][i] for j in range(len(self.hdds) - 1)]
# if the row XORed is different to what it should be
if self.xor(row) != self.hdds[-1][i]:
# send a warning, saying where the error will be
print(
"WARNING: data point {} corrupted, XOR didn't match. "
"This will be character {} if it's a string."
.format(i, ((i + 1) * (len(self.hdds) - 1) // 8) + 1))
if __name__ == "__main__":
print("hey Bob!")
a = RAID4("hey Bob!", 4)
print(a)
# uncomment one of the lines below to "screw with" the HDDs
#a.remove_hdd(2) # this line deletes a HDD
#a.hdds[2][5] = 0 # this line manually changes a bit
#a.hdds[2][5] = 0 if a.hdds[2][5] else 1 # this line manually toggles a bit
print(a)
a.repair()
print(a)
print(a.convert_from())发布于 2018-01-17 04:08:01
def __init__(self, input_str=None, hdd_num=3):
if input_str:
self.convert_to(input_str, hdd_num)这是有点模糊的一面。其效果似乎是将一个值赋给self.hdds。但令人惊讶的是,这种情况并不总是发生。另外,看到self.hdds = []或None这样的文本提示也很好,convert_to()会覆盖这些提示。在读取构造函数时,我们试图学习对象属性的集合,以及代码允许它们包含的那种“好值”。
此外,在引入构造函数之前,请定义嵌套的异常类。
for i in range(len(self.hdds) - 1):
print_str += "|{:^3}".format(i)这可能是二次型的,除非在扩展字符串的某些版本的cPython解释器上。通常的python成语是.append()到循环中的一个列表,然后用''.join()返回一个字符串。你的范围是有限的,所以这没什么大不了的,只是一个值得警惕的编码习惯。
您的字符串连接表达式非常好,但是可以考虑使用.format()。
if len(to_xor) == 1 and \
isinstance(to_xor[0], (list, tuple, types.GeneratorType)):这很好。考虑以这种方式编写它,而不使用反斜杠:
if (len(to_xor) == 1
and isinstance(to_xor[0], (list, tuple, types.GeneratorType))):与一群and's在左边边沿排成一排,这比右派and's在右边的边缘更容易读懂。
self.hdds[-1].append(self.xor(
self.hdds[j][i] for j in range(hdd_num - 1)
))在这种情况下,这对悬在一起的近亲似乎并不能提高清晰度。有时候,在它自己的行上的一个paren可能非常有用,就像定义一个长列表常量一样。在这里,考虑让for j开始一个新的行来提高清晰度。
"The HDD to remove does not exists. HDDs are 0-indexed.")错误:存在
print(a.convert_from())对不起,我没有发现这是一个非常清楚的公共API。“从”表示我们将通过一个arg。考虑重命名该方法。
发布于 2018-01-17 04:25:35
在Python3.x中,您不需要指定编码类型,因为默认的是UTF-8。这样您就可以安全地删除指令:# -*- coding: utf-8 -*-
https://codereview.stackexchange.com/questions/163814
复制相似问题