2017-11-03 2 views
1

나는 walkerround를 시도하고있는 reload() (파이썬 2 내장과 importlib 모두)이라는 성가신 행동을 발견했다.어떻게 super()를 우아하고 안전하게 사용할 수 있습니까 (파이썬 모듈 재로드에 관한)?

대화 형 Python 인터프리터에서 데이터를 분석하고 있습니다. 내 코드는 자주 변경되는 모듈 (Python 2 및 3 호환)로 구성되어 있습니다.

데이터로드 시간이 길어 인터프리터를 다시 시작할 수 없으므로 모듈을 재귀 적으로 다시로드하는 것이 좋습니다.

문제는 reload() updates the code but preserves the module global scope입니다 (Python 3 importlib.reload()에도 적용됨). super()을 사용하는 방법에 해로울 것 같습니다 (무슨 일이 벌어지고 있는지 깨닫는 데 시간이 걸렸습니다).

모듈 bar.py위한 최소한의 실패 예 :

class Bar(object): 
    def __init__(self): 
     super(Bar, self).__init__() 

이다 :

>>> import bar 
>>> class Foo(bar.Bar): 
...  pass 
... 
>>> reload(bar) 
<module 'bar' from '[censored]/bar.py'> 
>>> Foo() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "[censored]/bar.py", line 3, in __init__ 
    super(Bar, self).__init__() 
TypeError: super(type, obj): obj must be an instance or subtype of type 

I 수

파이썬 2와 호환되지 이다
  1. use super() without arguments in Python 3 manner (),
  2. 포기하면 대신 Bar.__init__(self) (which is harder to maintaindiscouraged)을 호출하십시오.
  3. monkey-patch 클래스 자체에 대한 참조를 순환하는 참조를 포함하는 클래스 속성을 추가하는 클래스입니다.

내가 좋아하는 아이디어는 없습니다. 이 문제를 다루는 다른 방법이 있습니까?

+1

'__init__' 메소드가 아닌 클래스 레벨에'super (Bar, self) .__ init __()'을 넣었으므로'bar.py'는 이미 실패합니다. – user2357112

+0

'super '의 사용법은 실제로 유효하지 않습니다. 'super'는 클래스 바디가 아닌 클래스의 메소드 내에서 사용됩니다. – direprobs

+1

또한, 모듈을 새로 고침하는 것은 일반적으로 힘들어하기가 정말 쉽지 않으며,'reload'는 가장 간단한 경우 만 처리합니다. 가장 좋은 방법은 항상 파이썬을 처음부터 다시 시작하는 것입니다. – user2357112

답변

1

모듈을 다시로드하는 경우 우아하고 안전하게 수행 할 수 없기 때문에 불가능합니다. 그런 종류의 일은 옳다는 것은 까다로울까요. 그 문제는 여기에 명시되어

구체적인 방법은 Foo의 슈퍼 클래스가 여전히 이전 Bar이지만, Bar 이전의 이름으로 자신을 참조하고,이 찾고 곳 Bar 이름은 이제 네임 스페이스에 새로운 Bar을 의미한다는 것입니다 . 이전 Bar은 새 Barsuper으로 전달하려고 시도하고 있습니다.


몇 가지 옵션을 제공 할 수 있습니다. 모두 우아하지 않음안전하지 않은은 아마도 이상한 놀라움을 줄 것입니다. 결국이지만 모듈 리로드에 대해서는 사실입니다.

는 아마도 가장 쉽게 이해되지 옵션은 새로운 Bar에서 새 Foo 급 하강 얻기 위해 Foo 클래스 정의를 다시 실행하는 것입니다 Foo

reload(bar) 
class Foo(bar.Bar): 
    pass 

새로운 인스턴스가 다음 새 Bar를 사용, 그리고 것 super에서 문제가 발생하지 않습니다.이전 인스턴스는 이전 Foo과 이전 Bar을 사용합니다. __init__에 문제가 없을 것입니다. 이미 실행 되었기 때문에 다른 문제가있을 수 있습니다. 당신이 취할 수

또 다른 옵션의 슈퍼 클래스Foo업데이트하는 것입니다 그래서 Foo 이제 새 Bar에서 내려 :

reload(bar) 

Foo.__bases__ = (bar.Bar,) 

신규 및 Foo의 기존 인스턴스는 새로운 Bar을 사용합니다. Bar에서 변경 한 내용에 따라 특히 새로운 데이터가 Bar의 데이터를 변경하거나 Bar.__init__이 초기화를 수행하는 방법을 변경 한 경우 새 클래스가 이전 인스턴스와 호환되지 않을 수 있습니다.

+0

실생활 예제 모듈에서 재귀 적으로 가져 오기를 다시로드하므로 코드 차이가 발생하지 않기를 바랍니다. – abukaj

0

사운드 정말 원하는대로 들으십시오 import 모듈. 다음은 이것을 허용한다 (파이썬 2와 3 모두).

import bar 
import sys 

class Foo(bar.Bar): 
    pass 

# Manually reload module. 
_saved_reference = sys.modules['bar'] # Needed for Python 2. 
del sys.modules['bar'] 

import bar # Re-import instead of reload(). 
Foo() # No error. 
+0

무엇이'_saved_reference'입니까? – user2357112

+0

물론이 솔루션에는 이상한 놀라움이 있습니다. 'bar'와'Bar'에 대한 이전 참조는 여전히 이전 모듈과 이전 클래스를 참조하므로'Foo'는 여전히 이전 클래스를 사용하고'bar '를 가져온 다른 모듈은 여전히 ​​이전 모듈을 갖습니다 . 이 방법으로 패키지를 다시 가져 오는 것은 하위 모듈에 대한 액세스를 끊을 수도 있습니다. 파이썬을 다시 시작하지 않고도 어떤 옵션이든 이상한 놀라움을 겪을 것입니다. – user2357112

+0

@ user2357112 : 파이썬 2가하기 때문에'_saved_reference'가 필요합니다. [이 질문에 대한] 답변 (https://stackoverflow.com/questions/5365562/why-is-the-value-of-name-changing-after-assignment-to-sys-modules-name)을 참조하십시오. 그것을 논의합니다. – martineau

관련 문제