I looked at the other answers but they didn't seem to work for me, or I could just be doing something wrong, or not understanding what I am supposed to do in the context of this code. On line 78, it talks about how there is a Nonetype value, even though I assigned a value to both variables no matter what.
Here is a link to a similar problem (I think):
[https://stackoverflow.com/questions/53680913/typeerror-cannot-unpack-non-iterable-nonetype-object][1]
Here is where I think the faulty code lies:
def check_win(turn, gamestate):
if turn == 1:
if gamestate[0] == gamestate[1] == gamestate[2] != '-' or gamestate[3] == gamestate[4] == gamestate[5] != '-' or gamestate[6] == gamestate[7] == gamestate[8] != '-':
winner = 1
win = True
return winner, win
elif gamestate[0] == gamestate[3] == gamestate[6] != '-' or gamestate[1] == gamestate[4] == gamestate[7] != '-' or gamestate[2] == gamestate[5] == gamestate[8] != '-':
winner = 1
win = True
return winner, win
elif gamestate[0] == gamestate[4] == gamestate[8] != '-' or gamestate[2] == gamestate[4] == gamestate[6] != '-':
winner = 1
win = True
return winner, win
elif turn == 2:
if gamestate[0] == gamestate[1] == gamestate[2] or gamestate[3] == gamestate[4] == gamestate[5] or gamestate[6] == gamestate[7] == gamestate[8]:
winner = 2
win = True
return winner, win
elif gamestate[0] == gamestate[3] == gamestate[6] or gamestate[1] == gamestate[4] == gamestate[7] or gamestate[2] == gamestate[5] == gamestate[8]:
winner = 2
win = True
return winner, win
elif gamestate[0] == gamestate[4] == gamestate[8] or gamestate[2] == gamestate[4] == gamestate[6]:
winner = 2
win = True
return winner, win
else:
winner = 'None'
win = False
return winner, win
Later on when I try to alter those values in another function:
winner, win = check_win(turn, gamestate) <--- Where error was found
Here is the code in its entirety :
print('Tic Tac Toe:')
pos = 0
turn = 1
gamestate = ['-', '-', '-', '-', '-', '-', '-', '-', '-']
def display_board(gamestate):
print(gamestate[0:3])
print(gamestate[3:6])
print(gamestate[6:9])
def move_validity(pos, gamestate):
if str(gamestate[int(pos)]) != '-':
print('Invalid move.')
valid = False
return valid
else:
valid = True
return valid
def update(gamestate, pos):
if turn == 1:
gamestate[int(pos)] = 'X'
if turn == 2:
gamestate[int(pos)] = 'O'
else:
print('ERROR')
def check_win(turn, gamestate):
if turn == 1:
if gamestate[0] == gamestate[1] == gamestate[2] != '-' or gamestate[3] == gamestate[4] == gamestate[5] != '-' or gamestate[6] == gamestate[7] == gamestate[8] != '-':
winner = 1
win = True
return winner, win
elif gamestate[0] == gamestate[3] == gamestate[6] != '-' or gamestate[1] == gamestate[4] == gamestate[7] != '-' or gamestate[2] == gamestate[5] == gamestate[8] != '-':
winner = 1
win = True
return winner, win
elif gamestate[0] == gamestate[4] == gamestate[8] != '-' or gamestate[2] == gamestate[4] == gamestate[6] != '-':
winner = 1
win = True
return winner, win
elif turn == 2:
if gamestate[0] == gamestate[1] == gamestate[2] or gamestate[3] == gamestate[4] == gamestate[5] or gamestate[6] == gamestate[7] == gamestate[8]:
winner = 2
win = True
return winner, win
elif gamestate[0] == gamestate[3] == gamestate[6] or gamestate[1] == gamestate[4] == gamestate[7] or gamestate[2] == gamestate[5] == gamestate[8]:
winner = 2
win = True
return winner, win
elif gamestate[0] == gamestate[4] == gamestate[8] or gamestate[2] == gamestate[4] == gamestate[6]:
winner = 2
win = True
return winner, win
else:
winner = 'None'
win = False
return winner, win
def restart():
gamestate = ['-', '-', '-', '-', '-', '-', '-', '-', '-']
turn = 1
win = False
return gamestate, turn, win
def choose_position():
pos = input('Player ' + str(turn) + ': ')
if int(pos) < 0 or int(pos) > 8:
print('Invalid move')
else:
return pos
def Tic_Tac_Toe():
while True:
global pos
global turn
if turn == 1:
pos = choose_position()
valid = move_validity(pos, gamestate)
if valid == True:
update(gamestate, pos)
if valid == False:
break
winner, win = check_win(turn, gamestate)
if win == True:
print(str(winner) + ' wins!')
break
if '-' not in gamestate:
print('Tie game.')
break
if turn == 2:
pos = choose_position()
if move_validity(pos, gamestate) == True:
continue
if move_validity(pos, gamestate) == False:
break
update(gamestate, pos)
winner, win = check_win(turn, gamestate)
if win == True:
print(str(winner) + ' wins!')
break
turn = 1
if '-' not in gamestate:
print('Tie game.')
break
display_board(gamestate)
display_board(gamestate)
Tic_Tac_Toe()
restart_case = input('y/n Would you like to play? ')
if restart_case == 'y':
gameboard, turn, win = restart()
Thank you so much, and sorry if the solution was a small typo, I am really new to this and have spent way too much time on this. :D
There are certain cases where you don't return anything in the function check_win.
For example, when turn == 1, you have an if, elif, elif block within that, but nothing for else. So, when turn == 1, if none of the if statements within the block for that are true, your function will return nothing. There is a similar problem for turn == 2. You may want to add the code you have in the else block for that function as an else block for both turn == 1 and turn == 2, as this will fix your problem.
I currently have defined my object (is_matched) that contains a while loop and also the checking of a string. I am trying to pull out the while loop into it's own object but am having trouble completing the coding. I also need the while loop to continue running until a user enters 'q' into the input.
def is_matched():
while True:
expr = input("Enter string (q to quit): ")
if expr == "q":
break
stack = Stack()
for i in expr:
if i == '{' or i == '(' or i == '[':
stack.push(i)
elif i == '}':
if len(expr) != 0:
c = stack.top()
if c == '{':
stack.pop()
else:
return "Unbalanced"
elif i == ')':
if len(expr) != 0:
c = stack.top()
if c == '(':
stack.pop()
else:
return "Unbalanced"
elif i == ']':
if len(expr) != 0:
c = stack.top()
if c == '[':
stack.pop()
else:
return "Unbalanced"
else:
return "Unbalanced"
if len(stack) != 0:
return "Unblanced"
return "Balanced"
result = is_matched()
print(result)
I am trying to pull out the while loop from above and enter into its own object as follows:
def main():
while True:
expr = input("Enter string (q to quit): ")
if expr == "q":
break
else:
return is_matched()
your is_matched function will take one argument which will be the expression to evaluate.
def is_matched(expr):
stack = Stack()
for i in expr:
if i == '{' or i == '(' or i == '[':
stack.push(i)
elif i == '}':
if len(expr) != 0:
c = stack.top()
if c == '{':
stack.pop()
else:
return "Unbalanced"
elif i == ')':
if len(expr) != 0:
c = stack.top()
if c == '(':
stack.pop()
else:
return "Unbalanced"
elif i == ']':
if len(expr) != 0:
c = stack.top()
if c == '[':
stack.pop()
else:
return "Unbalanced"
else:
return "Unbalanced"
if len(stack) != 0:
return "Unblanced"
return "Balanced"
main function.
def main():
while True:
expr = input("Enter string (q to quit): ")
if expr == "q":
break
else:
print(is_matched(expr))
import math
def findNextOpr(txt):
if len(txt)<=0 or not isinstance(txt,str):
return "type error: findNextOpr"
# --- YOU CODE STARTS HERE
if type(txt) == str:
opr_list = ["+", "-", "*", "/", '^']
for i in range(len(txt)):
if txt[i] in opr_list:
return(i)
return(-1)
# --- CODE ENDS HERE
def isNumber(txt):
if not isinstance(txt, str):
return "type error: isNumber"
if len(txt)==0:
return False
# --- YOU CODE STARTS HERE
if type(txt) == str:
try:
float(txt)
return True
except ValueError:
return False
def getNextNumber(expr, pos):
if len(expr)==0 or not isinstance(expr, str) or pos<0 or pos>=len(expr) or not isinstance(pos, int):
return None, None, "type error: getNextNumber"
# --- YOU CODE STARTS HERE
txt = expr[pos:]
oprPos = findNextOpr(txt)
if oprPos != -1:
if isNumber(txt[:oprPos]) == True:
return float(txt[:oprPos]), txt[oprPos], oprPos+pos
else:
return None, txt[oprPos], oprPos+pos
else:
if isNumber(txt):
return float(txt), None, None
else:
return None,None,None
# --- CODE ENDS HERE
def exeOpr(num1, opr, num2):
#This function is just an utility function for calculator(expr). It is skipping type check
if opr=="+":
return num1+num2
elif opr=="-":
return num1-num2
elif opr=="*":
return num1*num2
elif opr=="/":
return num1/num2
elif opr=="^":
return num1**num2
else:
return "error in exeOpr"
def calculator(expr):
if len(expr)<=0 or not isinstance(expr,str):
return "error"
expr = expr.strip()
if expr[0]!="-":
newNumber, newOpr, oprPos = getNextNumber(expr, 0)
else:
newNumber, newOpr, oprPos = getNextNumber(expr, 1)
newNumber *= -1
if newNumber is None:
return "error"
elif newOpr is None:
return newNumber
elif newOpr=="+" or newOpr=="-":
mode="add"
addResult=newNumber
mulResult=None
expResult=None
elif newOpr=="*" or newOpr=="/":
mode="mul"
addResult=0
mulResult=newNumber
expResult=None
elif newOpr=="^":
mode="exp"
expResult=newNumber
addResult=0
mulResult=None
pos=oprPos+1
opr=newOpr
oldopr=None
while True:
newNumber, newOpr, oprPos = getNextNumber(expr, pos)
if newNumber is None:
return "input error: line B in calculator"
elif newOpr is None:
if mode=='add':
if opr=='*':
return exeOpr(addResult, oldopr, mulResult*newNumber)
elif opr=='/':
return exeOpr(addResult, oldopr, mulResult/newNumber)
else:
return exeOpr(addResult, opr, newNumber)
elif mode=='mul':
if expResult==None:
expResult=0
if mulResult==None:
mulResult=0
return addResult + exeOpr(mulResult, opr, newNumber)
elif mode=="exp":
if expResult<0:
expResult=exeOpr(expResult,opr,newNumber)
if expResult>0:
expResult=-1*expResult
else:
expResult=exeOpr(expResult,opr,newNumber)
if mulResult!=0 and (oldopr=='*' or oldopr=='/'):
mulResult=exeOpr(mulResult,oldopr,expResult)
expResult=0
elif newOpr=='+' or newOpr=='-':
if expResult==None:
expResult=0
if mulResult==None:
mulResult=0
if mode=='add':
addResult = exeOpr(addResult, opr, newNumber)
mulResult = 0
expResult= 0
elif mode=='mul':
addResult += exeOpr(mulResult, opr, newNumber)
mulResult = 0
expResult= 0
elif mode=='exp':
if expResult<0:
expResult=exeOpr(expResult,opr,newNumber)
if expResult>0:
expResult=-1*expResult
addResult+=expResult
else:
addResult+=exeOpr(expResult,opr,newNumber)
if oldopr=='*' or oldopr=='/':
expResult=exeOpr(expResult,opr,newNumber)
mulResult=exeOpr(mulResult,oldopr,expResult)
addResult+=mulResult
mulResult = 0
expResult = 0
mode='add'
elif newOpr=="*" or newOpr=="/":
if mode=='add':
if opr=='-':
oldopr='-'
mulResult = newNumber
elif opr=='+':
#print('here1')
oldopr='+'
mulResult = newNumber
mode='mul'
else:
mulResult = newNumber
elif mode=='mul':
mulResult = exeOpr(mulResult, opr, newNumber)
elif mode=='exp':
if expResult<0:
expResult=exeOpr(expResult,opr,newNumber)
if expResult>0:
expResult=-1*expResult
else:
expResult=exeOpr(expResult,opr,newNumber)
if mulResult !=0 and (oldopr=='*' or oldopr=='/'):
mulResult=exeOpr(mulResult,oldopr,expResult)
expResult=0
else:
mulResult=expResult
expResult=0
mode='mul'
elif newOpr=='^':
if mode=='add':
if expResult==None:
expResult=0
if mulResult==None:
mulResult=0
if opr=='-':
expResult = -newNumber
else:
expResult = newNumber
oldopr=opr
elif mode=='mul':
expResult=newNumber
oldopr=opr
mode='exp'
if oprPos==None:
break
pos=oprPos + 1
opr=newOpr
if mulResult== None:
mulResult=0
if expResult==None:
expResult=0
return addResult+mulResult+expResult
Above is my code for a functional calculator no errors at all but when I run the code and try
calculator('-5 + 60 / 3^3 * 4 - 2 * 4^2')
I get 35.888888888888886 but the answer should be -28.11111111111111
Is there a mistake someone in my code that I cannot find?
I think it might be in the calculator section since everything else works perfectly fine with tests but I just can't find where.
I was told that one way to solve in class was that maybe using a node/stack class might help but is there any other solution than creating another class
In the calculator big loop, when opr is -, you forgot to change the sign of mulResult.
In order to debug it, I added a print statement to the exeOpr function, so that we could see what the calculator is doing at each step. Then it was easy to determine by looking at the partial results.
The full new code is like this:
import math
def findNextOpr(txt):
if len(txt) <= 0 or not isinstance(txt, str):
return "type error: findNextOpr"
# --- YOU CODE STARTS HERE
if type(txt) == str:
opr_list = ["+", "-", "*", "/", '^']
for i in range(len(txt)):
if txt[i] in opr_list:
return (i)
return (-1)
# --- CODE ENDS HERE
def isNumber(txt):
if not isinstance(txt, str):
return "type error: isNumber"
if len(txt) == 0:
return False
# --- YOU CODE STARTS HERE
if type(txt) == str:
try:
float(txt)
return True
except ValueError:
return False
def getNextNumber(expr, pos):
if len(expr) == 0 or not isinstance(expr, str) or pos < 0 or pos >= len(expr) or not isinstance(pos, int):
return None, None, "type error: getNextNumber"
# --- YOU CODE STARTS HERE
txt = expr[pos:]
oprPos = findNextOpr(txt)
if oprPos != -1:
if isNumber(txt[:oprPos]):
return float(txt[:oprPos]), txt[oprPos], oprPos + pos
else:
return None, txt[oprPos], oprPos + pos
else:
if isNumber(txt):
return float(txt), None, None
else:
return None, None, None
# --- CODE ENDS HERE
def exeOpr(num1, opr, num2):
# This function is just an utility function for calculator(expr). It is skipping type check
print("%s %s %s" % (num1, opr, num2)) # <==== DEBUGGING PRINT
if opr == "+":
return num1 + num2
elif opr == "-":
return num1 - num2
elif opr == "*":
return num1 * num2
elif opr == "/":
return num1 / num2
elif opr == "^":
return num1 ** num2
else:
return "error in exeOpr"
def calculator(expr):
if len(expr) <= 0 or not isinstance(expr, str):
return "error"
expr = expr.strip()
if expr[0] != "-":
newNumber, newOpr, oprPos = getNextNumber(expr, 0)
else:
newNumber, newOpr, oprPos = getNextNumber(expr, 1)
newNumber *= -1
if newNumber is None:
return "error"
elif newOpr is None:
return newNumber
elif newOpr == "+" or newOpr == "-":
mode = "add"
addResult = newNumber
mulResult = None
expResult = None
elif newOpr == "*" or newOpr == "/":
mode = "mul"
addResult = 0
mulResult = newNumber
expResult = None
elif newOpr == "^":
mode = "exp"
expResult = newNumber
addResult = 0
mulResult = None
pos = oprPos + 1
opr = newOpr
oldopr = None
while True:
newNumber, newOpr, oprPos = getNextNumber(expr, pos)
if newNumber is None:
return "input error: line B in calculator"
elif newOpr is None:
if mode == 'add':
if opr == '*':
return exeOpr(addResult, oldopr, mulResult * newNumber)
elif opr == '/':
return exeOpr(addResult, oldopr, mulResult / newNumber)
else:
return exeOpr(addResult, opr, newNumber)
elif mode == 'mul':
if expResult == None:
expResult = 0
if mulResult == None:
mulResult = 0
return addResult + exeOpr(mulResult, opr, newNumber)
elif mode == "exp":
if expResult < 0:
expResult = exeOpr(expResult, opr, newNumber)
if expResult > 0:
expResult = -1 * expResult
else:
expResult = exeOpr(expResult, opr, newNumber)
if mulResult != 0 and (oldopr == '*' or oldopr == '/'):
mulResult = exeOpr(mulResult, oldopr, expResult)
expResult = 0
elif newOpr == '+' or newOpr == '-':
if expResult == None:
expResult = 0
if mulResult == None:
mulResult = 0
if mode == 'add':
addResult = exeOpr(addResult, opr, newNumber)
mulResult = 0
expResult = 0
elif mode == 'mul':
addResult += exeOpr(mulResult, opr, newNumber)
mulResult = 0
expResult = 0
elif mode == 'exp':
if expResult < 0:
expResult = exeOpr(expResult, opr, newNumber)
if expResult > 0:
expResult = -1 * expResult
addResult += expResult
else:
addResult += exeOpr(expResult, opr, newNumber)
if oldopr == '*' or oldopr == '/':
expResult = exeOpr(expResult, opr, newNumber)
mulResult = exeOpr(mulResult, oldopr, expResult)
addResult += mulResult
mulResult = 0
expResult = 0
mode = 'add'
elif newOpr == "*" or newOpr == "/":
if mode == 'add':
if opr == '-':
oldopr = '-'
mulResult = -newNumber # <====== THIS IS THE PLACE I CHANGED
elif opr == '+':
# print('here1')
oldopr = '+'
mulResult = newNumber
mode = 'mul'
else:
mulResult = newNumber
elif mode == 'mul':
mulResult = exeOpr(mulResult, opr, newNumber)
elif mode == 'exp':
if expResult < 0:
expResult = exeOpr(expResult, opr, newNumber)
if expResult > 0:
expResult = -1 * expResult
else:
expResult = exeOpr(expResult, opr, newNumber)
if mulResult != 0 and (oldopr == '*' or oldopr == '/'):
mulResult = exeOpr(mulResult, oldopr, expResult)
expResult = 0
else:
mulResult = expResult
expResult = 0
mode = 'mul'
elif newOpr == '^':
if mode == 'add':
if expResult == None:
expResult = 0
if mulResult == None:
mulResult = 0
if opr == '-':
expResult = -newNumber
else:
expResult = newNumber
oldopr = opr
elif mode == 'mul':
expResult = newNumber
oldopr = opr
mode = 'exp'
if oprPos == None:
break
pos = oprPos + 1
opr = newOpr
if mulResult == None:
mulResult = 0
if expResult == None:
expResult = 0
return addResult + mulResult + expResult
x = calculator('-5 + 60 / 3^3 * 4 - 2 * 4^2')
print(x)
I am having the error come up as the >not supported between instances of 'str' and 'int'. This is at the part where it says 'if guess[1] in secretNum > 1'. I realise that this is comparing a string to an integer but i don't know how to change that. Any Help?
clue0 = []
clue1 = []
clue2 = []
clue3 = []
if guess[0] in secretNum:
clue0 = ['Pico']
if guess[0] == secretNum[0]:
clue0 = ['Fermi']
if guess[1] in secretNum or guess[1] == guess[0]:
if guess[1] == guess[0]:
if guess[1] in secretNum > 1:
clue1 == ['Pico']
else:
clue1 == []
else:
clue1 = ['Pico']
if guess[1] == secretNum[1]:
clue1 == ['Fermi']
if guess[2] in secretNum or guess[2] == guess[0] or guess[2] == guess[1]:
if guess[2] == guess[1] or guess[2] == guess[0]:
if guess[2] in secretNum > 2:
clue2 == ['Pico']
else:
clue2 == []
else:
clue2 = ['Pico']
if guess[2] == secretNum[2]:
clue2 == ['Fermi']
if guess[3] in secretNum or guess[3] == guess[0] or guess[3] == guess[1] or guess[3] == guess[2]:
if guess[3] == guess[1] or guess[3] == guess[0] or guess[3] == guess[2]:
if guess[3] in secretNum > 3:
clue3 == ['Pico']
else:
clue3 == []
else:
clue3 = ['Pico']
if guess[3] == secretNum[3]:
clue3 == ['Fermi']
clue = clue0 + clue1 + clue2 + clue3
if len(clue) == 0:
return 'Bagels'
clue.sort()
return ' '.join(clue)
guess[1] in secretNum > 1 equals to guess[1] in secretNum and secretNum > 1, secretNum seems to be string so the comparison after and is invalid (str > int)
if you want to count how many times guess[1] is in secretNumber you should use secretNumber.count(guess[1])
So this function takes inputs from the user and converts their input into a value. For example, if they put in 1k, the output would be 1000. I want to be able to go backwards. So say if I had a value of 325000, I want to change that to 325k. Any ideas on how I could achieve this?
class Parsing:
def __init__(self, instring):
self.instring = instring
def valueParsing(self):
self.instring = self.instring.strip()
self.parsedString = ''
self.scalerDict = {'K': 1000, 'MEG': 1000000, 'G': 1000000000, 'M': 0.001, 'U': 0.000001, 'N': 0.000000001, 'P': 0.000000000001}
self.scaler = 1.0
self.stringCounter = 0
self.errorflag = False
self.Parsedvalue = 0.0
self.inStringLength = len(self.instring)
for self.stringCounter in range (self.inStringLength):
if ((self.instring[self.stringCounter].upper()) == 'K'):
self.scaler = self.scalerDict['K']
elif ((self.instring[self.stringCounter].upper()) == 'G'):
self.scaler = self.scalerDict['G']
elif ((self.instring[self.stringCounter].upper()) == 'U'):
self.scaler = self.scalerDict['U']
elif ((self.instring[self.stringCounter].upper()) == 'N'):
self.scaler = self.scalerDict['N']
elif ((self.instring[self.stringCounter].upper()) == 'P'):
self.scaler = self.scalerDict['P']
elif ((self.instring[self.stringCounter].upper()) == 'M'):
if (((self.instring.upper()).count('MEG'))):
self.scaler = self.scalerDict['MEG']
else:
self.scaler = self.scalerDict['M']
elif (( self.instring[ self.stringCounter ].upper() ) == 'F' ):
break
elif (( self.instring[ self.stringCounter ].upper() ) == 'W' ):
break
elif (( self.instring[ self.stringCounter ].upper() ) == 'S' ):
break
elif (( self.instring[ self.stringCounter ].upper() ) == '%' ):
break
elif (( self.instring[ self.stringCounter ].upper() ) == 'V' ):
break
elif (( self.instring[ self.stringCounter ].upper() ) == 'A' ):
break
elif (( self.instring[ self.stringCounter ].upper() ) == 'H' ):
break
elif (( self.instring[ self.stringCounter ].upper() ) == 'Z' ):
break
elif (( self.instring[ self.stringCounter ]) == '.' ):
self.parsedString = self.parsedString + self.instring[ self.stringCounter ]
elif (self.instring[self.stringCounter].isdigit()):
if(int(self.instring[self.stringCounter]) >= 0):
if(int(self.instring[self.stringCounter]) <= 9):
self.parsedString = self.parsedString + self.instring[self.stringCounter]
else:
self.errorflag = True
break
else:
self.errorflag = True
print('Invalid input, Try again.')
if (self.errorflag):
self.parsedvalue = -1
else:
self.parsedvalue = long(self.parsedString)*self.scaler
return self.parsedvalue
print '1. Resistors in series\n',\
'2. Resistors in Parallel\n',\
'3. Voltage Divider\n'
iput = int(input("Enter your choice: "))
if iput == 1:
r1 = raw_input("Enter first resistor:")
r2 = raw_input("Enter second resistor:")
R1 = Parsing(r1)
R2 = Parsing(r2)
req = R1.valueParsing() + R2.valueParsing()
print "The value of the series resistors is %s." % req
Try this:
import math
def fmtnum(num):
k = (1e3, 'k')
M = (1e6, 'M')
G = (1e9, 'G')
table = {3: k, 4: k, 5: k, 6: M, 7: M, 8: M, 9: G, 10: G, 11: G}
num = float(num)
exp = math.log10(num)
if num < 0:
exp = int(exp)-1
else:
exp = int(exp)
try:
denum, suffix = table[exp]
return '{:g} {}'.format(num/denum, suffix)
except KeyError:
return '{:g}'.format(num)
Extending this solution for negative powers of 10 has been left as an exercise for the reader. :-)
Examples:
In [50]: fmtnum(3250)
Out[50]: '3.25 k'
In [51]: fmtnum(32500)
Out[51]: '32.5 k'
In [52]: fmtnum(325000)
Out[52]: '325 k'
In [53]: fmtnum(3250000)
Out[53]: '3.25 M'
In [54]: fmtnum(32500000)
Out[54]: '32.5 M'
In [55]: fmtnum(325000000)
Out[55]: '325 M'
In [56]: fmtnum(3250000000)
Out[56]: '3.25 G'
how about:
n = 1000
for exp, name in zip(range(9, -13, -3), ('GMk1munp')):
if exp == 0:
continue
if isinstance(n, int):
if n % 10**exp == 0:
n = '{0:d}{1}'.format(n / 10**exp, name)
break
elif isinstance(n, basestring):
if n[-exp:] == '0' * exp:
n = '{0}{1}'.format(n[:-exp], name)
break
elif n[-1] == name:
n = n[:-1] + '0' * exp
break
by running exponents backwards you make sure that you find the right match.