我对Python相当陌生(这是我做的第一件真正利用类的事情)。这是可行的,我对此很满意,只是寻求一般性的建议。特别好的是输入我的评论和如何‘仿生’的代码是。
#import fractions #unused, on todo
class Base:
# Dicts for getting a digit from a value and a value from a digit
nums = {0: '0', 1: '1', 2: '2', 3: '3', 4: '4', 5: '5', 6: '6', 7: '7', 8: '8', 9: '9', 10: 'A', 11: 'B', 12: 'C', 13: 'D', 14: 'E', 15: 'F', 16: 'G', 17: 'H', 18: 'I', 19: 'J', 20: 'K', 21: 'L', 22: 'M', 23: 'N', 24: 'O', 25: 'P', 26: 'Q', 27: 'R', 28: 'S', 29: 'T', 30: 'U', 31: 'V', 32: 'W', 33: 'X', 34: 'Y', 35: 'Z'}
rnums = {'6': 6, 'Y': 34, '3': 3, 'M': 22, 'C': 12, '0': 0, '7': 7, 'X': 33, '1': 1, 'D': 13, 'W': 32, '9': 9, 'V': 31, 'U': 30, 'A': 10, 'L': 21, 'F': 15, 'O': 24, '4': 4, 'J': 19, 'Z': 35, 'I': 18, '5': 5, 'T': 29, 'P': 25, '2': 2, 'E': 14, 'R': 27, 'H': 17, 'S': 28, 'N': 23, '8': 8, 'B': 11, 'Q': 26, 'K': 20, 'G': 16}
# The special bases (binary, octal, hex) have different identifiers from the pattern followed by most
sbases = {2: 'b', 8: 'o', 16: 'x'}
rsbases = {'b': 2, 'o': 8, 'x': 16}
def __init__(self, cols, base = 8, bigval = None): #cols is just a holdover; not sure what the best name for this general value would be
self.vals = {} # {column: value} dictionary
self.base = base
#can be created from an int & base, a str, a dict, or another Base object
if isinstance(cols, int) and bigval is None:
self.int_init(cols)
elif isinstance(cols, str):
if cols[0] == '0' and cols[2] == 'b': #valid string
self.baseNum_init(cols)
else:
raise ValueError('str init can only be used with a string of the form `0<base_char>b<basenum>`')
#self.vals = convert(int(cols)).vals
# ^Thought about this before but it shouldn't be allowed
elif isinstance(cols, dict):
self.dict_init(cols)
elif isinstance(cols, Base):
self.int_init(cols.base_ten())
else: #for using Base in a function like convert()
self.cols = cols
self.vals = {cols: bigval}
def int_init(self, num):
# The powers of the base, in a 1000-tuple of 2-tuples. i+1 b/c base**0 is the 1st column in a number.
self.powers = tuple( (i + 1, self.base**i) for i in range(1000 + 1) )
if self.base > len(nums) - 1 or self.base < 2: #unacceptable bases: <2 or more than are in the dict
raise ValueError('base used in int_init either too low or too high')
elif num > sum( set( power[1] for power in self.powers) ): #if num > sum of every power up to base**1000, can't represent it
raise ValueError('num is too large; must be <= sum_i=0^1000(base^i)') #sigma notation
elif num < 0: #no negatives
raise ValueError('num is too small; must be >= 0')
#special case for zero
if num == 0:
self.cols = 1
self.vals = {1: 0}
elif num % 1 != 0:
pass
#frac = fractions.Fraction(num)
#to-do: fractions
else:
for k in range(len(self.powers) - 1, 0 - 1, -1): #counting down through self.powers
power = self.powers[k]
if not self.vals: #not {} is True
if num >= power[1]: #go down till a power is smaller than the number
self.cols = power[0] #how many columns there are total
self.assign(power[0], num // power[1]) #how many of that power are in num
num %= power[1]
else:
self.assign(power[0], num // power[1])
num %= power[1]
def baseNum_init(self, _str):
#base included in the string in index 1 takes precedence over base argument of __init__
#if-statement b/c of special bases
self.base = self.rsbases[_str[1]] if _str[1] in self.rsbases else Base.val_from_char(_str[1])
baseNum = _str[3:] #the important bit
self.cols = len(baseNum)
_col = self.cols
#baseNum[::-1].index(digit) instead of a decrementing _col almost works, but repeating digits foil it
for digit in baseNum:
if Base.val_from_char(digit) >= self.base: #'8' is never allowed in a base-8 number
raise ValueError('Value in column ' + str(_col) + ' greater than allowed.')
else:
self.assign(_col, Base.val_from_char(digit))
_col -= 1
def dict_init(self, _dict):
if 'base' in _dict: #base can be supplied as argument to __init__ or as a dict key, if both dict takes precedence
self.base = _dict['base']
del _dict['base']
self.cols = len(_dict)
for col, val in _dict.items():
if val >= self.base:
raise ValueError('Value in column ' + str(col) + 'greater than allowed.')
else:
self.assign(col, val)
#ASSIGN
def assign(self, col, val):
self.vals[col] = val
#VAL DICTS
def val_from_char(char): #No self argument b/c they logically belong to the class, but they don't require an instance to work
return Base.rnums[char]
def char_from_val(val):
return Base.nums[val]
#TO AND FROM BASE-10
def base_ten(self):
result = 0
for col, val in self.vals.items():
result += self.base**(col-1) * val
return result
#basically undos str_init()
def __str__(self):
baseNum = ''
for m in range(len(self.vals), 0, -1):
baseNum += Base.char_from_val(self.vals[m])
baseId = Base.sbases[self.base] if self.base in Base.sbases else Base.char_from_val(self.base)
return '0' + baseId + 'b' + baseNum
def __format__(self):
pass
#on the to-do list
def __repr__(self):
return "Base('" + self.__str__() + "')"
# b/c of str_init, eval(repr(Base)) == Base
#-------------
#These are used in convert()
nums = {0: '0', 1: '1', 2: '2', 3: '3', 4: '4', 5: '5', 6: '6', 7: '7', 8: '8', 9: '9', 10: 'A', 11: 'B', 12: 'C', 13: 'D', 14: 'E', 15: 'F', 16: 'G', 17: 'H', 18: 'I', 19: 'J', 20: 'K', 21: 'L', 22: 'M', 23: 'N', 24: 'O', 25: 'P', 26: 'Q', 27: 'R', 28: 'S', 29: 'T', 30: 'U', 31: 'V', 32: 'W', 33: 'X', 34: 'Y', 35: 'Z'}
rnums = {'6': 6, 'Y': 34, '3': 3, 'M': 22, 'C': 12, '0': 0, '7': 7, 'X': 33, '1': 1, 'D': 13, 'W': 32, '9': 9, 'V': 31, 'U': 30, 'A': 10, 'L': 21, 'F': 15, 'O': 24, '4': 4, 'J': 19, 'Z': 35, 'I': 18, '5': 5, 'T': 29, 'P': 25, '2': 2, 'E': 14, 'R': 27, 'H': 17, 'S': 28, 'N': 23, '8': 8, 'B': 11, 'Q': 26, 'K': 20, 'G': 16}
#Has all the same logic as Base.int_init()
def convert(num, base=8):
if base > len(nums) or base < 2:
raise Exception
powers = tuple( (i + 1, base**i) for i in range(1000 + 1) )
if num == 0:
return Base(1, bigval = 0)
if num % 1 != 0:
pass
#frac = fractions.Fraction(num)
else:
result = None
for k in range(1, len(powers) + 1):
power = powers[-k]
if not result:
if num >= power[1]:
biggest = power
result = Base(biggest[0], base, nums[ num // biggest[1] ])
num %= biggest[1]
elif isinstance(result, Base):
result.assign(power[0], num // power[1])
num %= power[1]
return result
#This used to be a placeholder Base to use where needed but it's not needed anymore
#place = Base(1, base = 2)
#TESTING
#if __name__ == '__main__':
baseToTheWhat = 5
bases = ((2, 8, 16), range(2, 35 + 1), sorted( (2, 8, 6, 4, 35, 30, 16, 20, 15, 9, 29) ) ) #bases I want to try
baseIndex = 0 #which of those to use?
for i in bases[baseIndex]:
for l in sorted(set([0, 1, 2, 5, 8, 9, 10, 11, 20, 40, 32, 63, 64, 65, 8**3 - 1, 8**3, 8**3 + 1, 100, 1000, 8**5 ]
+ [1,2,3,4,5,6,7,8,9,10]
+ [8**q for q in range(baseToTheWhat + 1)] + [8**q - 1 for q in range(baseToTheWhat + 1)] + [8**q + 1 for q in range(baseToTheWhat)]
+ [r**t + v for v in (-1, 0, 1) for t in range(baseToTheWhat) for r in bases[baseIndex]]
+ list(range(100)) )):
print("{:10d} {:2d} {:20}".format(l, i, str(Base(l, base=i))))发布于 2017-03-22 04:40:11
一般来说,您的代码看起来不错。我有几条裤子。
您应该考虑按照pep8对代码进行格式化。在共享代码时,这一点很重要,因为一致的样式使其他程序员更容易阅读您的代码。有各种工具可以帮助使代码pep8兼容。我使用的是PyCharm IDE,它将在编辑器中显示pep8违规情况。
如果您改变了这一点:
nums = {0: '0', 1: '1', 2: '2', 3: '3', 4: '4', 5: '5', 6: '6', 7: '7',
8: '8', 9: '9', 10: 'A', 11: 'B', 12: 'C', 13: 'D', 14: 'E',
15: 'F', 16: 'G', 17: 'H', 18: 'I', 19: 'J', 20: 'K', 21: 'L',
22: 'M', 23: 'N', 24: 'O', 25: 'P', 26: 'Q', 27: 'R', 28: 'S',
29: 'T', 30: 'U', 31: 'V', 32: 'W', 33: 'X', 34: 'Y', 35: 'Z'}
rnums = {'6': 6, 'Y': 34, '3': 3, 'M': 22, 'C': 12, '0': 0, '7': 7, 'X': 33,
'1': 1, 'D': 13, 'W': 32, '9': 9, 'V': 31, 'U': 30, 'A': 10,
'L': 21, 'F': 15, 'O': 24, '4': 4, 'J': 19, 'Z': 35, 'I': 18,
'5': 5, 'T': 29, 'P': 25, '2': 2, 'E': 14, 'R': 27, 'H': 17,
'S': 28, 'N': 23, '8': 8, 'B': 11, 'Q': 26, 'K': 20, 'G': 16}至:
nums = {i: chr(ord('0') + i) for i in range(10)}
nums.update({i+10: chr(ord('A') + i) for i in range(26)})
rnums = {v: k for k, v in nums.items()}我相信结果更容易检查正确性。坦率地说,我发现从一开始就容易得多。
你可以改变:
if self.base > len(nums) - 1 or self.base < 2:至:
if not 2 <= self.base < len(nums):我觉得更容易读懂。
您的convert()代码重新定义了nums和rnums。可以以Base.nums和Base.rnums的形式直接从类中访问这些数据,这将允许更好的干的。
https://codereview.stackexchange.com/questions/158444
复制相似问题