Python: recarregar o componente Y importado com 'de X import Y'?

91

No Python, depois de importar um módulo X em uma sessão de intérprete usando import X, e as mudanças do módulo na parte externa, posso recarregar o módulo com reload(X). As alterações ficam disponíveis na minha sessão de intérprete.

Estou me perguntando se isso também é possível quando importo um componente Y do módulo X usando from X import Y.

A instrução reload Ynão funciona, pois Y não é um módulo em si, mas apenas um componente (neste caso, uma classe) dentro de um módulo.

É possível recarregar componentes individuais de um módulo sem sair da sessão do intérprete (ou importar o módulo inteiro)?

EDITAR:

Para esclarecimento, a questão é sobre como importar uma classe ou função Y de um módulo X e recarregar em uma mudança, não um módulo Y de um pacote X.

cschol
fonte
Acredito que haja uma contradição nessa questão: " ... possible ... import a component Y from module X" vs " question is ... importing a class or function X from a module Y". Estou adicionando uma edição para esse efeito.
Catskul
parece que a resposta marcada não responde realmente à pergunta, acredito que a minha sim. Você pode atualizar / comentar?
Catskul

Respostas:

49

Se Y for um módulo (e X um pacote) reload(Y)estará bem - caso contrário, você verá porque bons guias de estilo Python (como o do meu empregador) dizem para nunca importar nada, exceto um módulo (este é um dos muitos grandes motivos - mas as pessoas ainda manter a importação de funções e classes diretamente, não importa o quanto eu explico que é não uma boa ideia ;-).

Alex Martelli
fonte
1
Eu vejo seu ponto. Você se importaria de explicar qualquer uma das outras boas razões pelas quais não é uma boa ideia?
cschol
6
@cschol: Zen do Python, último verso ( import thisdo prompt interativo para ver o Zen do Python); e todas as razões pelas quais os namespaces são uma ótima ideia (pistas visuais locais imediatas de que o nome está sendo pesquisado, facilidade de simulação / injeção em testes, capacidade de recarregar, capacidade de um módulo mudar de maneira flexível redefinindo algumas entradas, previsível e controlável comportamento na serialização e recuperação de seus dados [[por exemplo, por decapagem e retirada da separação]] e assim por diante - um comentário SO dificilmente é longo o suficiente para fazer justiça a este argumento longo e rico !!! -)
Alex Martelli
4
observe que no Python 3, reload não está mais no namespace padrão, mas foi movido para o importlibpacote. importlib.reload(Y) docs.python.org/3.4/library/… veja também stackoverflow.com/questions/961162/…
voa em
4
@ThorSummoner, absolutamente não - significa "sempre importe MÓDULOS", então "from my.package import mymodule" é absolutamente bom e de fato preferido - apenas, nunca importe classes, funções, etc - sempre, apenas, nunca módulos .
Alex Martelli
2
Votar negativamente. Por quê? Esta não é a resposta certa. A resposta certa foi dada por Catskul em 30 de julho de 12 às 15h04.
meh
102

Responda

Em meus testes, a resposta marcada, o que sugere um simples reload(X), não funciona.

Pelo que posso dizer, a resposta correta é:

from importlib import reload # python 2.7 does not require this
import X
reload( X )
from X import Y

Teste

Meu teste foi o seguinte (Python 2.6.5 + bpython 0.9.5.2)

X.py:

def Y():
    print "Test 1"

bpython:

>>> from X import Y
>>> print Y()
Test 1
>>> # Edit X.py to say "Test 2"
>>> print Y()
Test 1
>>> reload( X )  # doesn't work because X not imported yet
Traceback (most recent call last):
  File "<input>", line 1, in <module>
NameError: name 'X' is not defined
>>> import X
>>> print Y()
Test 1
>>> print X.Y()
Test 1
>>> reload( X ) # No effect on previous "from" statements
>>> print Y()
Test 1
>>> print X.Y() # first one that indicates refresh
Test 2
>>> from X import Y
>>> print Y()
Test 2 
>>> # Finally get what we were after
Catskul
fonte
1
Uau. Eu achei isso muito útil. Obrigado! Eu uso isso como um forro agora: import X; recarregar (X); de X import Y
otterb
1
Esta é uma resposta melhor do que a aceita. É justo avisar as pessoas, mas o caso de uso de cada um é diferente. Em alguns casos, é realmente útil recarregar uma classe, por exemplo, quando você está usando o console Python e deseja carregar alterações em seu código sem perder sua sessão.
nicb de
Isso não parece funcionar sempre. Eu tenho um módulo Fooque tem um __init__.pyque busca um submódulo ... Vou postar uma resposta como contra-exemplo.
Jason S,
Python 3 one liner agora: import importlib; import X; importlib.reload (X); de X import Y
Wayne
12
from modulename import func

import importlib, sys
importlib.reload(sys.modules['modulename'])
from modulename import func
Mirek
fonte
Esta é a melhor maneira de fazer isso, porque você pode não se lembrar exatamente como foi importado
portforwardpodcast
Essa é a única solução que funciona para a questão original e tem poucos votos!
CharlesB
1
em python 3 add: from importlib import reload
mirek
7

Em primeiro lugar, você não deve usar reload de forma alguma, se puder evitá-lo. Mas vamos supor que você tenha seus motivos (ou seja, depuração dentro do IDLE).

Recarregar a biblioteca não levará os nomes de volta ao namespace do módulo. Para fazer isso, basta reatribuir as variáveis:

f = open('zoo.py', 'w')
f.write("snakes = ['viper','anaconda']\n")
f.close()

from zoo import snakes
print snakes

f = open('zoo.py', 'w')
f.write("snakes = ['black-adder','boa constrictor']\n")
f.close()

import zoo
reload(zoo)
snakes = zoo.snakes # the variable 'snakes' is now reloaded

print snakes

Você poderia fazer isso de algumas outras maneiras. Você poderia automatizar o processo pesquisando no namespace local e reatribuindo qualquer coisa que fosse do módulo em questão, mas acho que estamos sendo malvados o suficiente.

meloso
fonte
4

Se você quiser fazer isso:

from mymodule import myobject

Em vez disso:

import mymodule
myobject=mymodule.myobject

Agora você pode usar myobject da mesma maneira que estava planejando (sem as cansativas referências ilegíveis de mymodule em todos os lugares).

Se você está trabalhando interativamente e deseja recarregar myobject de mymodule, agora você pode usar:

reload(mymodule)
myobject=mymodule.myobject
Chris Fryer
fonte
2

presumindo que você usou from X import Y, você tem duas opções:

reload(sys.modules['X'])
reload(sys.modules[__name__]) # or explicitly name your module

ou

Y=reload(sys.modules['X']).Y

algumas considerações:

A. se o escopo de importação não for de todo o módulo (por exemplo: importar em uma função) - você deve usar a segunda versão.

B. se Y é importado para X de outro módulo (Z) - você deve recarregar Z, recarregar X e recarregar seu módulo, mesmo recarregando todos os seus módulos (por exemplo, usando [ reload(mod) for mod in sys.modules.values() if type(mod) == type(sys) ]) pode recarregar X antes de recarregar Z - e então não atualize o valor de Y.

Ohad Cohen
fonte
1
  1. reload()módulo X,
  2. reload()módulo importando Yde X.

Observe que o recarregamento não altera os objetos já criados vinculados a outros namespaces (mesmo se você seguir o guia de estilo de Alex).

Denis Otkidach
fonte
1

Se você estiver trabalhando em um ambiente jupyter, e você já tem from module import functionpode usar a função mágica, autoreloadpor

%load_ext autoreload
%autoreload
from module import function

A introdução do autoreloadem IPython é fornecida aqui .

Yanqi Huang
fonte
0

Só para acompanhar AlexMartelli do e do Catskul respostas, existem alguns casos muito simples, mas desagradáveis que aparecem para confundirreload , pelo menos em Python 2.

Suponha que eu tenha a seguinte árvore de origem:

- foo
  - __init__.py
  - bar.py

com o seguinte conteúdo:

init.py:

from bar import Bar, Quux

bar.py:

print "Loading bar"

class Bar(object):
  @property
  def x(self):
     return 42

class Quux(Bar):
  object_count = 0
  def __init__(self):
     self.count = self.object_count
     self.__class__.object_count += 1
  @property
  def x(self):
     return super(Quux,self).x + 1
  def __repr__(self):
     return 'Quux[%d, x=%d]' % (self.count, self.x)

Isso funciona bem sem usar reload:

>>> from foo import Quux
Loading bar
>>> Quux()
Quux[0, x=43]
>>> Quux()
Quux[1, x=43]
>>> Quux()
Quux[2, x=43]

Mas tente recarregar e não terá efeito ou corromperá as coisas:

>>> import foo
Loading bar
>>> from foo import Quux
>>> Quux()
Quux[0, x=43]
>>> Quux()
Quux[1, x=43]
>>> reload(foo)
<module 'foo' from 'foo\__init__.pyc'>
>>> Quux()
Quux[2, x=43]
>>> from foo import Quux
>>> Quux()
Quux[3, x=43]
>>> reload(foo.bar)
Loading bar
<module 'foo.bar' from 'foo\bar.pyc'>
>>> Quux()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "foo\bar.py", line 17, in __repr__
    return 'Quux[%d, x=%d]' % (self.count, self.x)
  File "foo\bar.py", line 15, in x
    return super(Quux,self).x + 1
TypeError: super(type, obj): obj must be an instance or subtype of type
>>> Quux().count
5
>>> Quux().count
6
>>> Quux = foo.bar.Quux
>>> Quux()
Quux[0, x=43]
>>> foo.Quux()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "foo\bar.py", line 17, in __repr__
    return 'Quux[%d, x=%d]' % (self.count, self.x)
  File "foo\bar.py", line 15, in x
    return super(Quux,self).x + 1
TypeError: super(type, obj): obj must be an instance or subtype of type
>>> foo.Quux().count
8

A única maneira de garantir que o barsubmódulo fosse recarregado era reload(foo.bar); a única maneira de acessar a Quuxclasse recarregada é alcançá-la e pegá-la do submódulo recarregado; mas o foopróprio módulo manteve o Quuxobjeto de classe original , presumivelmente porque ele usa from bar import Bar, Quux(ao invés de import barseguido por Quux = bar.Quux); além disso, a Quuxclasse saiu de sincronia consigo mesma, o que é simplesmente bizarro.

Jason S
fonte