Help get the remainder in python

0

I get this error and I do not know why it is:

line 15, in toBinario
    residuo = ip%2
TypeError: not all arguments converted during string formatting

This is my code:

def toBinario(ip):
    binarios = []
    residuo = 0
    resultado = 0

    while True:
        residuo = ip%2
        resultado = ip/2
        ip = resultado
        binarios.append(residuo)
        print(binarios)
        if len(binarios) < 1:
            break
    
asked by Fernando 31.03.2018 в 06:02
source

1 answer

1

The freely translated error comes to say:

  

Typing error : not all arguments were converted during formatting of the string.

This really gives us the key, formatting of string . What is happening is that the function is passing a string ( str ) so that ip is a string and therefore in residuo = ip%2 the operator % is not interpreted as the operator module in the context of two integers, is interpreted in the context of the basic string formatting C-style ( interpolation operator ):

>>> "12345%d" % 2
'123452'

Since the string that is received (ip) does not contain any specifier that determines the type and position to embed the 2 , as in the previous example, formatting can not be carried out and it shows us the error mentioned.

It is important to remember that Python is a dynamic typing language but strongly typed , that is, the interpreter has no problem in inferring the type of value that a variable points to when we declare it:

>>> s = "1"  # tipo str
>>> i = 1    # tipo int

What you will never do is modify the type of a variable to "adapt" it to the context or operator that is implicitly applied to it. This is logically a design characteristic with a view to security and one of the principles of language: "better than implicit explicit". In this case ip is a string and operator% is interpreted in that context, instead the following line gives us an even clearer error:

>>> ip = "123"
>>> resultado = ip/2
Traceback (most recent call last):
  File "<pyshell#2>", line 1, in <module>
    resultado = ip/2
TypeError: unsupported operand type(s) for /: 'str' and 'int'

Python therefore forces us to explicitly cast int . In your case, or you do the casting before passing the argument to the function, which is perhaps the most logical:

i = int(i)
b = toBinario(i)

Or do the casting within the function:

def toBinario(ip):
    ip = int(ip)

Apparently you are trying to convert from int to binary representation. Your function more or less does that, but the problem is that you never break the cycle, it should be something like this:

def to_binary(n):
    bits = []

    while n:
        bit = n % 2
        n //= 2
        bits.append(str(bit))
    bits.reverse()
    return ''.join(bits)

The / operator in Python 2 returns the integer division if both operands are integers, in Python 3 the real division always returns. This is the cause of using // (integer division).

There are other possibilities such as:

  • Using bit-level operators:

    from collections import deque
    
    def to_binary(n):
        bits = deque()
    
        while n:
            bits.insert(0, str(n & 1))
            n >>= 1
        return ''.join(bits)
    
  • Using the built-in bin :

    def to_binary(n):
        return(bin(n)[2:])
    
  • Using string format:

    def to_binary(n):
        return(format(n, "b"))
    
    # Python >= 3.6
    def to_binary(n):
        return(f"{n:b}")
    

All of them presuppose that n is an integer and the output is a string with the binary representation of the string (although you could return a list for example):

>>> to_binary(148)
'10010100'
    
answered by 31.03.2018 в 20:01