I have a script with a lot of print calls.
I want to limit all the printed numbers to a maximum of 5 decimals, but changing it by hand with f_strings or formatting would be a lot of work.
Is there any way to specify at the beginning of the script that whenever I call a print function or use an f string, I do not want to know more than 5 (or n) decimals without having to change the formatting of every call I make?
I just care about the representation of the screen. It does not matter to me if the number under the hood has more decimals.
Essentially, instead of having to rewrite each print to this
print(f'{value:.6f}')
I would like somethink akin to this:
#define max_print_length = 10
Thanks!
I have looked for ways to try and change the behaviour of the print function or defining some kind of flag at the beggining of the script but, so far I'm empty handed. I found a couple of solutions but they are for different programming languages.
As I do not think there is a method of setting a float precision for the entire code, maybe a not-so-elegant custom print method that takes in multiple parameters would be useful. For example-
def myprint(dict_to_print: Dict[str,float], precision:int)->None:
to_print = f""
for key, value in dict_to_print.items():
to_print += f"{key}: {value:.{precision}f}\n"
print(to_print)
myprint({'1st': 12.9943943504538, '2nd': 9.4093485739048}, 2)
>>> 1st: 12.99
2nd: 9.41
PS. a one-liner:
def myprint(dict_to_print: Dict[str, float], precision: int) -> None:
print("".join([f"{key}:{value:.{precision}f}\n" for key, value in dict_to_print.items()]))
Related
I have a file that has 3 values on each line. It is a fairly random file, and any of these values can be str or int.
George, 34s, Nikon
42, absent, Alan
apple, 111, 41
marked, 15, never
...
So, I read in the line, and using split I get the first value:
theFile = r"C:\... "
tDC = open(theFile, "r")
for theLine in tDC:
a, b, c = theLine.split(',')
So far so good.
Where I'm stuck is when I try to deal with variable a. I need to deal with it differently if it is a str or if it is an int. I tried setting a = int(a), but if it is a string (e.g., 'George') then I get an error. I tried if type(a) = int or if isinstance(a,int), but neither work because all the values come in as a string!
So, how do I evaluate the value NOT looking at its assigned 'type'? Specifically, I want to read all the a's and find the maximum value of all the numbers (they'll be integers, but could be large -- six digits, perhaps).
Is there a way to read in the line so that numbers come in as numbers and strings come in as strings, or perhaps there is a way to evaluate the value itself without looking at the type?
The first point is that you need some rule that tells you which values are integers and which ones aren't. In a data set that includes things like 32s, I'm not sure it makes sense to just treat anything that could be an integer as if it were.
But, for simplicity, let's assume that is the rule you want: anything that could be an integer is. So, int(a) is already pretty close; the only issue is that it can fail. What do you do with that?
Python is designed around EAFP: it's Easier to Ask Forgiveness than Permission. Try something, and then deal with the fact that it might fail. As Cyber suggests, with a try statement:
try:
intvalue = int(a)
except ValueError:
# Oops, it wasn't an int, and that's fine
pass
else:
# It was an int, and now we have the int value
maxvalue = max(maxvalue, intvalue)
isalpha() Returns "True" if all characters in the string are in the alphabet
isnumeric() Returns "True" if all characters in the string are numeric
so;
data="Hello World"
print(data.isnumeric()) #it will retuns with False
print(data.isalpha()) # True
Sorry for my soulles answer, I just came here for same issue, I found a different way and wanted to share with you
values = theLine.split(',')
for value in values:
try:
number = int(value)
# process as number
except ValueError:
# process value as string
this :
def ret_var(my_var: int) -> int:
try:
intvalue = int(my_var)
return my_var
except ValueError:
print("my_var not int!")
I have created the following snippet of code and I am trying to convert my 5 dp DNumber to a 2 dp one and insert this into a string. However which ever method I try to use, always seems to revert the DNumber back to the original number of decimal places (5)
Code snippet below:
if key == (1, 1):
DNumber = '{r[csvnum]}'.format(r=row)
# returns 7.65321
DNumber = """%.2f""" % (float(DNumber))
# returns 7.65
Check2 = False
if DNumber:
if DNumber <= float(8):
Check2 = True
if Check2:
print DNumber
# returns 7.65
string = 'test {r[csvhello]} TESTHERE test'.format(r=row).replace("TESTHERE", str("""%.2f""" % (float(gtpe))))
# returns: test Hello 7.65321 test
string = 'test {r[csvhello]} TESTHERE test'.format(r=row).replace("TESTHERE", str(DNumber))
# returns: test Hello 7.65321 test
What I hoped it would return: test Hello 7.65 test
Any Ideas or suggestion on alternative methods to try?
It seems like you were hoping that converting the float to a 2-decimal-place string and then back to a float would give you a 2-decimal-place float.
The first problem is that your code doesn't actually do that anywhere. If you'd done that, you would get something very close to 7.65, not 7.65321.
But the bigger problem is that what you're trying to do doesn't make any sense. A float always has 53 binary digits, no matter what. If you round it to two decimal digits (no matter how you do it, including by converting to string and back), what you actually get is a float rounded to two decimal digits and then rounded to 53 binary digits. The closest float to 7.65 is not exactly 7.65, but 7.650000000000000355271368.* So, that's what you'd end up with. And there's no way around that; it's inherent to the way float is stored.
However, there is a different type you can use for this: decimal.Decimal. For example:
>>> f = 7.65321
>>> s = '%.2f' % f
>>> d = decimal.Decimal(s)
>>> f, s, d
(7.65321, '7.65', Decimal('7.65'))
Or, of course, you could just pass around a string instead of a float (as you're accidentally doing in your code already), or you could remember to use the .2f format every time you want to output it.
As a side note, since your DNumber ends up as a string, this line is not doing anything useful:
if DNumber <= 8:
In Python 2.x, comparing two values of different types gives you a consistent but arbitrary and meaningless answer. With CPython 2.x, it will always be False.** In a different Python 2.x implementation, it might be different. In Python 3.x, it raises a TypeError.
And changing it to this doesn't help in any way:
if DNumber <= float(8):
Now, instead of comparing a str to an int, you're comparing a str to a float. This is exactly as meaningless, and follows the exact same rules. (Also, float(8) means the same thing as 8.0, but less readable and potentially slower.)
For that matter, this:
if DNumber:
… is always going to be true. For a number, if foo checks whether it's non-zero. That's a bad idea for float values (you should check whether it's within some absolute or relative error range of 0). But again, you don't have a float value; you have a str. And for strings, if foo checks whether the string is non-empty. So, even if you started off with 0, your string "0.00" is going to be true.
* I'm assuming here that you're using CPython, on a platform that uses IEEE-754 double for its C double type, and that all those extra conversions back and forth between string and float aren't introducing any additional errors.
** The rule is, slightly simplified: If you compare two numbers, they're converted to a type that can hold them both; otherwise, if either value is None it's smaller; otherwise, if either value is a number, it's smaller; otherwise, whichever one's type has an alphabetically earlier name is smaller.
I think you're trying to do the following - combine the formatting with the getter:
>>> a = 123.456789
>>> row = {'csvnum': a}
>>> print 'test {r[csvnum]:.2f} hello'.format(r=row)
test 123.46 hello
If your number is a 7 followed by five digits, you might want to try:
print "%r" % float(str(x)[:4])
where x is the float in question.
Example:
>>>x = 1.11111
>>>print "%r" % float(str(x)[:4])
>>>1.11
I'm writing a program that converts an integer to binary and everything has worked well save for one thing. I have the binary numbers stored in a list, so therefore I want to join the list together using the join() function. This works well too, however since the list is stored as integers I must concatenate an empty string with the binary list (whilst converting each number into a string). By the way, it's nothing to do with the rest of the code because i've experimented this with a standalone program and I still get the same results. The code is as follows:
import backwards
class Binary(object):
binary=[1,2,4,8,16,32,64,128,256]
answer=[]
def __init__(self,enter):
self.enter=enter
if self.enter>256:
self.alternative()
elif self.enter<=256:
self.calculate()
def add(self,a,b):
a.append(b)
def clear(self):
Binary.binary=[]
def calculate(self):
start=len(Binary.binary)
start-=1
on=1
off=0
while start>-1:
if self.enter<Binary.binary[start]:
self.add(Binary.answer,off)
start-=1
elif self.enter>=Binary.binary[start]:
self.add(Binary.answer,on)
self.enter-=Binary.binary[start]
start-=1
def alternative(self):
current_max=256
while Binary.binary[len(Binary.binary)-1]<self.enter:
current_max*=2
self.add(Binary.binary,current_max)
self.calculate()
def __str__(self):
converted=""
for i in Binary.answer:
converted+=str(Binary.answer[i])
joined=''.join(converted)
final_answer=backwards.back(joined)
return joined
a=int(input("Enter the decimal number you want to convert to binary: "))
b=Binary(a)
print(b)
The backwards module is a function I created that basically reverses a string. Basically, THE PROBLEM IS IS THAT if the first two binary numbers start with a 0, it will print every other 1 as a 0 too (so prints out 00000000). I've purposefully returned the joined variable to prove this (the final_answer variable just reverses the string like I said). As mentioned before, it's nothing to do with the rest of the code as I get the same results when I do this by itself. So how do I make it print out properly without mysteriously converting 1s to 0s, but at the same time ensuring that the list is still joined.
Your code as is does nothing since it never calls Binary.
b=Binary # needs to be b=Binary(200), for example, to be called.
I commented out the use of backwards since it wasn't provided and actually call Binary with b=Binary(200) and print(b) and get 011001000, which is correct for 200, so I'd guess the problem is your backwards module that isn't provided for us to see.
You can just do the following instead of all this code to get the same answer. 09b means format as nine digits with leading zeros in binary.
>>> format(200,'09b')
'011001000'
Edit
Found the bug. Binary(54) prints all zeros as you stated. The bug is in this line in the __str__ function:
for i in Binary.answer:
converted+=str(Binary.answer[i])
i is the actual digit (0 or 1) so if the first two digits are zero Binary.answer[i] always looks up a zero. You want:
for i in Binary.answer:
converted+=str(i)
def binary(i):
i, n = divmod(i, 2)
n = str(n)
if i == 0:
return n
return binary(i) + str(n)
I am looking for a slick function that reverses the digits of the binary representation of a number.
If f were such a function I would have
int(reversed(s),2) == f(int(s,2)) whenever s is a string of zeros and ones starting with 1.
Right now I am using lambda x: int(''.join(reversed(bin(x)[2:])),2)
which is ok as far as conciseness is concerned, but it seems like a pretty roundabout way of doing this.
I was wondering if there was a nicer (perhaps faster) way with bitwise operators and what not.
How about
int('{0:b}'.format(n)[::-1], 2)
or
int(bin(n)[:1:-1], 2)
The second method seems to be the faster of the two, however both are much faster than your current method:
import timeit
print timeit.timeit("int('{0:b}'.format(n)[::-1], 2)", 'n = 123456')
print timeit.timeit("int(bin(n)[:1:-1], 2)", 'n = 123456')
print timeit.timeit("int(''.join(reversed(bin(n)[2:])),2)", 'n = 123456')
1.13251614571
0.710681915283
2.23476600647
You could do it with shift operators like this:
def revbits(x):
rev = 0
while x:
rev <<= 1
rev += x & 1
x >>= 1
return rev
It doesn't seem any faster than your method, though (in fact, slightly slower for me).
Here is my suggestion:
In [83]: int(''.join(bin(x)[:1:-1]), 2)
Out[83]: 9987
Same method, slightly simplified.
I would argue your current method is perfectly fine, but you can lose the list() call, as str.join() will accept any iterable:
def binary_reverse(num):
return int(''.join(reversed(bin(num)[2:])), 2)
It would also advise against using lambda for anything but the simplest of functions, where it will only be used once, and makes surrounding code clearer by being inlined.
The reason I feel this is fine as it describes what you want to do - take the binary representation of a number, reverse it, then get a number again. That makes this code very readable, and that should be a priority.
There is an entire half chapter of Hacker's Delight devoted to this issue (Section 7-1: Reversing Bits and Bytes) using binary operations, bit shifts, and other goodies. Seems like these are all possible in Python and it should be much quicker than the binary-to-string-and-reverse methods.
The book isn't available publicly but I found this blog post that discusses some of it. The method shown in the blog post follows the following quote from the book:
Bit reversal can be done quite efficiently by interchanging adjacent
single bits, then interchanging adjacent 2-bit fields, and so on, as
shown below. These five assignment statements can be executed in any
order.
http://blog.sacaluta.com/2011/02/hackers-delight-reversing-bits.html
>>> def bit_rev(n):
... return int(bin(n)[:1:-1], 2)
...
>>> bit_rev(2)
1
>>>bit_rev(10)
5
What if you wanted to reverse the binary value based on a specific amount of bits, i.e. 1 = 2b'00000001? In this case the reverse value would be 2b'10000000 or 128 (dec) respectively 0x80 (hex).
def binary_reverse(num, bit_length):
# Convert to binary and pad with 0s on the left
bin_val = bin(num)[2:].zfill(bit_length)
return int(''.join(reversed(bin_val)), 2)
# Or, alternatively:
# return int(bin_val[::-1], 2)
Let's say there is a parameter n. Can n be any numbers? For example, question like this: Given a non-negative number num, return True if num is within 2 of a multiple of 10. This is what I am thinking:
def near_ten(num):
n = int #So I assume n can be any integer
if abs(num - n*10) <=2:
return True
Return False
However, there are two problems. First, in n*10, * is a unsupported operand type cuz I thought I could use Python as a calculator. 2nd, I cannot just simply say n = int, then n can be viewed as a variable as any number (or integer) in a math function. If there is a way that I could use n in that way, then life would be so much easier.
Finally I figure it out in another way which doesn't include "n" as a parameter:
def near_ten(num):
if num%10<=2:
return True
if (num+2)%10<=2:
return True
return False
However, I'm still curious about "n" as a parameter mentioned before. Since I'm just a starter, so this is really confusing.
In Python, int is a type. Types are first-class objects in Python, and can be bound to names. Of course, trying to multiply a type by a number is usually meaningless, so the operation is not defined by default. It can be referred to by the new name though.
n = int
print(n(3.4))
print(n('10') == 10)
Here is a much simpler solution:
def near_mult_ten(num):
return abs(num - (num+5) // 10 * 10) <= 2
Edit: Fixed.
try this:
d=a%10
if d<=2 or d>=8:
return True
return False
I am new to coding as well so forgive any mistakes.
i am not sure if you have ran your code or not, but python is a high level interpreted language, python CAN distinguish between variable types and therefore you do not need to explicitly declare them, your function header is valid.
you can also do operations between integers and floats/doubles without the need of casting, python already handles that for you
your function will raise an error in any compiler, ur n variable is declared, you have defined it, but you have not initialized it