However, why is the parenthesis left closed without any information inside of it?
df.corr()
Because there's nothing more to pass to the function. Or, more exactly (and assuming df
is something like a panda dataframe instance or other similar object), because the only required argument (df
) is, in this case, automagically passed to the function.
Why can't you put the variable within the expression like this -
corr(df)
You could do something like type(df).corr(df)
if you really want, but that's a bit useless.
Ok, let's go a bit deeper: Python is an object oriented language. In OO, objects have "methods" - functions that act on the object on which they are called. In most OOPLs, the syntax for method calls is obj.method()
instead of method(obj)
. Behind the scene, your language's compiler or interpreter (or whatever other mechanism) actually make obj
available to the method, so there's no need to pass it explicitely.
The point of having things this way - instead of having a standard function - is that different objects can define the same method each in it's own way, so as a "client" of those objects, you don't have to check the exact type and call the object-specific version yourself, ie:
without objects:
def draw_rect(rect):
# code to draw a rect here
def draw_line(line):
# code to draw a line here
def draw_circle(circle):
# code to draw a circle here
def draw_all(drawables):
for obj in drawables:
if isinstance(obj, Rect):
draw_rect(obj)
elif isinstance(obj, Line):
draw_line(obj)
elif isinstance(obj, Circle):
draw_circle(obj)
def main():
# a list of various "drawable" objects
objects = [Rect(), Line(), Cicle()]
draw_all(objects)
with objects:
class Rect():
def draw(self):
# code to draw a rect here
class Line():
def draw(self):
# code to draw a line here
class Circle():
def draw(self):
# code to draw a circle here
def draw_all(drawables):
for obj in drawables:
obj.draw()
def main():
# a list of various "drawable" objects
objects = [Rect(), Line(), Cicle()]
draw_all(objects)
and behind the scene, Python will turn obj.draw()
into type(obj).draw(obj)
. This is called "type-based polymorphic dispatch" and is really the most essential concept in OOP.
Now Python is not a "pure" OOPL, in that in doesn't force you into using only objects and methods - you can also write and use plain functions too (our draw_all
and main
functions above for example), which, of course, will work as you expect.