I'm doing a bunch of work in the Python console, and most of it is referring to addresses, which I'd prefer to see in hex.
So if a = 0xBADF00D, when I simply enter Python> a into the console to view its value, I'd prefer python to reply with 0xBADF00D instead of 195948557.
I know I can enter '0x%X' % a to see it in hex, but I'm looking for some sort of python console option to have it do this automatically. Does something liket this exist? Thanks!
The regular Python interpreter will call sys.displayhook to do the actual displaying of expressions you enter. You can replace it with something that displays exactly what you want, but you have to keep in mind that it is called for all expressions the interactive interpreter wants to display:
>>> import sys
>>> 1
1
>>> "1"
'1'
>>> def display_as_hex(item):
... if isinstance(item, (int, long)):
... print hex(item)
... else:
... print repr(item)
...
>>> sys.displayhook = display_as_hex
>>> 1
0x1
>>> "1"
'1'
I suspect you'll quickly get tired of seeing all integers as hex, though, and switch to explicitly converting the ones you want to see as hex accordingly.
Building on previous answers, here's a version that works for Python 2/3, doesn't display bools as hex, and also properly sets the _ variable:
import sys
def _displayhook(o):
if type(o).__name__ in ('int', 'long'):
print(hex(o))
__builtins__._ = o
else:
sys.__displayhook__(o)
def hexon():
sys.displayhook = _displayhook
def hexoff():
sys.displayhook=sys.__displayhook__
Something like this, perhaps?
class HexInt(int):
"Same as int, but __repr__() uses hex"
def __repr__(self):
return hex(self)
So you'd use that when creating all your integers that you want to be shown as hex values.
Example:
>>> a = HexInt(12345)
>>> b = HexInt(54321)
>>> a
0x3039
>>> b
0xd431
>>> c = HexInt(a + b)
>>> c
0x1046a
Note that if you wanted to skip the explicit creation of a new HexInt when doing arithmetic operations, you'd have to override the existing int versions of methods such as __add__(), __sub__(), etc., such that they'd return HexInts.
Modifying the top python2 answer for python3...
def display_as_hex(item):
if isinstance(item, int):
print(hex(item))
else:
print(repr(item))
import sys
sys.displayhook = display_as_hex
You could so something like this:
while True:
print hex(input('> '))
To get a basic prompt that prints the hex value of all of the results. You could even make it conditional -- check to see if the return type of input is a string or number, and if it is, print the hex value, else print the value normally.
Related
I am working on python 2-3 compatibility. When working with str and byte types, there is an issue I am coming across. Here is an example
# python 2
x = b"%r" % u'hello' # this returns "u'hello'"
# python 3
x = b"%r" % u'hello' # this returns b"'hello'"
Notice how the extra unicode u appears in the final representation of x in python 2? I need to make my code return the same value in python3 and python2. My code can take in str, bytes, or unicode values.
I can coerce the python 3 value to the python 2 value by doing
# note: six.text_type comes from the six compatibility library. Basically checks to see if something is unicode in py2 and py3.
new_data = b"%r" % original_input
if isinstance(original_input, six.text_type) and not new_data.startswith(b"u'"):
new_data = b"u%s"
This makes the u'hello' case work correct but messes up the 'hello' case.
This is what happens:
# python 2
x = b"%r" % 'hello' # this returns "'hello'"
# python 3
x = b"%r" % 'hello' # this returns b"'hello'"
The problem is that in python 3 u'hello' is the same as 'hello', So if I include my code above, the result for both u'hello and 'hello' end up returning the same result as u'hello in python 3.
So I need some kind of way to tell if a python 3 input string explicitly has specified the u in front of the string, and only execute my code above if that case is satisfied.
It's a simple matter of knowing what version of python you are currently executing, and looking at the type of the input. Of course, this is just taking what data you have and producing a consistent output. It's not going to recover syntactic sugar from the "original source code" because that's not the data you have to work with. I'm just going for a consistent output like you asked for when you said, "I need to make my code return the same value in python3 and python2."
In python2 you'll probably be dealing with str and unicode.
In python3 you'll probably be dealing with bytes and str.
Look at the python version first, because if you compare to a data type that doesn't exist in that version, it will raise an exception just trying to do the check.
import six
if six.PY2:
samples = ['hello', u'hello']
elif six.PY3:
samples = ['hello', bytes('hello', 'utf-8')]
else:
raise ValueError('python version unknown')
def normalize(message):
if six.PY2:
if type(message)==unicode:
return str(message)
elif type(message)==str:
return message
else:
raise ValueError('expected string type, got ' + message.__class__.__name__)
elif six.PY3:
if type(message)==bytes:
return message.decode('utf-8')
elif type(message)==str:
return message
else:
raise ValueError('expected string type, got ' + message.__class__.__name__)
else:
raise ValueError('python version unknown')
for message in samples:
print(normalize(message))
This is tested on 2.7.5 and 3.9.2
If you have bytes in python2, it's just an alias for str (https://stackoverflow.com/a/5901825/1766544)
I have a requirement to return a price range from function something like
"£150 to £199"
but when the function returns the value coverts to "\u00a3150 to \u00a3199".
now I understand that the value "\u00a" is escaped version of £.
but when I print("\u00a3150") it prints £150 I have tried using encoding and unichr(163) but I could not return the value as £150.
Any help is much appreciated.
Just to make it cogent..
def price_range(price):
print("Print value {}".format(price))
return "Return value {}".format(price)
So now if I send the value "£150 to £199" the output is below
>>> price_range("£150 to £199")
Print value £150 to £199
Return value \xa3150 to \xa3199'
I think you are just making a confusion between the internal representation of a string and the way it is displayed by print.
When you evaluate an expression in interactive mode, Python displays the representation of the result of the expression.
Just look this in a terminal using Latin1 charset:
>>> t = '\xa3150'
>>> t
'\xa3150'
>>> print t
£150
>>> repr(t)
"'\\xa3150'"
>>> print(repr(t))
'\xa3150'
Similarily with you example, you get the correct display, if you print the returned value:
>>> x = price_range("£150 to £199")
Print value £150 to £199
>>> x
'Return value \xa3150 to \xa3199'
>>> print x
Return value £150 to £199
In fact the eval loop of the Python interpretor is close to :
while True:
expr = input(">>> ")
print(repr(expr))
(It is indeed far more complex because of EOF and error processing, but thinking of it that way is enough to understand what happens with your code)
In python we have conversion specifier like
'{0!s}'.format(10)
which prints
'10'
How can I make my own conversion specifiers like
'{0!d}'.format(4561321)
which print integers in following format
4,561,321
Or converts it into binary like
'{0!b}'.format(2)
which prints
10
What are the classes I need to inherit and which functions I need to modify? If possible please provide a small example.
Thanks!!
What you want to do is impossible, because built-in types cannot be modified and literals always refer to built-in types.
There is a special method to handle the formatting of values, that is __format__, however it only handles the format string, not the conversion specifier, i.e. you can customize how {0:d} is handled but not how {0!d} is. The only things that work with ! are s and r.
Note that d and b already exist as format specifiers:
>>> '{0:b}'.format(2)
'10'
In any case you could implement your own class that handles formatting:
class MyInt:
def __init__(self, value):
self.value = value
def __format__(self, fmt):
if fmt == 'd':
text = list(str(self.value))
elif fmt == 'b':
text = list(bin(self.value)[2:])
for i in range(len(text)-3, 0, -3):
text.insert(i, ',')
return ''.join(text)
Used as:
>>> '{0:d}'.format(MyInt(5000000))
5,000,000
>>> '{0:b}'.format(MyInt(8))
1,000
Try not to make your own and try to use default functions already present in python. You can use,
'{0:b}'.format(2) # for binary
'{0:d}'.format(2) # for integer
'{0:x}'.format(2) # for hexadecimal
'{0:f}'.format(2) # for float
'{0:e}'.format(2) # for exponential
Please refer https://docs.python.org/2/library/string.html#formatspec for more.
We've all made this kind of mistake in python:
if ( number < string ):
python silently accepts this and just gives incorrect output.
Thank goodness python 3 finally warns us. But in some cases python 2.7 is needed. Is there any way in python 2.7 to guard against this mistake other than "just be careful" (which we all know doesn't work 100% of the time)?
You could explicitly convert both numbers to int. The string will get converted, and the number won't be effected (it's already an int). So this saves you the need to start remembering what type of value the number holds:
a = 11
b = "2"
print a > b # prints False, which isn't what you intended
print int(a) > int(b) # prints True
EDIT:
As noted in the comments, you cannot assume a number is an integer. However, applying the same train of though with the proper function - float should work just fine:
a = 11
b = "2"
print a > b # prints False, which isn't what you intended
print float(a) > float(b) # prints True
If you really, really want to be 100% sure that comparing strings and ints is impossible, you can overload the __builtin__.int (and __builtin__.float, etc. as necessary) method to disallow comparing ints (and floats, etc) with strings. It would look like this:
import __builtin__
class no_str_cmp_int(int):
def __lt__(self,other):
if type(other) is str:
raise TypeError
return super.__lt__(other)
def __gt__(self,other):
if type(other) is str:
raise TypeError
return super.__gt__(other)
# implement __gte__, __lte__ and others as necessary
# replace the builtin int method to disallow string comparisons
__builtin__.int = no_str_cmp_int
x = int(10)
Then, if you attempted to do something like this, you'd receive this error:
>>> print x < '15'
Traceback (most recent call last):
File "<pyshell#15>", line 1, in <module>
print x < '15'
File "tmp.py", line 7, in __lt__
raise TypeError
TypeError
There is a major caveat to this approach, though. It only replaces the int function, so every time you created an int, you'd have to pass it through the function, as I do in the declaration of x above. Literals will continue to be the original int type, and as far as I am aware there is no way to change this. However, if you properly create these objects, they will continue to work with the 100% assurance you desire.
Just convert the string or any data type to float first.
When two data types are same, then only we can compare them.
Suppose,
a = "10"
b= 9.3
c=9
We want to add a,b,c.. So,
So, the correct way to add these three is to convert them to same data type and then add.
a = float(a)
b = float(b)
c = float(c)
print a+b+c
You can check if each variable is an int like this :
if ( isinstance(number, int) and isinstance(string, int) ):
if (number < string):
Do something
else:
Do something else
else :
print "NaN"
*Edit:
To check for a float too the code should be :
if ( isinstance(number, (int,float )) and isinstance(string, (int,float) ) ):
Okay, I want to use repr() to print out a text version of a bunch of lists and nested arrays.
But I want the numbers to have only 4 decimal places not: 42.7635745114 but 32.7635.
I'd like to use repr() because of its nice ability to handle nested arrays. Writing my own print loop is an unattractive option.
Surely there is some way to overload repr to do this? I see there is a repr and reprlib modules but examples are really scarce, like nonexistent.
No, there is no way to overload repr(). The format for floats is hardcoded in the C source code.
The float_repr() function calls a helper function with the 'r' formatter, which eventually calls a utility function that hardcodes the format to what comes down to format(float, '.16g').
You could subclass float, but to only do that for representing values (especially in a larger structure) is overkill. This is where repr (reprlib in Python 3) comes in; that library is designed to print useful representations of arbitrary data structures, and letting you hook into printing specific types in that structure.
You could use the repr module by subclassing repr.Repr(), providing a repr_float() method to handle floats:
try: # Python 3
import reprlib
except ImportError: # Python 2
import repr as reprlib
class FloatRepr(reprlib.Repr):
def repr_float(self, value, level):
return format(value, '.4f')
print(FloatRepr().repr(object_to_represent))
Demo:
>>> import random
>>> import reprlib
>>> class FloatRepr(reprlib.Repr):
... def repr_float(self, value, level):
... return format(value, '.4f')
...
>>> print(FloatRepr().repr([random.random() for _ in range(5)]))
[0.5613, 0.9042, 0.3891, 0.7396, 0.0140]
You may want to set the max* attributes on your subclass to influence how many values are printed per container type.
Maybe you could try string formatting using return "%.4f" %(self.float):
>>> class obj:
... def __init__(self, value):
... self.float = value
... def __repr__(self):
... return "%.4f" %(self.float)
...
>>> x = obj(8.1231231253252)
>>> x.float
8.1231231253252
>>> x
8.1231
>>>