2010-01-23 4 views
3

여러 변수로 제어해야하는 다양한 객체가 많이있는 모듈을 만들고 있습니다.모듈에 정의 된 객체와 변수를 공유하는 Pythonic 방법은 무엇입니까?

이것이 C 인 경우 개체에 변수/개체에 대한 포인터를 전달하고 응용 프로그램에서 필요에 따라 변수를 변경하게하고 모듈의 개체가 새 변수를 "보게"됩니다 값. 애플리케이션에서

class foo(object): 
    def __init__(self, varToWatch): 
    self.varToWatch = varToWatch 
    def DoSomething(self): 
    print self.varToWatch 

, bar.py : 모듈 foo.py에서

import foo 
x = "before" 
y = foo.foo(x) 
y.DoSomething() 
x = "after" 
y.DoSomething() 

이것은 물론, 작동하지 않는 때문에, X의 원래 값 (또는 레퍼런스 x의 원래 값으로)가 y에 저장됩니다. "전에" "전에"얻을.

그래서, 나는

  1. 글로벌의 이름을 전달하고, foo는의 이름으로 세계를 참조 ...보십시오. 아니요, 글로벌은 모듈이 아닌 애플리케이션의 공간에 있기 때문입니다.
  2. foo 네임 스페이스에서 global을 사용하고 있지만 변수 이름으로 해당 공간을 처리하는 방법을 모르며 foo를 가져 오는 대신 foo에서 import *를하고 있습니다. 이것을 바꾸는 것은 고통 스러울 것입니다.
  3. 모듈에서 사전을 만들고 사전에있는 키 이름을 모듈의 개체로 전달하십시오. 응용 프로그램에서 사전 내용을 조작하십시오. 기본적으로 저는 새로운 글로벌 공간을 정의하고 변수를 고집합니다. 나는 그것이 작동하지 않을 이유를 보지 못하지만, 나에게 깔끔한 느낌을 준다. 파이썬에 익숙하지 않은가?

필자가 보았던 아름다운 솔루션을 파이썬에서 쉽게 찾을 수 없어 뭔가 놓친 것 같습니다.

제안 사항?

TIA, - 팀.

+0

()에

y = test.foo('x') 

동등한 인쇄 varToWatch 인쇄 self.varToWatch – Ponkadoodle

+0

SHO '그런가되어야한다. 감사. – tbroberg

답변

3

제어 변수를 별도의 모듈 (예 : settings)에 넣고 별도의 import settings을 사용하는 것은 어떻습니까? 그런 다음 객체에 settings.barsettings.quux을 표시하고 from foo import *을 수행하면 기본 네임 스페이스가 어지럽게 정리됩니다. ;-) 또한 전역 개체를 사용하여 설정을 저장할 수 있으며 대부분 같은 효과가 있습니다.

물론 이런 문제가 있다면 import foo을 할 수있는 구조 조정이 장기적으로 도움이되지 않을지 궁금합니다. 문제를 알지 못하고 판단 할 수 없으므로 떠나겠습니다. 이 문제는 당신에게 있습니다.

+0

하지만 클래스와 응용 프로그램의 변수를 어떻게 식별합니까? 이름으로 할 경우 설정 네임 스페이스에서 해당 변수에 어떻게 도달합니까? 거기에 약간의 명백한 방법이 있지만, 나는 그것을 발견 할 수 없었다. settings.global()은 그것을하지 않습니다. – tbroberg

+3

'getattr (settings, varname)'을 사용하여 객체의 네임 스페이스에서 변수를 얻을 수 있습니다. –

+1

@tbroberg : 맥스가 말하는 것! 예를 들어,'getattr (foo, "bar")'는'foo.bar'의 값을 반환합니다.'foo'는 모듈 (또는 어떤 객체)이 될 수 있습니다. 당신은'foo import *'보다는'import foo'를 사용하여'foo'에 접근해야합니다. 따라서 이런 방식으로 액세스하고자하는 것들을위한 별도의 모듈이 가장 깨끗한 코드를 만들 수 있습니다. @ 맥스 : 코멘트 주셔서 감사합니다! –

3

트릭은 변경 가능한 유형을 사용하는 것입니다. 문자열은 변경할 수 없으므로 문자열을 변경하면 새 메모리 공간에 새 문자열 객체가 만들어집니다. 그러나 목록을 참조하고 목록에 추가하면 메모리 공간이 변경되지 않습니다. 귀하의 코드를 적용 ...

>>> class Foo(object): 
...  def __init__(self, var): 
...   self.var = var 
...  def show(self): 
...   print self.var 
... 
>>> x = ['before'] 
>>> y = Foo(x) 
>>> y.show() 
['before'] 
>>> x.append('after') 
>>> y.show() 
['before', 'after'] 
+0

네, 그게 제가 가장 잘 나온 해결책입니다 (원래 게시물의 # 3). 나는리스트 나 딕테이션에서 그것들을 모두 감싸는 것보다 질서 정연한 대답이 있기를 바랐다. 그러나 그렇지 않다면 그렇지 않다. 감사합니다. -> 인쇄 self.var ('후') [0] 및 x.append - – tbroberg

+0

나는 그것이 더 나은 것 같아요. 이것은 내가 사전 사전 아이디어로가는 곳의 일종이며, 목록도 작동합니다. 그것은 나에게 깨끗하다고 ​​느끼지는 않지만, 아마도 나는 여전히 내 C 방법에 빠져 있습니다. –

1

여기에서 C 변수는 데이터가 객체라는 점입니다. 파이썬에서 변수는 항상 객체 (데이터)에 대한 참조입니다. 변수가 아닌 객체를 쉽게 볼 수 있습니다.예를 들어, x = "after"은 실제로 객체 beforex에서 "연결 해제"하고 새 객체 ("after")를 연결합니다. 즉, xfoo.varToWatch은 더 이상 같은 개체를 참조하지 않습니다.

x이 참조하는 개체를 바꾼 경우 xvarToWatch은 여전히 ​​같은 개체를 참조하며 변경 사항이 반영됩니다. 예를 들어, x이 사전과 같이 변경 가능한 유형 인 경우 - 실제로이 지정을하지 않는 한 x을 변경하면이 경우 varToWatch에 반영됩니다.

+0

가 합의> X [0] = '후' 인쇄 self.var : – tbroberg

+1

글쎄, 나는 그것이 깨끗하지 않다는 것에 동의해야만한다. 내 게시물은 낮은 수준의 문제를 해결했습니다. 더 높은 수준에서, 나는'settings' 또는'config' 모듈을 가지고있는 Michal의 답변을 제안 할 것입니다. –

3

이름의 모든 바인딩을 다시 잡으려면 이름 공간 을 모두 전달해야합니다. dict을 네임 스페이스로 사용하는 것이 좋지만 전체 모듈 (globals()) 또는 o (특성을 관찰하고 싶은 특정 객체 (vars(o)))의 경우 dict을 사용해도됩니다.

그래서 : 당신이 글로벌 수준에있어 이후

class foo(object): 
    def __init__(self, namespace, name): 
    self.namespaceToWatch = namespace 
    self.nameToWatch = name 
    def DoSomething(self): 
    print self.namespaceToWatch[self.nameToWatch] 

하고, 귀하의 예를 들어, 사용, 알렉스 마르 텔리의 솔루션에 대한 코멘트에서

import foo 
x = "before" 
y = foo.foo(globals(), 'x') 
y.DoSomething() 
x = "after" 
y.DoSomething() 
+0

고마워, 좋은 팁, 특히 globals() 전달에 대해. 당사자가 모듈의 네임 스페이스 사용에 동의하면 어떻게됩니까? 어떻게 응용 프로그램이 모듈의 네임 스페이스를 가져올 수 있습니까? – tbroberg

+0

'globals()'**는'globals()'에 대한 호출이 어휘 적으로 상주하는 모듈의 네임 스페이스 사전입니다. (의미 상'vars (sys.modules [__ name __])'의 줄임말입니다. "호출자의 전역을 자동으로 찾는"것을 언급하고 있다면 프로덕션 코드에서 그러한 인트로 스펙 션을 사용하는 것은 좋지 않은 아이디어입니다. 어쨌든 몇 가지 SO 질문 및 답변을 논의 할 수 있습니다 (방법을 보여주고 설명하지 않는 이유 설명). 좋은 생각). Java는 이런 점에서 더 적은 옵션을 가지고 있습니다 (전역 변수가 없습니다). 따라서 다른 Q에서 어떻게 완료되었는지 묻고 싶을 수도 있습니다. –

+0

프로덕션 코드에서 인트로 스펙 션을 사용하는 것이 왜 나쁜지에 대해 설명하거나 알려주십시오. 나는'site : stackoverflow.com martelli inspect python bad'와 같은 것들의 인터넷 검색을 시도했지만 비어 있습니다. – unutbu

1

, tbroberg는 묻는다, "어떤 경우 당사자가 모듈의 네임 스페이스 사용에 동의합니까? 응용 프로그램이 모듈의 네임 스페이스를 어떻게 얻을 수 있습니까? " 내가 그렇게 namespace 지금 선택적 인수 인 인수의 순서를 변경

import inspect 
class foo(object): 
    def __init__(self, name, namespace=None): 
     self.namespaceToWatch = (namespace if namespace else 
           inspect.currentframe().f_back.f_globals) 
     self.nameToWatch = name 
    def DoSomething(self): 
     print self.namespaceToWatch[self.nameToWatch] 

참고 : 여기에

는 (기본적으로) 네임 스페이스를 설정할 수 발신자의 네임 스페이스를 할 방법이다.

inspect.currentframe()foo.__init__ 안에 현재 프레임을 반환합니다.

inspect.currentframe().f_backfoo('x')이 호출되는 이전 프레임을 반환합니다.

inspect.currentframe().f_back.f_globals은이 프레임의 전역 이름 공간을 반환합니다. 이

foo.DoSomething에서
y = test.foo('x', globals()) 
+0

와우! 그렇게 할 수 있다는 것을 알면 아주 좋습니다. 복잡성의 수준은 잘 맞은 길에서 벗어난 좋은 신호입니다. 감사! – tbroberg

관련 문제