|
|
|||||||||
|
|||||||||
| |||||||||
|
|
|
| |||||||||
![]() |
|
|
«
Previous Thread
|
Next Thread
»
|
Thread Tools | Search this Thread | Rate Thread | Display Modes |
|
|
|
Stop making mediocre tutorials.The best tutorials are video! Camtasia Studio makes it easy to create engaging, buzz-building screen videos at any size, in any popular format. Download the free trial!
|
|
#1
|
|||
|
|||
|
Okay. I have ran into the first problem in python that I havent been able to solve myself, and I am asking for your help. My problem is that I have created a very simple app that calculates a door cutlist for a cabinet shop. The user inputs the different dimensions of the door and the output tells them what to cut. Now the problem seem to be having is the output doesnt give the correct decimals. If you set the values by hand an not allow for user input it works fine. But using input() seems to throw it out the window.
Also some of the dimensions need to be mixed numbers like 2 and 1/2 inches or 2 1/2 for the user input. But when I try this it gives me and invalid syntax error. My code is as follows: Code:
from __future__ import division
q = input(" Number of doors: ")
w = input(" Width: ")
l = input(" Length: ")
c = input(" Cut depth: ")
m = input("Machine clearance: ")
s = input(" Stile width: ")
r = input(" Rail width: ")
sl = l
rl = w-(2*s)+(2*c)
pl = sl-(2*r)-(2*c)-(2*m)
pw = w -(2*s)-(2*c)-(2*m)
rq = 2*q
sq = 2*q
pq = q
print "Cutlist for: ", q, "doors", w, "x", l
print ""
print " Panels: ", pq, pw, "x", pl
print " Stiles: ", sq, s, "x", sl
print " Rails: ", rq, r, "x", rl
Some test inputs for reproduction are: Number of doors: 1 Width: 12 Length: 12 Cut Depth: 1/8 Machine clearance: 1/32 Stile width: 2.5 Rail width: 2.5 That will give you the output with incorrect decimals. For the Mixed number error change the 2.5 to 2 1/2 Any suggestions would be greatly appreciated. ![]() Last edited by DFarist : March 21st, 2004 at 10:51 PM. |
|
#2
|
|||
|
|||
|
the problem is that by default the division operator between two integers returns an integer value. This is the same way that languages like C do it, so it has some historical precedent. To get a floating point number, one of the numbers needs to be a float. e.g.
Code:
>>> 1/2 0 >>> 1.0/2 0.5 >>> float(1)/2 0.5 >>> However the developers of Python realise this is a problem, and are in the process of changing it. They can't do this all in one go since it will break existing code, so from Python 2.2 this behaviour is deprecated. From version 2.4 the division operator on integers will return a floating point number, which is what you want. If you are using 2.2 or 2.3 then you can get this behaviour now by doing "from __future__ import division" at the start of your code: Code:
>>> from __future__ import division >>> 1/2 0.5 See PEP 238 at http://www.python.org/peps/pep-0238.html for the full gory details. This will fix your problem, but will mean your program will fail if run on versions earlier than 2.2. This may or may not be a problem for you, depending on how you distribute it. This will also still not allow the user to enter values such as 2 1/2, since that is not a valid Python expression. It would need to be written as 2+1/2 or 2.5. Also, if you are going to run this on a server then using 'input' is not safe - the user could enter any Python statements, and take control of your system, delete files etc. The alternative is to write your own expression parser, which is a non-trivial task for a novice programmer but would give complete control over how the user's input is interpreted. If you decide to go this route, let us know and I will post some pointers to writing it. Regards, Dave - The Developers' Coach |
|
#3
|
||||
|
||||
|
The problem is a bit more interesting - it seems that (on Python 2.3 at least) the input () function ignores the
from __future__ import division command statement. Code:
>>> from __future__ import division >>> 1/2 0.5 >>> input() 1/2 0 >>> a = raw_input() 1/2 >>> a '1/2' >>> eval(a.strip()) 0.5 However, as you can see above combining raw_input() with eval() seems to avoid the problem. Grim ![]()
__________________
*** Experimental Python Markup CGI V2 *** |
|
#4
|
||||
|
||||
|
My guess - this is an oversight (bug) due the the fact that no one really uses input in code that others will use - because of the security issues.
|
|
#5
|
||||
|
||||
|
I don't get enough practice with regular expressions but here's my solution:
It allows input in the form integer, floating point and integer with fraction. The fraction is deliberately constrained to only allow single digit numerators. Code:
from __future__ import division
import re
imperial = re.compile(r"(\d*\s+\d/\d+)|(\d/\d+)")
metric = re.compile(r"(\d*\.\d+)|(\d+)(?!.*/)")
def NumericInput(prompt="Input value:"):
while True:
inp = raw_input(prompt).strip()
match = imperial.match(inp)
try:
if match:
val = match.group().replace(" ", "+", 1)
value = eval(val)
break
else:
match = metric.match(inp)
if match:
val = match.group()
value = eval(val)
break
except:
pass
print "Input format '1' , '1.5' or '1 1/2', retry..."
return value
q = NumericInput(" Number of doors: ")
w = NumericInput(" Width: ")
l = NumericInput(" Length: ")
c = NumericInput(" Cut depth: ")
m = NumericInput("Machine clearance: ")
s = NumericInput(" Stile width: ")
r = NumericInput(" Rail width: ")
sl = l
rl = w-(2*s)+(2*c)
pl = sl-(2*r)-(2*c)-(2*m)
pw = w-(2*s)-(2*c)-(2*m)
rq = 2*q
sq = 2*q
pq = q
print "Cutlist for: ", q, "doors", w, "x", l
print ""
print " Panels: ", pq, pw, "x", pl
print " Stiles: ", sq, s, "x", sl
print " Rails: ", rq, r, "x", rl
I'm sure it can be improved on ![]() Grim |
|
#6
|
|||
|
|||
|
Grim Archon. That method worked exactly like I wanted it to. Thank you so much for your help. I have one more question though. Is there any way to get the output to also be in fractions and mixed numbers or am I just asking to much in that line? If you get tired of typing all this just let me know where to find out information, because I have been looking forever. Thanks again.
|
|
#7
|
||||
|
||||
|
My function to handle numberic input, enjoy!
Code:
#!/usr/bin/env python
import re
def nuput(prompt = 'Enter a number: '):
#Parses raw input depending on user input; this can be an int, float or
#Fraction. If an error occurs while parsing then raise a 'TypeError' for
#error catching purposes.
numbers = []
try:
for number in raw_input(prompt).split():
#Loops over each int, float and fraction in the raw_input()
#call and checks that the input fits given patterns.
if len(number) > 1:
if re.search('^(\d+/\d+)$', number):
#Checks if the the string 'number' is a fraction.
#Unpacks numbers and assigns the values to 'one'
#and 'two'.
one, two = map(float, number.split('/'))
#Appends a string of float / float to 'numbers'.
numbers.append('%f/%f' % (one, two))
elif re.search('^(\d*\.\d+)$', number):
numbers.append(number)
elif number.isdigit(): numbers.append(number)
#Returns an evaluted expression of the values passed to nuput().
return eval('+'.join(numbers))
except:
raise TypeError, 'Input must be Decimal, Float or Fraction.'
Spot an error, let me know. Mark. |
|
#8
|
||||
|
||||
|
It was an fun twist on the temperature conversion problem
![]() This version of the code attempts to match half, 4ths,5ths,8ths,10ths,16ths and 32ths. If it can't then it just prints floating point. Code:
from __future__ import division
import re
imperial = re.compile(r"(\d*\s+\d/\d+)|(\d/\d+)")
metric = re.compile(r"(\d*\.\d+)|(\d+)(?!.*/)")
#Generate Fractions
fractions = {}
for n in range(1, 32):
fractions["%0.5f"%(n/32.0)] = "%s/32"%n
for n in range(1, 16):
fractions["%0.5f"%(n/16.0)] = "%s/16"%n
for n in range(1, 10):
fractions["%0.5f"%(n/10.0)] = "%s/10"%n
for n in range(1, 8):
fractions["%0.5f"%(n/8.0)] = "%s/8"%n
for n in range(1, 5):
fractions["%0.5f"%(n/5.0)] = "%s/5"%n
for n in range(1, 4):
fractions["%0.5f"%(n/4.0)] = "%s/4"%n
for n in range(1, 3):
fractions["%0.5f"%(n/3.0)] = "%s/3"%n
fractions['0.00000'] = ''
fractions["0.50000"] = "1/2"
#End of Fractions
def NumericInput(prompt="Input value:"):
while True:
inp = raw_input(prompt).strip()
match = imperial.match(inp)
try:
if match:
val = match.group().replace(" ", "+", 1)
value = eval(val)
break
else:
match = metric.match(inp)
if match:
val = match.group()
value = eval(val)
break
except:
pass
print "Input format '1' , '1.5' or '1 1/2', retry..."
return value
def ImpPrint(value):
neg = ''
if value<0:
neg = '-'
value = -value
integer = int(value)
remainder = "%0.5f"%(value-integer)
if fractions.has_key(remainder):
return "%s%d %s"%(neg, integer, fractions[remainder])
else:
return "%s%d.%s"%(neg, integer, remainder)
q = NumericInput(" Number of doors: ")
w = NumericInput(" Width: ")
l = NumericInput(" Length: ")
c = NumericInput(" Cut depth: ")
m = NumericInput("Machine clearance: ")
s = NumericInput(" Stile width: ")
r = NumericInput(" Rail width: ")
sl = l
rl = w-(2*s)+(2*c)
pl = sl-(2*r)-(2*c)-(2*m)
pw = w-(2*s)-(2*c)-(2*m)
rq = 2*q
sq = 2*q
pq = q
print "Cutlist for: %4d doors %-8s x %-8s"%(q, ImpPrint(w), ImpPrint(l))
print ""
print " Panels: %4d %-8s x %-8s"%(pq, ImpPrint(pw), ImpPrint(pl))
print " Stiles: %4d %-8s x %-8s"%(sq, ImpPrint(s), ImpPrint(sl))
print " Rails: %4d %-8s x %-8s"%(rq, ImpPrint(r), ImpPrint(rl))
If you don't like the fractions I chose (do you use 16ths?) then just modify the fraction generator - (the order is important). I hope this helps ![]() Grim |
|
#9
|
||||
|
||||
|
Quote:
Nice code Netytan -- in colour ![]() Last edited by netytan : March 22nd, 2004 at 08:01 PM. |
|
#10
|
|||
|
|||
|
Grim, when I ran your code I got an invalid syntax on the
if value<0: It highlights the semi-colon. I am running Python 2.3 if that has anything to do with it. Also I hate to ask, but all this stuff looks latin to me. I understand the basic idea of these code snippets but maybe you could help me understand how to do my own. For future reference. Or atleast point me toward some reading material. That would be great. Again, thanks for all yalls help. |
|
#11
|
||||
|
||||
|
The problem here is that devshed doesnt display html entities, change > with > and < with < and the program should
work fine .Also, a good place to start would be the Python tutorial at Python.org, what exactly are you looking for? Mark. |
|
#12
|
|||
|
|||
|
Okay, I tried fixing the code like you said but it gave me a semanic error. Anyway, I will just live with the decimal output because I am amazed that we could get the fractions working. As far as the tutorial goes. I know the basics of Python, so the beginners tutorials wont really help that much. I am looking for things that explain the stuff like:
Code:
imperial = re.compile(r"(\d*\s+\d/\d+)|(\d/\d+)") metric = re.compile(r"(\d*\.\d+)|(\d+)(?!.*/)") I have no clue what all those 'd's and 's's mean. I can kinda follow but not very ?comprehendably? Other than that I can follow an reproduce yalls code with the exception of some minor syntax errors because of stupid mistakes. The logic is fine. Any pointers would be great, but that is what I am mainly confused on. Thanks |