Назначение функции вызова без скобок python

Рассмотрим следующее:

class objectTest():

    def __init__(self,a):

        self.value = a

    def get_value(self):

        return self.value


class execute():

    def __init__(self):

        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)


if __name__ == '__main__':

    execute = execute();

Этот код возвращает

>>>
False
False
True 
False

Учитывая, что get_value является функцией, я ожидал бы, что выполнение остановится и вернет ошибку, но это не так. Может кто-нибудь объяснить, почему интерпретатор python допускает такой синтаксис вместо повышения ошибки атрибута, который в моем случае спас бы мне драгоценное время.

Ответ 1

Как уже упоминалось, функции и методы являются первоклассными объектами. Вы вызываете их, бросая в конец скобки (скобки). Но похоже, что вам нужна еще одна мотивация к тому, почему python даже позволяет нам это делать. Почему нам должно быть интересно, являются ли функции первоклассными или нет?

Иногда вы не хотите называть их, вы хотите передать ссылку на вызываемый сам.

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

Если вы положили скобки после выше, он запускает ваш my_long_running_function в вашем основном потоке; вряд ли то, что вы хотели! Вы хотели бы дать Process ссылку на ваш вызываемый код, чтобы он запускался в новом процессе.

Иногда вы просто хотите указать вызываемый и разрешить что-то еще...

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

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

(map в этом случае) заполнить свои аргументы.

Может быть, вы просто захотите сбросить кучу вызовов в какую-нибудь коллекцию и вытащить ту, которую вы хотите динамически.

from operator import *

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

Вышеупомянутый способ - сопоставить строковые представления операторов с их действительным действием.

Ответ 2

Функции и методы в Python также являются объектами. Таким образом, вы можете сравнить их так же, как и любой другой объект.

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

Обычно, конечно, вы не будете сравнивать методы друг с другом или чем-то еще, потому что это не очень полезно. В одном месте это полезно, когда вы хотите передать функцию в другую функцию.

Ответ 3

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) Является ли возвращаемое значение вызова a.get_value() равным методу b.get_value?

2) Возвращает ли a.get_value() то же, что и b.get_value()?

3) Является ли метод-ссылка a.get_value равным методу-ссылке b.get_value?

Это вполне допустимый Python:)

Ответ 4

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

Ответ 5

Несколько комментаторов хотят получить пример того, где это полезно. Одно приложение находится в потоке. Нам нужно передать цель потоку без использования скобок. В противном случае цель создается в главном потоке, чего мы и пытаемся избежать.

Пример:

В test1.py я вызываю ThreadTest без использования скобок. test_thread запускается в потоке и позволяет test1.py продолжать работу.

В test2.py я передаю ThreadTest() в качестве цели. В этом случае поток не позволяет test2.py продолжать работу.

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')

вывод из test1.py:

thread_test started
not blocked
test_thread
test_thread
test_thread

вывод из test2.py:

thread_test started
test_thread
test_thread
test_thread

Я использую python3.5 на Linux Mint.

Ответ 6

Разница между функцией без скобок и скобками заключается в том, что при использовании скобок вы получите выходные данные этой функции, а при использовании функции без скобок вы создадите копию этой функции. например

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')

здесь мы копируем функцию externalFunction в x, а затем копируем y в x.