Módulos, variables globales y más problemas en Python

juaja

Buena tardes amiwitos, tengo un problema con Python que seguro es una tontería pero es que soy un novato en Python, y necesito un script para un trabajo.

El problema es el siguiente:

Yo tenía un script gigante lleno de funciones, tal que así:

def myfunction(test,myfile):
    printFunction(myfile)

def printFunction(myfile):
    print myfile

test = "prueba"
myfile = "archivo"

myfunction(test,myfile)

Esto funcionaba.. bueno pues he separado las funciones a un módulo dejándolo tal que así:

Fichero principal

from my_module import *

test = "prueba"
myfile = "archivo"

myfunction(test,myfile)

Fichero my_module

def myfunction(test,myfile):
    printFunction(myfile)

def printFunction(myfile):
    print myfile

Y ahora, este es el error que da:

Global name myfile is not defined

Sé que algo no estoy haciendo bien con las variables globales o los módulos, o algo no estoy entendiendo. A ver si alguien me puede ayudar porque estoy desesperado... :(

cabron

Hace algún tiempo que no toco python así que no te lo digo 100% seguro, pero creo que tienes que cualificar el nombre de la función con el del módulo, tal que así:

my_module.myfunction(test,myfile)

C

Tienes algunos errores importantes, incluso para un novato, bastante antes de llegar a dominar los paquetes y módulos:

1.- No tienes declarado ni los nombres de 'test' ni 'myfile'

2.- La palabra 'imports' no es reservada. Se usa 'import', sin la 's' final.

3.- La definición de funciones acaban con el caracter de los dos puntos.

Creo que con eso te funcionará o al menos estarás mucho más cerca.

1 respuesta
juaja

#3 Si, esos fallos han sido al escribir el código para no escribir el original. Lo corrijo, el problema creo que no es de sintaxis, sino de que hay algún tipo de problema al llamar desde una función de un módulo a otra función del mismo módulo. Es en la segunda función, printfunction donde el valor ya llega vacío, sin embargo se llama la función con una variable que tiene valor, por eso mis dudas sobre variables globales y locales y el alcance de las variables en python. :(

1 respuesta
C

#4 El problema (al menos para mí) es que si pones el código a medias no puedo hacer una comprobación válida. Por ejemplo, el siguiente test tiene el código completo, funciona y es comprobable (en una terminal de linux):

$ cat my_module.py
def myfunction(test,myfile):
    printFunction(myfile)

def printFunction(myfile):
    print myfile

$ cat main.py
from my_module import *

test = "a"
myfile = "b"

myfunction(test,myfile)

$ python2 main.py
b
1 respuesta
juaja

#5 Tienes razón, es que lo puse un poco deprisa y corriendo porque estaba desesperado.

Si esa prueba funciona, quizás el fallo no está donde yo pensaba. Voy a hacer unas pruebas y comento.

Gracias.

Edit: Funciona perfectamente, puff pues entonces voy listo...

juaja

Bueno pongo el código real a ver si me podéis ayudar :santo:
functions.py

def GenFunction(mole,ErrorFile,LogFile,linea,filemolecula,moltype):
    
Lista = [] LisTag = [] if linea == 0: Modo = "a" else: Modo = "w" Modo = "a" Retorno = 0 smi ="" PrintLog(LogFile,"a","---------------","------------------------------------------------------------------------------------ ")
def PrintLog(Logfile,modo,File,texto): with open(LogFile, modo) as f: f.write(strftime("%Y-%m-%d %H:%M:%S", gmtime()) + ' : ' + File + texto + '\n')

main.py

from time import gmtime, strftime
import csv
import pickle
import os
import sys

import numpy as np
from pychem import pychem
from pychem.GeoOpt import _ReadCoordinates
from rdkit import Chem
from functions import *


proteinName = "tk"

OutFile   = os.getcwd()+'/calcProperties/out_properties_calculated/'+proteinName+'_data.csv'
OutFileTarget   = os.getcwd()+'/calcProperties/out_properties_calculated/'+proteinName+'_target.csv'
ErrorFile = os.getcwd()+'/calcProperties/out_properties_calculated/'+proteinName+'_error.txt'
LogFile   = os.getcwd()+'/calcProperties/out_properties_calculated/'+proteinName+'_log.txt'



mol = "a"
Linea = 1
filename = "mar"
moltype="aaa"


GenFunction(mol,"csv",LogFile,Linea,filename,moltype)

Y nada, al ejecutarlo el mismo error:

NameError: global name 'LogFile' is not defined
juaja

Solucionado!

Parece ser que al estar la variable LogFile en el módulo principal, se había creado automáticamente como variable global, y cuando se pasa como parámetro a una función de otro módulo hay que evitar que tenga el mismo nombre. Ha sido cambiar de nombre la variable en las 2 funciones y a funcionar. Si alguien se sabe la teoría bien, molaría que lo explicara :D

1 respuesta
C

#8 Creo que no es exactamente así. La variable 'LogFile' puede ser global y usar ese mismo nombre como argumento a una función que la enmascare. El problema es que el primer parámetro a la función 'PrintLog()' se denomina 'Logfile', que es muy diferente de 'LogFile' y en Python no se puede usar una variable que no se haya declarado antes, de ahí el problema.

Y el siguiente error que te puedes encontrar después es que en 'functions.py' estás usando la función 'strftime()' que no la va a resolver desde 'main.py', tienes que importarla en el módulo que la usas.

1 1 respuesta
juaja

#9 pero es que antes separarlo en un módulo esas funciones funcionaban, de ahí mi duda.

1 respuesta
C

#10 Cada módulo en Python usa su propia tabla de símbolos que no comparte con el resto.

Cuando tienes todo el código dentro de un mismo archivo (módulo), la variable que has definido al principio como global es accesible para todo el resto del código, y sólo se enmascara cuando usas ese mismo nombre como argumento o le asignas un nuevo valor dentro de un ámbito local (como una función).

Cuando separas el código en diferentes módulos, cada uno usa su propia tabla de símbolos. Pasar las variables globales como argumentos tal como haces es correcto, pero cuidado, porque Python crea una variable local que enmascara la global, y cualquier cambio que hagas se perderá al salir de la función (como cambiar su valor).

Tu error es que el argumento es 'Logfile' y usas 'LogFile'. Con todo el código en el mismo archivo Python recupera el 'LogFile' definido como global anteriormente (misma tabla de símbolos) pasando completamente del argumento. En cuanto cambias de módulo intenta recuperar 'LogFile' pero no lo encuentra ni en local (argumento mal escrito) ni en global (tabla de símbolos diferente).

Y misma explicación vale para el error del 'strftime()'. Lo importas en la tabla de símbolos de 'main.py' pero 'functions.py' lo buscará en su tabla de símbolos y no lo encontrará. ¡Buumm!

Así es como lo entiendo yo.

1 respuesta
juaja

#11 Creo que sí que era eso, porque justo después de corregir el error me saltó el error de strftime. Así que tuvo que ser eso, osea que me he vuelto loco por una letra minúscula xD.

Muchas Gracias por vuestro tiempo.

Usuarios habituales