파이썬 속성을 사용하면 다음과 같이 만들 수 있습니다.
obj.y
값을 반환하는 대신 함수를 호출합니다.
모듈로이를 수행하는 방법이 있습니까? 내가 원하는 케이스가 있어요
module.y
거기에 저장된 값을 반환하는 대신 함수를 호출합니다.
답변:
새 스타일 클래스의 인스턴스 만 속성을 가질 수 있습니다. 그런 인스턴스를 sys.modules[thename] = theinstance
. 예를 들어 m.py 모듈 파일은 다음과 같을 수 있습니다.
import sys
class _M(object):
def __init__(self):
self.c = 0
def afunction(self):
self.c += 1
return self.c
y = property(afunction)
sys.modules[__name__] = _M()
types.ModuleType
의 다른 매우 유사한 답변에서 볼 수 있듯이 인스턴스의 클래스를 파생시키는 데 특별한 이점이 있습니까?
builtins.module
. 즉, 자체가 인스턴스 type
(새 스타일 클래스의 정의) 인의 인스턴스입니다 . 문제는 속성이 클래스 인스턴스가 아니라에 있어야한다는 것입니다 : 당신이 할 경우 f = Foo()
, f.some_property = property(...)
당신은 순진하게도 모듈에 넣어 경우와 같은 방법으로 실패 할 수 있습니다. 해결책은 그것을 클래스에 넣는 것이지만 모든 모듈이 속성을 갖기를 원하지 않기 때문에 하위 클래스를 만듭니다 (Unknown의 답변 참조).
globals()
을 다시 None
바인딩 할 때 ( 키는 그대로 유지하지만 값을로 재설정하는 ) 변경 sys.modules
은 Python 2 문제입니다 .Python 3.4는 의도 한대로 작동합니다. Py2의 클래스 객체에 액세스해야하는 경우 예를 들어 명령문 _M._cls = _M
바로 뒤에 추가 하고 class
(또는 다른 네임 스페이스에 동등하게 숨겨 둡니다)이를 self._cls
요구하는 메서드에서 와 같이 액세스 합니다 (의 type(self)
서브 클래 싱도 수행하는 경우 괜찮을 수 있지만 _M
). .
모듈의 모든 속성을 올바르게 상속하고 isinstance ()로 올바르게 식별하기 위해 이렇게합니다.
import types
class MyModule(types.ModuleType):
@property
def y(self):
return 5
>>> a=MyModule("test")
>>> a
<module 'test' (built-in)>
>>> a.y
5
그런 다음 이것을 sys.modules에 삽입 할 수 있습니다.
sys.modules[__name__] = MyModule(__name__) # remember to instantiate the class
__file__
수동으로 정의해야하는 다른 속성도 예상 할 수 있습니다. (2) 클래스를 포함하는 모듈에서 만든 가져 오기는 런타임 중에 "보이지"않는 등 ...
types.ModuleType
, 어떤 (새로운 스타일의) 클래스가 할 것입니다. 상속하려는 특수 모듈 속성은 정확히 무엇입니까?
__init__
, 인스턴스 일 때 모듈 이름을 지정할 수 있으며 , isinstance
.
으로 PEP (562)는 파이썬으로 구현되었습니다> = 3.7, 이제 우리는이 작업을 수행 할 수 있습니다
파일 : module.py
def __getattr__(name):
if name == 'y':
return 3
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
other = 4
용법:
>>> import module
>>> module.y
3
>>> module.other
4
>>> module.nosuch
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "module.py", line 4, in __getattr__
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
AttributeError: module 'module' has no attribute 'nosuch'
당신이를 생략하면 참고 raise AttributeError
에 __getattr__
기능, 그것은을 가진 함수 끝을 의미 return None
, 그 다음이 module.nosuch
값을 얻을 것이다 None
.
을 바탕으로 존 린의 대답 :
def module_property(func):
"""Decorator to turn module functions into properties.
Function names must be prefixed with an underscore."""
module = sys.modules[func.__module__]
def base_getattr(name):
raise AttributeError(
f"module '{module.__name__}' has no attribute '{name}'")
old_getattr = getattr(module, '__getattr__', base_getattr)
def new_getattr(name):
if f'_{name}' == func.__name__:
return func()
else:
return old_getattr(name)
module.__getattr__ = new_getattr
return func
사용 (선도 밑줄 주)에서 the_module.py
:
@module_property
def _thing():
return 'hello'
그때:
import the_module
print(the_module.thing) # prints 'hello'
속성 화 된 함수를 원래 함수와 구별하려면 선행 밑줄이 필요합니다. 데코레이터가 실행되는 동안 식별자가 아직 할당되지 않았기 때문에 식별자를 다시 할당하는 방법을 생각할 수 없었습니다.
IDE는 속성이 존재하는지 알지 못하며 빨간색 wavie를 표시합니다.
@property def x(self): return self._x
이라고 생각 def thing()
합니다. 그리고 대답에 "모듈 속성 설정자"데코레이터를 만들 수 있습니까?
def thing()
제안 을 구현하려고 시도했습니다 . 문제는 누락 된 속성에__getattr__
대해서만 호출 된다는 것 입니다. 그러나 @module_property def thing(): …
실행 후에 the_module.thing
는 정의되므로 getattr 이 호출되지 않습니다. thing
데코레이터 에 어떻게 든 등록한 다음 모듈의 네임 스페이스에서 삭제해야합니다. 나는 돌아 시도 None
데코레이터에서,하지만 다음 thing
과 같이 정의된다 None
. 하나는 할 수 @module_property def thing(): … del thing
있지만 thing()
함수로 사용 하는 것보다 더 나쁘다는 것을 알았습니다
__getattribute__
좋습니다. "모듈 속성 설정자"나 "모듈 "이 없습니다. 감사합니다.
일반적인 사용 사례는 다음과 같습니다. 모든 모듈 항목을 클래스 레이아웃으로 전환하지 않고 일부 (몇 가지) 동적 속성을 사용하여 기존 모듈을 풍부하게합니다. 불행히도 가장 간단한 모듈 클래스 패치 sys.modules[__name__].__class__ = MyPropertyModule
는 TypeError: __class__ assignment: only for heap types
. 따라서 모듈 생성을 다시 연결해야합니다.
이 접근 방식은 모듈 코드 위에 프롤로그를 추가하여 Python 가져 오기 후크없이 수행합니다.
# propertymodule.py
""" Module property example """
if '__orgmod__' not in globals():
# constant prolog for having module properties / supports reload()
print "PropertyModule stub execution", __name__
import sys, types
class PropertyModule(types.ModuleType):
def __str__(self):
return "<PropertyModule %r from %r>" % (self.__name__, self.__file__)
modnew = PropertyModule(__name__, __doc__)
modnew.__modclass__ = PropertyModule
modnew.__file__ = __file__
modnew.__orgmod__ = sys.modules[__name__]
sys.modules[__name__] = modnew
exec sys._getframe().f_code in modnew.__dict__
else:
# normal module code (usually vast) ..
print "regular module execution"
a = 7
def get_dynval(module):
return "property function returns %s in module %r" % (a * 4, module.__name__)
__modclass__.dynval = property(get_dynval)
용법:
>>> import propertymodule
PropertyModule stub execution propertymodule
regular module execution
>>> propertymodule.dynval
"property function returns 28 in module 'propertymodule'"
>>> reload(propertymodule) # AFTER EDITS
regular module execution
<module 'propertymodule' from 'propertymodule.pyc'>
>>> propertymodule.dynval
"property function returns 36 in module 'propertymodule'"
참고 : 다음과 같은 from propertymodule import dynval
것은 물론 고정 된 사본을 생성합니다.dynval = someobject.dynval
proxy_tools
proxy_tools
패키지를 제공하려고 노력하고 @module_property
기능을.
다음과 함께 설치됩니다.
pip install proxy_tools
에, Marein의 예 @의 약간의 수정을 사용하여 the_module.py
우리가 넣어
from proxy_tools import module_property
@module_property
def thing():
print(". ", end='') # Prints ". " on each invocation
return 'hello'
이제 다른 스크립트에서 할 수 있습니다.
import the_module
print(the_module.thing)
# . hello
이 솔루션에는 경고가 없습니다. 즉, 문자열the_module.thing
이 아닙니다 ! proxy_tools.Proxy
문자열을 모방하도록 특수 메서드가 재정 의 된 개체입니다. 요점을 설명하는 몇 가지 기본 테스트는 다음과 같습니다.
res = the_module.thing
# [No output!!! Evaluation doesn't occur yet.]
print(type(res))
# <class 'proxy_tools.Proxy'>
print(isinstance(res, str))
# False
print(res)
# . hello
print(res + " there")
# . hello there
print(isinstance(res + "", str))
# . True
print(res.split('e'))
# . ['h', 'llo']
내부적으로 원래 함수는 다음에 저장됩니다 the_module.thing._Proxy__local
.
print(res._Proxy__local)
# <function thing at 0x7f729c3bf680>
솔직히, 모듈에이 기능이 내장되어 있지 않은 이유에 대해 당황 스럽습니다. 문제의 핵심은 그것이 클래스 the_module
의 인스턴스 라고 생각합니다 types.ModuleType
. "모듈 속성"을 설정하는 것은 클래스 자체가 아니라이 클래스 의 인스턴스 에 속성을 설정하는 것과 같습니다 types.ModuleType
. 자세한 내용은 이 답변을 참조하십시오 .
types.ModuleType
결과가 좋지는 않지만 실제로 다음과 같이 속성을 구현할 수 있습니다 . 내장 유형을 직접 수정할 수는 없지만 저주 할 수는 있습니다.
# python -m pip install forbiddenfruit
from forbiddenfruit import curse
from types import ModuleType
# curse has the same signature as setattr.
curse(ModuleType, "thing2", property(lambda module: f'hi from {module.__name__}'))
이것은 우리에게 모든 모듈에 존재하는 속성을 제공합니다. 모든 모듈에서 설정 동작을 깨기 때문에 약간 다루기 어렵습니다.
import sys
print(sys.thing2)
# hi from sys
sys.thing2 = 5
# AttributeError: can't set attribute
cached_module_property
사실 __getattr__()
이 도움이됩니다. ( functools.cached_property
수행하는 것과 유사 ).
__getattr__
은 모듈 을 참조하십시오 .