In the code below,
abc = (1,2,3)
a = abc[0]
b = abc[1]
c = abc[2]
print('%d, %d, %d' %(a,b,c)) # gives 1,2,3 as expected
a /= 3
b /= 3
c /= 3
print('%d, %d, %d' %(a,b,c)) # gives 0,0,1... which is NOT expected
I'm trying, however, to have a, b, c be 0.333, 0.6666, 1 respectively.
This problem persists even when I:
divide by 3.0
use a stupid abc = tuple([i/3.0 for i in abc]) workaround and then try to list all the elements again as above
even when I cast everything into a float like:
a = float(float(a)/float(3.0)) # still returns 0
I'm even using python 3, so an int/int division should return a float regardless.
Your print statements say to display the values as integers (%d); try using %f instead.
You are using %d so the output is printed as ints/decimal just use print:
print(a,b,c)
Use %f inside print statement
print('%f, %f, %f', %(a,b,c))
Related
After using Matlab for some time I grew quite fond of its sprintf function, which is vectorized (vectorization is the crucial part of the question).
Assuming one has a listli=[1,2,3,4,5,6],
sprintf("%d %d %d\n", li)
would apply the format on the elements in li one after another returning
"1 2 3\n4 5 6\n"
as string.
My current solution does not strike as very pythonic:
def my_sprintf(formatstr, args):
#number of arguments for format string:
n=formatstr.count('%')
res=""
#if there are k*n+m elements in the list, leave the last m out
for i in range(n,len(args)+1,n):
res+=formatstr%tuple(args[i-n:i])
return res
What would be the usual/better way of doing it in python?
Would it be possible, without explicitly eliciting the number of expected parameters from the format string (n=formatstr.count('%') feels like a hack)?
PS: For the sake of simplicity one could assume, that the number of elements in the list is a multiple of number of arguments in the format string.
You could use a variation of the grouper recipe if you get the user to pass in the chunk size.
def sprintf(iterable,fmt, n):
args = zip(*[iter(iterable)] * n)
return "".join([fmt % t for t in args])
Output:
In [144]: sprintf(li,"%.2f %.2f %d\n", 3)
Out[144]: '1.00 2.00 3\n4.00 5.00 6\n'
In [145]: sprintf(li,"%d %d %d\n", 3)
Out[145]: '1 2 3\n4 5 6\n'
You could handle when the chunk size was not a multiple of the list size using izip_longest and str.format but it would not let you specify the types without erroring :
from itertools import izip_longest
def sprintf(iterable, fmt, n, fillvalue=""):
args = izip_longest(*[iter(iterable)] * n, fillvalue=fillvalue)
return "".join([fmt.format(*t) for t in args])
If you split the placeholders or get the user to pass an iterable of placeholders you could catch all the potential issues.
def sprintf(iterable, fmt, sep=" "):
obj = object()
args = izip_longest(*[iter(iterable)] * len(fmt), fillvalue=obj)
return "".join(["{sep}".join([f % i for f, i in zip(fmt, t) if i is not obj]).format(sep=sep) + "\n"
for t in args])
Demo:
In [165]: sprintf(li, ["%.2f", "%d", "%.2f", "%2.f"])
Out[165]: '1.00 2 3.00 4\n5.00 6\n'
In [166]: sprintf(li, ["%d", "%d", "%d"])
Out[166]: '1 2 3\n4 5 6\n'
In [167]: sprintf(li, ["%f", "%f", "%.4f"])
Out[167]: '1.000000 2.000000 3.0000\n4.000000 5.000000 6.0000\n'
In [168]: sprintf(li, ["%.2f", "%d", "%.2f", "%2.f"])
Out[168]: '1.00 2 3.00 4\n5.00 6\n'
You may want to remove the += in the for loop. The following version is approximately three times faster than yours. It also works even in cases where you want to print the % symbol in the output. Therefore, the format string contains '%%'.
def my_sprintf(format_str, li):
n = format_str.count('%') - 2*format_str.count('%%')
repeats = len(li)//n
return (format_str*repeats) % tuple(li[:repeats*n])
A less hacky way is possible if you use the newer .format method instead of %. In such a case, you can use the string.Formatter().parse() method to get the list of fields used in the format_str.
The function then looks like this:
import string
li = [1, 2, 3, 4, 5, 6, 7]
format_str = '{:d} {:d} {:d}\n'
def my_sprintf(format_str, li):
formatter = string.Formatter()
n = len(list(filter(lambda a: a[2] is not None,
formatter.parse(format_str))))
repeats = len(li)//n
return (format_str*repeats).format(*li[:repeats*n])
I was using this question to help me create a Scientific Notation function, however instead of 4.08E+10 I wanted this: 4.08 x 10^10. So I made a working function like so:
def SciNotation(num,sig):
x='%.2e' %num #<-- Instead of 2, input sig here
x= x.split('e')
if (x[1])[0] == "-":
return x[0]+" x 10^"+ x[1].lstrip('0')
else:
return x[0]+" x 10^"+ (x[1])[1:].lstrip('0')
num = float(raw_input("Enter number: "))
sig = raw_input("Enter significant figures: ")
print SciNotation(num,2)
This function, when given an input of 99999 will print an output of 1.00 x 10^5 (2 significant figures). However, I need to make use of my sig variable (# of significant figures inputted by user). I know I have to input the sig variable into Line 2 of my code but I can't seem to get to work.
So far I have tried (with inputs num=99999, sig=2):
x='%.%de' %(num,sig)
TypeError: not all arguments converted during string formatting
x='%d.%de' %(num,sig)
x = 99999.2e (incorrect output)
x='{0}.{1}e'.format(num,sig)
x = 99999.0.2e (incorrect output)
Any help would be appreciated!
If you must do this, then the easiest way will be to just use the built in formating, and then just replace the e+05 or e-12 with whatever you'd rather have:
def sci_notation(number, sig_fig=2):
ret_string = "{0:.{1:d}e}".format(number, sig_fig)
a, b = ret_string.split("e")
# remove leading "+" and strip leading zeros
b = int(b)
return a + " * 10^" + str(b)
print sci_notation(10000, sig_fig=4)
# 1.0000 * 10^4
Use the new string formatting. The old style you're using is deprecated anyway:
In [1]: "{0:.{1}e}".format(3.0, 5)
Out[1]: '3.00000e+00'
Lets say I have the following function that converts ounces to lbs & oz
def oz2lboz(oz):
oz, lbs = oz - int(oz), int(oz)
l = lbs * 0.062500
o = oz
print "(%d,%d)" % (l,o)
Right now, if i was to compute oz2lboz(16), it would give me
(1,0)
However, I need it to give me,
(1,0.0)
How would i go about doing that?
First of all, the conversion algorithm you have is incorrect.
This line:
oz, lbs = oz - int(oz), int(oz)
Sets oz to be the value of the decimal portion and disguards the rest and lbs to the integer part. Then you multiply the pounds by 1/16, which in most cases will give you a decimal portion again, which is not usually whats wanted in this type of conversion.
Below we'll alter your original code to return a value to make a point:
def oz2lboz(oz):
oz, lbs = oz - int(oz), int(oz)
l = lbs * 0.062500
o = oz
return (l,o)
And call:
print "(%d,%.1f)" % oz2lboz(16)
>>> (1,0.0)
print "(%d,%.1f)" % oz2lboz(17)
>>> (1,0.0)
print "(%d,%.1f)" % oz2lboz(18)
>>> (1,0.0)
Well, that isn't right, 16, 17 and 18 oz are all equal to 1 pound! Lets try again and output the pounds using floats...
print "(%.1f,%.1f)" % oz2lboz(16)
>>> (1.0,0.0)
print "(%.1f,%.1f)" % oz2lboz(17)
>>> (1.1,0.0)
print "(%.1f,%.1f)" % oz2lboz(18)
>>> (1.1,0.0)
Better, but 17 and 18 are still the same... using more decimal points we get:
print "(%.4f,%.1f)" % oz2lboz(16)
>>> (1.0000,0.0)
print "(%.4f,%.1f)" % oz2lboz(17)
>>> (1.0625,0.0)
print "(%.4f,%.1f)" % oz2lboz(18)
>>> (1.1250,0.0)
So, basically unless there is a decimal portion you are going to be doing round behind the scenes, because the conversion is off.
Below I've rewritten your conversion in a correct and slightly simpler way that again returns the values rather than prints them, so you can output or reuse them as necessary.
def oz2lboz(oz):
lb=int(oz/16)
oz=float(oz%16)
return lb,oz
print oz2lboz(17)
Which gives this output:
(1, 1.0)
You can then use normal python string formatting to output it as needed, like so:
print "(%d,%.1f)" % oz2lboz(17) #using decimal integer and float formatting
>>> (1,1.0)
print "The baby weighed about, %d pounds and %d ounces." % oz2lboz(42) # just decimals
>>> The baby weighed about, 2 pounds and 10 ounces.
Or with our original "problematic" data we get the expected results:
print "(%d,%.1f)" % oz2lboz(16)
>>> (1,0.0)
print "(%d,%.1f)" % oz2lboz(17)
>>> (1,1.0)
print "(%d,%.1f)" % oz2lboz(18)
>>> (1,2.0)
Hi I'm trying to create a Fibonacci sequence generator in Python. This is my code:
d =raw_input("How many numbers would you like to display")
a = 1
b = 1
print a
print b
for d in range(d):
c = a + b
print c
a = b
b = c
When I ran this program, I get the error:
File "Fibonacci Sequence Gen.py", line 10, in <module>
for d in range(d):
TypeError: range() integer end argument expected, got str
Thanks for your help, I'm trying to teach myself python with basic projects.
raw_input returns a string. So convert d to an integer with:
d = int(d)
One more thing: Do not use for d in range(d). It works but it is awful, unpythonic, whatever.
Try this way for example:
numbers = raw_input("How many numbers would you like to display")
a = 1
b = 1
print a
print b
for d in range(int(numbers)):
c = a + b
print c
a = b
b = c
Edit: I complete below the answer with additional code tuning (thanks to commenters):
# one space will separate better visually question and entry in console
numbers = raw_input("How many numbers would you like to display > ")
# I personnally prefer this here, although you could put it
# as above as `range(int(numbers))` or in `int(raw_input())`
# In a robust program you should use try/except to catch wrong entries
# Note the number you enter should be > 2: you print 0,1 by default
numbers = int(numbers)
a, b = 0, 1 # tuple assignation
# note fibonnaci is 0,1,1,2,3...
print a # you can write this as print "%i\n%i" % (a, b)
print b # but I think several prints look better in this particular case.
for d in range(numbers - 2): # you already printed 2 numbers, now print 2 less
c = a + b
print c
a, b = b, c # value swapping.
# A sorter alternative for this three lines would be:
# `a, b = b, a + b`
# `print b`
Problem
The problem here is that here:
d = raw_input("How many numbers would you like to display")
you assign string from the input into the d variable, and later you pass it to range(). But range() expects expects integers, not strings, and Python does not convert it automatically (it leaves conversion to you).
Solution
The solution is to convert result of raw_input() into int like that:
d = int(raw_input("How many numbers would you like to display"))
and everything will work unless you provide non-integer.
But there is better (shorter, more efficient, more encapsulated) method of generating Fibonacci numbers (see below).
Better method of generating Fibonacci numbers
I believe this is the best (or nearly the best) solution:
def fibo(n):
a, b = 0, 1
for i in xrange(n):
yield a
a, b = b, a + b
This is a generator, not a simple function. It is very efficient, its code is short and does not print anything, but you can print its result like that:
>>> for i in fibo(20):
print i,
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181
or convert it into a list like that:
>>> list(fibo(20))
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181]
Applying the above in your case
After applying the above to your code, it could look like this:
def fibo(n):
a, b = 0, 1
for i in xrange(n):
yield a
a, b = b, a + b
d = int(raw_input("How many numbers would you like to display"))
for i in fibo(d):
print i
Does it answer your question?
You have to convert the input to a number, like this:
d = int(raw_input("How many numbers would you like to display: "))
Also, just for fun, the fibonacci sequence can be expressed more succinctly:
a, b = 0, 1
for i in range(d):
print a
a, b = b, a+b
raw_input returns string type.You need to convert it to int.
>>> x = raw_input()
2
>>> x
'2'
>>> type(x)
<type 'str'>
and range function requires int as an argument not string.
Thats why when i do
>>> range(x)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: range() integer end argument expected, got str.
So, change it to
for x in range(int(d)):
Simpler method:
a = [0,1]
for n in range(1,41):
a.append(a[n]+a[n-1])
print a[-1]
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
6765
10946
17711
28657
46368
75025
121393
196418
317811
514229
832040
1346269
2178309
3524578
5702887
9227465
14930352
24157817
39088169
63245986
102334155
165580141
I see many over complicated Fibonacci Sequence programs so I just did this with a while loop; changing the number after the while loop
a = 0
b = 1
while a <= 1000000000: #Changing this number will change how long the sequence goes on for
print(a)
print(b)
a = a+b
b = b+a
I know this isn't your program but it is a very basic version;
I hope this helps :)
is it possible some way to "print" in python in a fortran like way like this?
1 4.5656
2 24.0900
3 698.2300
4 -3.5000
So the decimal points is always in the same column, and we get always 3 or n decimal numbers?
Thanks
>>> '%11.4f' % -3.5
' -3.5000'
or the new style formatting:
>>> '{:11.4f}'.format(-3.5)
' -3.5000'
more about format specifiers in the docs.
You could also take a look at the fortranformat library on PyPI or the project page if you wanted to fully recreate FORTRAN text IO.
If you have any questions, send me an email (I wrote it).
for i in [(3, 4.534), (3, 15.234325), (10,341.11)]:
... print "%5i %8.4f" % i
...
3 4.5340
3 15.2343
10 341.1100
print "%10.3f" % f
will right align the number f (as an aside: %-10.3f would be left-aligned). The string will be right-aligned to 10 characters (it doesn't work any more with > 10 characters) and exactly 3 decimal digits. So:
f = 698.230 # <-- 7 characters when printed with %10.3f
print "%10.3f" % f # <-- will print " 698.2300" (two spaces)
As a test for your example set do the following:
print "\n".join(map(lambda f: "%10.3f" % f, [4.5656, 24.09, 698.23, -3.5]))
You can use string.rjust(), this way:
a = 4.5656
b = 24.0900
c = 698.2300
d = -3.5000
a = "%.4f" % a
b = "%.4f" % b
c = "%.4f" % c
d = "%.4f" % d
l = max(len(a), len(b), len(c), len(d))
for i in [a, b, c, d]:
print i.rjust(l+2)
Which gives:
~ $ python test.py
4.5656
24.0900
698.2300
-3.5000
Fortran io is totally different to C style io in every way.
Go for Brendan's fortranformat package.
https://pypi.python.org/pypi/fortranformat
easy_install fortranformat
This allows arcane old fortran input files to be created with much less trial and error than trying to use C style string formatting.