He aquí un ejemplo de lo que quiero decir:
def foo(): foo = 5 print(foo + 5) foo() # => 10El código no produce ningún error y funciona perfectamente. Esto contradice la idea de que las variables y las funciones no deberían tener el mismo nombre a menos que las sobrescriba. ¿Por qué funciona? Y cuando se aplica al código real, ¿debería usar diferentes funciones/nombres de variables locales, o está perfectamente bien?
foo = 5 crea una variable local dentro de su función. def foo crea una variable global. Es por eso que ambos pueden tener el mismo nombre.
Si hace referencia a foo dentro de su función foo() , se está refiriendo a la variable local. Si hace referencia a foo fuera de esa función, se está refiriendo a la variable global.
Dado que evidentemente causa confusión para las personas que intentan seguir el código, probablemente no debería hacer esto.
La respuesta es sí. Las funciones son objetos de primera clase en Python. No existe una diferencia fundamental entre la función foo y la variable foo . Ambos son referencias a la memoria y ambos tienen un alcance, por lo que ambos son equivalentes a una variable. Si ha definido foo como una función y luego no la sobrescribe localmente, será como una variable global (tomada del ámbito de nivel superior):
def foo(): print(foo)y luego, si lo sobrescribe con una variable local, solo definirá una variable local dentro del alcance de la función:
def foo(): foo = 3 print(foo)En Python, cada referencia (variable) se puede sobrescribir durante la vida útil de un ámbito en particular. Puedes probar:
def foo(): pass foo = 3Esto sobrescribirá el valor de foo y apuntará ahora a 3 en lugar de la función foo en la memoria.
Bueno, es por el alcance de la variable que es cada foo . La función foo() está en el ámbito global, por lo tanto, se puede llamar dentro de otras funciones y fuera de las funciones.
Sin embargo, la variable foo está en el ámbito local. Eso significa que solo "existe" dentro de la función, no se puede llamar o hacer referencia fuera de la función.
Por lo tanto, cada función diferente crea su propio ámbito local cuando se llama, y las variables creadas dentro se olvidan tan pronto como se destruye el ámbito (la función finaliza).
Se puede acceder a las variables globales dentro del ámbito local, no se puede acceder a las variables locales en el ámbito global.
Si desea crear la variable en el ámbito global, llámela así:
global varAquí hay un ejemplo de alcance global y local:
var=1 def foo1(): var=3 foo1() print(var) #prints 1 because the "var" in foo1() is locally assigned def foo2(): global var var=2 foo2() print(var) #prints 2 because "var" is global Entonces, su función funciona porque solo asigna el nombre foo localmente, no globalmente.
Sin embargo , si llama a foo() más adelante en esa función, generará un error porque ese alcance local ha asignado un valor int a foo , no una función, por lo tanto, no se puede llamar.
Algo que nadie más ha mencionado todavía: Python es un lenguaje dinámico , con muy poca verificación estática. Así que cuando escribes
def foo(): foo = 5 print(foo + 5) es posible que haya estado pensando en eso como una "contradicción": ¿cómo puede foo ser una función y una variable entera al mismo tiempo? La respuesta de primer orden es "Son dos foo s diferentes", porque el foo interno es solo una variable local, sin relación con el nombre global foo . ¡Pero hágalo global y el código seguirá funcionando!
def foo(): global foo foo = 5 print(foo + 5) foo() # OK, prints 10 ¡En este código solo hay un foo ! Sin embargo, no es "tanto una variable como una función". Primero, en las líneas 1 a 4, definimos foo como una función con cierto cuerpo, pero aún no ejecutamos ese cuerpo. Después de la línea 4, el foo global tiene una función. Luego, en la línea 6, llamamos a la función a la que se refiere foo , que ejecuta su cuerpo. Lo primero que hace el cuerpo es asignar 5 a foo ... y ahora foo contiene un número entero. Al ejecutar un código que asigna un nuevo valor a foo , hemos cambiado el valor de foo . Solía ser esa-función-allí; ahora es 5. En un lenguaje de escritura dinámica como Python, no hay nada de malo en esto.
def foo(): global foo foo = 5 print(foo + 5) foo() # OK, prints 10 (and incidentally assigns a new value to foo) foo() # Raises TypeError: 'int' object is not callableEn python, el alcance de la variable se determina buscando desde el alcance más interno actual hasta el alcance global.
En cualquier momento durante la ejecución, hay 3 o 4 ámbitos anidados cuyos espacios de nombres son directamente accesibles:
Una peculiaridad especial de Python es que, si no hay una declaración global o no local en vigor, las asignaciones de nombres siempre van al ámbito más interno.
En el ejemplo,
# Current Modules Scope Starts here. def foo(): # Local Scope Starts here. foo = 5 print(foo + 5) # Local scope Ends here. foo() # Current Modules Scope Ends here.Aplicando las reglas anteriores para resolver el alcance de
foo = 5 pertenece al ámbito local ya que no hay declaración global o nonlocal . foo que está dentro de la función pertenece al ámbito local de la función.
print(foo + 5) resuelve el foo presente dentro de la función cuando python comienza a buscar desde el alcance más interno. Se aplican las reglas de resolución de alcance 1 y 2. El alcance más interno aquí es el mismo que el alcance de la función envolvente.
foo() se llama en el ámbito de nivel de módulo. Python comienza a buscar en el alcance más interno disponible, que aquí es a nivel de módulo. Por lo tanto, resolvió la función definida en el nivel del módulo.
Otro ejemplo,
def foo(): print(foo + 5) foo() # TypeError: unsupported operand type(s) for +: 'function' and 'int'foo() se llama en el ámbito de nivel de módulo. Python comienza a buscar en el alcance más interno disponible, que aquí es a nivel de módulo. Por lo tanto, resolvió la función definida en el nivel del módulo.print(foo + 5) también se resolvería en la función foo a nivel de módulo porque python inicia la búsqueda en el alcance de la función adjunta pero no encontró ninguna coincidencia. Se movió al siguiente ámbito, es decir, a nivel de módulo, y se encontró una coincidencia. El partido es la función foo . Por lo tanto, el error.Otro ejemplo,
def foo(): foo = "str" def inner(): #(1) foo = 1 # Commented this line print(foo) inner() print(foo) foo() # str # str # Uncommenting (1) gives output as foo() # 1 # strMás información sobre las reglas de alcance
Otro problema con el uso del mismo nombre es obviamente la ambigüedad al escribir recursiones:
def fibo(n: int) -> int: if n <= 1: fibo = 1 else: fibo = fibo(n - 1) + fibo(n - 2) return fiboResultados en:
UnboundLocalError: variable local 'fibo' referenciada antes de la asignación
Sucede porque cuando fibo se define dentro de la función. Cuando Python intenta ejecutar fibo(n - 1) , busca la variable fibo local y no encuentra su valor.
Solo un breve comentario: pylint marca esto con una advertencia. pylint es nuestro amigo!