¿Qué significa cuando se omiten los paréntesis en una función o llamada a un método?

Resuelto user3311142 asked hace 10 años • 6 respuestas

Tengo este código de ejemplo:

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)

Los resultados mostrados son:

False
False
True 
False

¿Por qué esto no causa un error ? get_valuees un método, entonces ¿por qué podemos usarlo así sin llamarlo primero?


Ver también : En Python, ¿qué significa '<función en...>'?

user3311142 avatar Feb 15 '14 00:02 user3311142
Aceptado

Como se mencionó, las funciones y los métodos son objetos de primera clase. Los llamas colocando algunos paréntesis (corchetes) al final. Pero parece que quieres más motivación sobre por qué Python nos permite hacer eso. ¿Por qué debería importarnos si las funciones son de primera clase o no?

A veces no quieres llamarlos, quieres pasar una referencia al propio invocable.

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

Si coloca corchetes después de lo anterior, se ejecutará my_long_running_functionen su hilo principal; ¡Difícilmente lo que querías! Quería dar Processuna referencia a su invocable para que se ejecute solo en un nuevo proceso.

A veces solo quieres especificar el invocable y dejar algo más...

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

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

( mapen este caso) complete sus argumentos.

Tal vez solo desee colocar un montón de invocables en alguna colección y recuperar el que desee de manera dinámica.

from operator import *

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

Lo anterior es una forma de asignar representaciones de cadenas de operadores a su acción real.

roippi avatar Feb 14 '2014 18:02 roippi

Las funciones y métodos en Python también son objetos en sí mismos. Por lo tanto, puedes compararlos como lo harías con cualquier otro objeto.

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

Normalmente, por supuesto, no compararías métodos entre sí ni con ninguna otra cosa, porque no es muy útil. Un lugar en el que resulta útil es cuando desea pasar una función a otra función. Un uso común es ordenar una cadena que no distingue entre mayúsculas y minúsculas diciéndole que la use str.lowercomo método para generar la clave de clasificación:

>>> list_of_strings=['A','b','C']
>>> sorted(list_of_strings)
['A', 'C', 'b']
>>> sorted(list_of_strings, key=str.lower)
['A', 'b', 'C']
Mark Ransom avatar Feb 14 '2014 17:02 Mark Ransom
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
voronin avatar Feb 14 '2014 18:02 voronin
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) ¿El valor de retorno de la llamada es a.get_value()igual al método b.get_value?

2) ¿ a.get_value()Devuelve lo mismo que b.get_value()?

3) ¿Es la referencia del método a.get_valueigual a la referencia del método b.get_value?

Esto es Python perfectamente válido :)

Morten Jensen avatar Feb 14 '2014 17:02 Morten Jensen

Varios comentaristas quieren un ejemplo de dónde esto resulta útil. Una aplicación está en subprocesos. Necesitamos pasar el objetivo al hilo sin usar corchetes. De lo contrario, el objetivo se crea en el hilo principal, que es lo que intentamos evitar.

Ejemplo:

En test1.py llamo a ThreadTest sin usar corchetes. test_thread comienza en el hilo y permite que test1.py continúe ejecutándose.

En test2.py, paso ThreadTest() como objetivo. En este caso, el hilo no permite que test2.py continúe ejecutándose.

prueba1.py

import threading
from thread_test import ThreadTest

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

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

salida de test1.py:

thread_test started
not blocked
test_thread
test_thread
test_thread

salida de test2.py:

thread_test started
test_thread
test_thread
test_thread

Estoy usando python3.5 en Linux Mint.

Oppy avatar May 16 '2018 17:05 Oppy