Rewriting over int value in int subclass impossible? - python

I am currently on a python 3 project in witch I work a lot with binary representation of ints, because of this, I made a classe to make the work easier for myself, but I can't make it fully work :
class EnhancedInt(int):
def __init__(self, x: Union[str, bytes, SupportsInt] = ...) -> None:
int.__init__(int(x))
def __getitem__(self, key: int) -> int:
"""Returns the digit number key from the binary representation of self (little endian)
Args:
key (int):
Returns:
int:
"""
if key > 32:
raise ValueError("int are 32 bits long, %d given is too much" % key)
if key < 0:
raise ValueError("Negative keys not supported, %d given is too low" % key)
else:
return EnhancedInt((self >> key) & 1)
def __setitem__(self, key: int, value: int) -> None:
if value != 0 and value != 1:
raise ValueError('Value must be 0 or 1')
self -= self[key]*pow(2, key)
if value:
self += pow(2, key)
So, the part that's not working : __setitem__. I understand why, changing self seems a bit brutal, but I can't find where the value is stored in an int.
For additional comprehension, here is the code calling my class :
>>> i = EnhancedInt(5)
>>> print(i[1])
0
>>> i[1] = 1
>>> print(i)
5 ????
I would like for 7 to be returned, but for now, only 5 is returned.

I found a working solution, even though it required a lot of work, compared to what I wanted to do. I did the following :
class EnhancedInt(int):
"""
Does everything a int can do, but can also be addressed bitwise (you can read, write,
add and delete a bit at given position)
Bit representation is in little endian : the lowest indexes corresponding to the least
significant bits
"""
def __init__(self, x: Union[str, bytes, SupportsInt]) -> None:
int.__init__(int(x))
self.__value__ = int(x)
def __getitem__(self, key: int) -> int:
"""Returns the digit number *key* from the binary representation of *self* (little endian)
Args:
key (int): bit number to be returned
Returns:
int: value of the bit addressed
"""
EnhancedInt._check_key_value(key)
return (self.__value__ >> key) & 1
def __setitem__(self, key: int, value: int) -> None:
"""Changes the value of the *key*th bit of *self* (little endian)
Args:
key (int): index of bit to be modified
value (int): bit value (must be 0 or 1)
"""
EnhancedInt._check_key_value(key)
if value != 0 and value != 1:
raise ValueError("Value must be 0 or 1, %d given" % value)
if (not self[key]) and value:
self.__value__ += 1 << key
return None
if self[key] and not value:
self.__value__ -= 1 << key
I also redefines all the methods used for the class int.
This method seems overkill, and has other flaws. I'd like to find a more elegant way, but meanwhile, this will to.
The complete code can be found at the following address : https://github.com/assombrance/Quantomatic/blob/master/src/data.py

Related

How to make python stop looking if there is a negative value?

I have a dict:
ff = {("Tom Brady",45678 ): [[456.0, 4050.0], [0.32, 5.6]]}
and
f = {("Tom Brady",45678 ): [[456.0, 4050.0, -1000.0], [0.32, 5.6, 4.56]]}
I have this code:
def find_neg (client_list: dict[tuple[str, int], list[list[float]]], client: tuple[str, int]) -> int
for a in client_list[client][0]:
if a>0:
return 2
if a<0
return 1
the problem with this code is that when there is no negative value, python gives me an error telling me it cannot be NoneType. I want the code to give me an answer if there is a negative, but instead it only gives me an error.
Your current logic is:
def help_find_neg(lst: list[float]):
for element in lst:
if element > 0:
return 2
if element < 0:
return 1
# and if element == 0: go to the next element
If your lst consists only of zeros, the function will skip all of them (and return None).
This might be the reason behind your NoneType error.
You could make the list of lists (the value in your dictionaries) into one big list, and then use list comprehension to create a new list that only holds the negative numbers. If the length of this list comprehension result is bigger than 0, then you have negative numbers in any of the lists that is in the value of your dictionary.
def find_neg (client_list: dict[tuple[str, int], list[list[float]]], client: tuple[str, int]) -> int:
big_list = sum(client_list[client], [])
negatives = [i for i in big_list if i < 0]
if len(negatives) > 0:
return True
return False
(the sum is a little trick to create one list out of a list of lists).
As per comments; if you only need to know if there was a negative number (and you will never need to know what number(s) those were), you could simplify:
def find_neg (client_list: dict[tuple[str, int], list[list[float]]], client: tuple[str, int]) -> int:
big_list = sum(client_list[client], [])
for i in big_list:
if i < 0:
return True
return False

Type hints in python puzzled by from typing import Any

I have the following exercise:
Annotate with correct types the parameters and the return values of
the functions, as well as of the variables, in the program in the
other panel. For that, you only need to replace every occurrence of
Any, except for the very first line, by an appropriate type.
Example: The first Any in line 3, i.e., n: Any, must be replaced by
int. You can see that from the line 9.
While I understand the theory of type hints I don't get the exercise, most probably because I do not get at this point the use of Any.
Furthermore the exercise is ambiguous, it says to replace every occurrence of Any.
If this is the case would the first line be:
def get_half(n : int) -> int:
return n/2
If so it does not work.
from typing import Any #do not edit this line
def get_half(n : Any) -> Any:
return n/2
def print_half(n : Any) -> Any:
print(n/2)
y = get_half(10)
print_half(20)
def is_present(s : Any, char : Any) -> Any:
found : Any = False
l : Any = len(s)
for i in range(0, l):
if s[i] == char:
found = True
return found
print(is_present("john", "h"))
This is the correct solution thanks to your answers
This link was very useful
https://mypy-play.net/?mypy=latest&python=3.10
from typing import Any #do not edit this line
def get_half(n : int) -> float:
return n/2
def print_half(n : int) -> None:
print(n/2)
y = get_half(10)
print_half(20)
def is_present(s : str, char : str) -> bool:
found : bool = False
l : int = len(s)
for i in range(0, l):
if s[i] == char:
found = True
return found
print(is_present("john", "h"))
The first any is an int like the example said def get_half(n : int) -> Any: and the return value will differ depending if your exercise is for python 2 or 3.
Python2: def get_half(n : int) -> int:
Python3: def get_half(n : int) -> float:
The reason for this is that Python 2 always returns an int if you divide and int with an int. int/int=int And Python 3 uses "true division" and therefor returns an float. int/int=float
For more info see: https://en.wikibooks.org/wiki/Python_Programming/Operators

typing.Generator extract ReturnType from Generator

taking this properly typed example from the official Python docs:
def echo_round() -> Generator[int, float, str]:
sent = yield 0
while sent >= 0:
sent = yield round(sent)
return 'Done'
How does one "extract" the ReturnType? Consider the following example:
def use_generator() -> str:
# Do generator stuff, keeping this a minimal example...
next(echo_round())
# Finally get the return value
val = echo_round()
# Do something else?
return val
The mypy error message I receive for the last line:
Incompatible return value type (got "Generator[int, float, str]", expected "str")
The val variable receives the generator object from echo_round(). The val value stays a generator type because the code does nothing with the value, and therefore is returned as Generator[int, float, str] type. This is causing an error because use_generator() expects to return val as str type.

Function handling floating point numbers to produce a boolean

I've been struggling with the following Boolean problem:
Write a function even_int that consumes any type of data, produces True if it is an even integer, and produces False otherwise.
I wrote:
def even_int(any):
return type(any) != type("a") and float(any % 2 == 0.0)
Feedback on your program:
Make sure your function works when the input is a floating point number.
Don't really understand this feedback. I put the float in front so that should be covered. I also tried without the float or the decimal on the 0.
I think you should just directly check if any is an integer type. I also don't think you need to put a float around any % 2 == 0
def even_int(value):
return isinstance(value, int) and value % 2 == 0
EDIT:
if you want to accept floats as well,
def even_int(value):
return isinstance(value, (float, int)) and value % 2 == 0
I would try this - it's pythonic in that it asks for forgiveness rather than permission by trying to convert to an int (this means it works for strings as well) and catches the TypeError to return False if that doesn't work either.
def even_int(v):
try:
return int(v) % 2 == 0 #will trigger exception if v cannot be cast to int
except (TypeError, ValueError):
return False
EDIT: Simplified based on comments

Checking type of variable against multiple types doesn't produce expected result

Task:
Define a function, distance_from_zero with one parameter.
Have that function do the following:
Check the type of the input it receives.
If the type is int or float, the function should return the absolute value of the function input.
If the type is any other type, the function should return "Not an integer or float!"
My answer that does not work:
def distance_from_zero(d):
if type(d) == int or float:
return abs(d)
else:
return "Not an integer or float!"
You should use isinstance here rather than type:
def distance_from_zero(d):
if isinstance(d, (int, float)):
return abs(d)
else:
return "Not an integer or float!"
if type(d) == int or float is always going to be True as it is evaluated as float and it is a True value:
>>> bool(float)
True
help on isinstance:
>>> print isinstance.__doc__
isinstance(object, class-or-type-or-tuple) -> bool
Return whether an object is an instance of a class or of a subclass thereof.
With a type as second argument, return whether that is the object's type.
The form using a tuple, isinstance(x, (A, B, ...)), is a shortcut for
isinstance(x, A) or isinstance(x, B) or ... (etc.).
Related : How to compare type of an object in Python?
The type check should be
if isinstance(d, int) or isinstance(d, float):
which can be abbreviated
if isinstance(d, (int, float))
What your current code is testing is
(type(d) == int) or float
or, in words: "either the type of d is int, or float is true". For technical reasons, this entire expression is always true. Logical expressions in programming languages have to be specified a bit more precisely than in natural language.
You cannot use this kind of "natural language based logic concatenation". What I mean is that you need to state the parts of your logical conditions explicitly.
if type(d) == int or type(d) == float
This way you have the two comparisons, which stand for themselves: if type(d) == int as well as type(d) == float. The results of this can be combined with the or-operator.
Here is a correct code:
def distance_from_zero(d):
if type(d) in (int, float):
return abs(d)
else:
return "Not an integer or float!"
print distance_from_zero(3)
print distance_from_zero(-5.4)
print distance_from_zero("abc")
Output:
3
5.4
Not an integer or float!
Please be aware of indention, in Python is very important comparing to other languages.
In programming, if statements don't work like they do in plain language. If you want to say something like This fruit is an apple or an orange, you need to program it as
if type(fruit) == Apple or type(fruit) == Orange
More specific to your problem, you want to use isinstance() instead of type(), as isinstance() will properly account for subclassing. See this answer for more details.
So you should end up with something like
def distance_from_zero(d):
if isinstance(d, int) or isinstance(d, float):
    return abs(d)
else:
    return "Not an integer or float!"
The mistake you are making is using a little too much of English shortforms.
if type(d) == int or float:
This means check if the type is int or if float is True, which is not what you want.
if type(d) == int or type(d) == float:
This will give required result.

Categories