Is everything object in Python?

8

I am very confused about what is object and what can behave as an object, see the example I created to illustrate the situation:

def subtrai(x,y):
    return (x - y)

class OpeMatematica(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def soma(self):
        return (self.x + self.y)

soma = OpeMatematica(10,10)
print(soma.soma())

print(subtrai(100, 10))

s = subtrai
print(s(50,10))

s = soma
s.x = 10
s.y = 100
print(s.soma())

I created a subtrai function that performs a subtraction and created a OpeMatematica class with the attributes x and y and a soma method.

In this line:

soma = OpeMatematica(10,10)
print(soma.soma())

I instantiated my class OpeMatematica and invoked method soma and got the result 20 .

In this line:

print(subtrai(100, 10))

Invoke the function subtrai and get the result 90 .

In this line I discovered something interesting:

s = subtrai
print(s(50,10))

See that I assign the variable s to the function subtrai and it has passed the behavior of the function subtrai see s(50,10) , it is as if the subtrai function was an object and could be instantiated, the result of the operation is 40 .

And in this line has another curiosity:

s = soma
s.x = 10
s.y = 100
print(s.soma())

Assigns the s to the object soma and s to an object of type OpeMatematica , accessing the attributes x and y and invoking the soma method, the result is 110 .

Now I'm confused as to what a Python object is, analyzing this code I concluded that everything seems to be a Python object, even variables and functions , someone could you explain to me why Python has this behavior, and what is an object or a class in Python?

    
asked by anonymous 19.01.2016 / 15:16

1 answer

12

This is a very different concept. This means that Python functions are first class . That is, among other characteristics the function can be assigned to a variable (obviously it can also be passed as argument or function return). The function itself (code) is treated as if it were a value, a given. This is usually done with anonymous or lambdas functions, but you can do the same directly an existing function, as was done in the example.

In this case the variable will save the function and not a result of it. The type of this variable is FunctionType . Of course, it does not actually keep the source code of the function (I could, but I do not know any language that does this, it would be inefficient and risky), there are mechanisms that refer to the function and the compiler / interpreter knows how to handle this variable in a way different, and its access is given as a function call, since it is a function.

This concept has nothing to do with object orientation. But it may be that the internal way of storing the function in the variable is through an object (even without even using OOP). The more traditional, especially when it's not a closure , is that it's just one pointer . In the case of Python there is actually an object controlling this, but it is an object like any other. One of its members is __call__ that allows you to make the call.

In Python not everything is an object in the sense that people expect, the class's own syntax already gives a hint that it needs to be explicit about it. Leaving aside OOP, the concept of type object , in a certain way, we can say that everything in any language is an object. If it is not an object, then what? Of course this terminology may be strange to some, but it is real. In C you have objects, they are just not the same as in Java, for example.

Another less convenient way to do the same:

callable(s, 50, 10)

A function has an infrastructure in an object that allows it to be stored on it and then called. This is an internal mechanism that ensures the call. Like everything else in computing, there is no magic, there is engineering. Someone saw a problem, and found a workable solution to solve the problem. One of the ways to call a function stored in an object is through the function callable() . The other way is through the compiler calling the function using the direct form variable. With the help of the compiler the call becomes more convenient and elegant, as shown in the question.

If you're not sure if you can call it, you can check first:

s = 0
if hasattr(s, '__call__')
    s(50, 10)

This will not call anything and will not give error, because in this example the s variable is not "callable", it is an integer and not a function. Verifying whether the variable could be called as function was done before calling, avoiding the error. This way allows you to solve a lot of problems conveniently without resorting to object orientation.

    
19.01.2016 / 15:31