파이썬 속성을 사용하면 다음과 같이 만들 수 있습니다.
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_toolsproxy_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__은 모듈 을 참조하십시오 .