python - eyed3
¿Por qué el valor de__name__ cambia después de la asignación a sys.modules[__ name__]? (2)
Mientras intentaba hacer algo similar a lo que se encuentra en la receta de ActiveState titulada Constantes en Python por Alex Martelli, me encontré con el efecto secundario inesperado (en Python 2.7) que asigna una instancia de clase a una entrada en sys.modules
. al hacerlo, aparentemente cambia el valor de __name__
a None
como se ilustra en el siguiente fragmento de código (que rompe parte del código en la receta):
class _test(object): pass
import sys
print ''# __name__: %r'' % __name__
# __name__: ''__main__''
sys.modules[__name__] = _test()
print ''# __name__: %r'' % __name__
# __name__: None
if __name__ == ''__main__'': # never executes...
import test
print "done"
Me gustaría entender por qué esto está sucediendo. No creo que fuera así en Python 2.6 y versiones anteriores, ya que tengo un código más antiguo donde aparentemente el if __name__ == ''__main__'':
condicional funcionó como se esperaba después de la asignación (pero ya no lo hace).
FWIW, también noté que el nombre _test
se está recuperando de un objeto de clase a None
, después de la asignación. Me parece extraño que se estén recuperando en None
lugar de desaparecer por completo ...
Actualizar:
Me gustaría agregar que cualquier solución para lograr el efecto de if __name__ == ''__main__'':
dado lo que sucede, sería muy apreciado. TIA!
Esto sucede porque ha sobrescrito su módulo cuando hizo sys.modules[__name__] = _test()
por lo que su módulo se eliminó (porque el módulo ya no tenía ninguna referencia y el contador de referencia se puso a cero, por lo que se eliminó) pero, mientras tanto, el intérprete aún tiene el código de bytes, por lo que seguirá funcionando, pero devolviendo None
a todas las variables en su módulo (esto se debe a que Python establece todas las variables en None
en un módulo cuando se elimina).
class _test(object): pass
import sys
print sys.modules[''__main__'']
# <module ''__main__'' from ''test.py''> <<< the test.py is the name of this module
sys.modules[__name__] = _test()
# Which is the same as doing sys.modules[''__main__''] = _test() but wait a
# minute isn''t sys.modules[''__main__''] was referencing to this module so
# Oops i just overwrite this module entry so this module will be deleted
# it''s like if i did:
#
# import test
# __main__ = test
# del test
# __main__ = _test()
# test will be deleted because the only reference for it was __main__ in
# that point.
print sys, __name__
# None, None
import sys # i should re import sys again.
print sys.modules[''__main__'']
# <__main__._test instance at 0x7f031fcb5488> <<< my new module reference.
EDITAR:
Una solución será haciendo esto:
class _test(object): pass
import sys
ref = sys.modules[__name__] # Create another reference of this module.
sys.modules[__name__] = _test() # Now when it''s overwritten it will not be
# deleted because a reference to it still
# exists.
print __name__, _test
# __main__ <class ''__main__._test''>
Espero que esto explique las cosas.
Si asigno algo a sys.modules[''__main__'']
obtengo un entorno muy dañado. No es este comportamiento exacto, pero todos mis globales y elementos desaparecen.
no se ha documentado que sys.modules
se comporte de ninguna manera en particular cuando se escribe, solo vagamente que puede usarlo para "recargar trucos" (y hay algunas trampas importantes incluso para ese uso).
No le escribiría un no-módulo y no esperaría más que dolor. Creo que esta receta está totalmente equivocada.