What does it mean when the parentheses are omitted from a function or method call?
Asked Answered
W

6

28

I have this example code:

class objectTest():
    def __init__(self, a):
        self.value = a

    def get_value(self):
        return self.value

a = objectTest(1)
b = objectTest(1)
        
print(a == b)
print(a.get_value() == b.get_value)
print(a.get_value() == b.get_value())
print(a.get_value == b.get_value)

The displayed results are:

False
False
True 
False

Why doesn't this cause an error? get_value is a method, so why can we use it like this without calling it first?


See also: In Python, what does '<function at ...>' mean?

Weightless answered 14/2, 2014 at 17:37 Comment(2)
Just in case you arrived here because you really do want to call a function without paranetheses, note is is possible sometimes via hacky decators. e.g. >>> f = lambda *args: print('hi') >>> @f ... class _: pass ... hi Photoflood
@Photoflood When would you ever need to do that?Nock
G
40

As mentioned, functions and methods are first-class objects. You call them by throwing some parentheses (brackets) on the end. But it looks like you want some more motivation for why python even lets us do that. Why should we care if functions are first-class or not?

Sometimes you don't want to call them, you want to pass a reference to the callable itself.

from multiprocessing import Process
t = Process(target=my_long_running_function)

If you put brackets after the above, it runs your my_long_running_function in your main thread; hardly what you wanted! You wanted to give Process a reference to your callable that it will run itself in a new process.

Sometimes you just want to specify the callable and let something else...

def do_something(s):
    return s[::-1].upper()

map(do_something,['hey','what up','yo'])
Out[3]: ['YEH', 'PU TAHW', 'OY']

(map in this case) fill in its arguments.

Maybe you just want to drop a bunch of callables into some collection, and fetch the one you want in a dynamic manner.

from operator import *

str_ops = {'<':lt,'>':gt,'==':eq} # etc
op = str_ops.get(my_operator)
if op:
    result = op(lhs,rhs)

The above is one way to map string representations of operators onto their actual action.

Gaily answered 14/2, 2014 at 18:8 Comment(1)
so in that context, if I see an assert do_something in code, what would that mean? In, short what would assert ing a function achieve?Pow
L
26

Functions and methods in Python are also objects themselves. Thus you can compare them just as you would any other object.

>>> type(a.get_value)
<type 'instancemethod'>
>>> type(a.get_value())
<type 'int'>

Normally of course you wouldn't compare methods to each other or anything else, because it's not terribly useful. One place it's useful is when you want to pass a function into another function. One common usage is for a case-insensitive string sort by telling it to use str.lower as the method to generate the sort key:

>>> list_of_strings=['A','b','C']
>>> sorted(list_of_strings)
['A', 'C', 'b']
>>> sorted(list_of_strings, key=str.lower)
['A', 'b', 'C']
Ladybird answered 14/2, 2014 at 17:39 Comment(2)
To briefly expand on Mark's comment, you aren't actually calling the method when you enter a.get_value without the parens at the end. You're just referencing the object associated with the method.Declan
Give some examples of how to use this\ why this is desirable and get a +1Protozoan
D
7
def mul(a, b):
    return a * b

def add(a, b):
    return a + b

def do(op, a, b):
    return op(a, b)

do(add, 2, 3)  # return 5
Dyslexia answered 14/2, 2014 at 18:13 Comment(0)
P
6
print(a.get_value() == b.get_value)   # 1
print(a.get_value() == b.get_value()) # 2
print(a.get_value == b.get_value)     # 3

1) Is return value of calling a.get_value() equal to the method b.get_value ?

2) Does a.get_value() return the same as b.get_value() ?

3) Is the method-reference a.get_value equal to the method-reference b.get_value ?

This is perfectly valid Python :)

Procrustean answered 14/2, 2014 at 17:42 Comment(0)
L
1

Several commentators want an example of where this is useful. One application is in threading. We need to pass the target to the thread without using brackets. Otherwise the target is created in the main thread, which is what we are trying to avoid.

Example:

In test1.py I call ThreadTest without using brackets. test_thread starts in the thread and allows test1.py to continue running.

In test2.py, I pass ThreadTest() as the target. In this case the thread does not allow test2.py to continue running.

test1.py

import threading
from thread_test import ThreadTest

thread = threading.Thread(target=ThreadTest)
thread.start()
print('not blocked')

test2.py

import threading
from thread_test import ThreadTest

thread = threading.Thread(target=ThreadTest())
thread.start()
print('not blocked')

test_thread.py

from time import sleep


class ThreadTest():
    def __init__(self):
        print('thread_test started')
        while True:
            sleep(1)
            print('test_thread')

output from test1.py:

thread_test started
not blocked
test_thread
test_thread
test_thread

output from test2.py:

thread_test started
test_thread
test_thread
test_thread

I am using python3.5 on Linux Mint.

Lian answered 16/5, 2018 at 17:1 Comment(1)
"Otherwise the target is created in the main thread, which is what we are trying to avoid" - do you mean that the target is executed-called (instead of "created") in the main thread? @LianMaroc
W
1

Difference between function without parentheses and with parentheses is that when using parentheses you will get the output of that function and when you use the function without parentheses you create a copy of that function. for example

def outerFunction(text): 
    text = text 

    def innerFunction(): 
        print(text) 

    return innerFunction()

if __name__ == '__main__': 
    outerFunction('Hey!') 
    x = outerFunction
    y = x 
    x('Hey i am busy can you call me later')
    y('this is not a function')

here we copy the function outerFunction to x and then copy y to x.

Weltschmerz answered 1/7, 2019 at 10:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.