모듈이 개체가 할 수 있는 것과 동일한 속성을 가질 수 있습니까?
파이썬 속성을 이용하면 다음과 같이 만들 수 있습니다.
obj.y
값만 반환하는 것이 아니라 함수를 호출합니다.
모듈로 이것을 할 수 있는 방법이 있습니까?제가 원하는 케이스가 있습니다.
module.y
단순히 저장된 값을 반환하는 것이 아니라 함수를 호출합니다.
PEP 562가 Python >= 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
.
편집
내 대답에는 세터와 삭제자가 있을 수 없습니다.필요하다면 kxr의 답변을 받아들이세요.
하위 클래스 만들기<class 'module'>
, 해당 클래스에서 속성을 정의한 다음 모듈 클래스를 해당 클래스로 변경합니다.
파일: mymodule.py
import sys
class This(sys.__class__): # sys.__class__ is <class 'module'>
_y = 3
@property
def y(self): # do the property things in this class
return self._y
@y.setter
def y(self, value): # setter is also OK
self._y = value
other = 4
sys.modules[__name__].__class__ = This # change module class into This
데모:
>>> import mymodule
>>> mymodule.y
3
>>> mymodule.other
4
>>> mymodule.y = 5
>>> mymodule.y
5
>>> mymodule._y
5 # to prove that setter works
저는 너무 초보자라서 왜 작동하는지 알 수가 없습니다.그래서 크레딧은 kxr로 가야 합니다.
새 스타일 클래스의 인스턴스만 속성을 가질 수 있습니다.Python이 이러한 인스턴스를 모듈이라고 믿게 할 수 있습니다.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()
모듈의 모든 속성을 올바르게 상속하고 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
존 린의 답변을 토대로:
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는 속성이 존재하는지 알 수 없으며 빨간색 물결 모양을 표시합니다.
파이썬 3 업데이트
파이썬 3에서는 적어도 3.7 이후로 모듈 클래스를 서브 클래스로 변경할 수 있으므로 실제 모듈 속성(또는 디스크립터)을 구현하기 쉽습니다. PEP 562 모듈보다 견고하고 강력합니다.__getattr__
.
# mymodule.py
class ThisMod(sys.modules[__name__].__class__):
y = property(lambda self: "Hi this is module %s." % __name__)
const = property(lambda self: _const) # block setting
sys.modules[__name__].__class__ = ThisMod
_const = 77
# rest of module code ...
파이썬 2 호환
전형적인 사용 사례는 모든 모듈 내용을 클래스 레이아웃으로 전환하지 않고 기존 모듈을 몇 가지(몇 가지) 동적 특성으로 강화하는 것입니다.안타깝게도 가장 간단한 모듈 클래스 패치는 다음과 같습니다.sys.modules[__name__].__class__ = MyPropertyModule
실패로 돌아가다TypeError: __class__ assignment: only for heap types
. 따라서 모듈 제작은 재배선이 필요합니다.
이 접근 방식은 Python Import Hook 없이도 모듈 코드 위에 프롤로그를 몇 가지만 올려도 가능합니다.
# 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
패키지가 제공을 시도합니다.@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
class. "module property"를 설정하는 것은 이 클래스의 인스턴스에 속성을 설정하는 것과 같습니다.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
사용자 2124834의 답변을 토대로:
import sys
class AttrGeter:
def __new__(cls, gt):
if isinstance(gt, cls):
return gt
else:
o = super().__new__(cls)
o.oldgetattr = gt
o.funcmap = {}
return o
def __call__(self, name):
name2 = "_" + name
if name2 in self.funcmap:
return self.funcmap[name2]()
else:
return self.oldgetattr(name)
def add(self, func):
self.funcmap[func.__name__] = func
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}'")
ag = AttrGeter(getattr(module, '__getattr__', base_getattr))
module.__getattr__ = ag
ag.add(func)
return func
_module에서 사용(앞줄 밑줄 참조).py:
@module_property
def _thing():
return 'hello'
그러면:
import the_module
print(the_module.thing) # prints 'hello'
나는 a를 사용합니다.dict
d function
원액으로 번 이 더 일 수 .하나의 모듈에서 데코레이터를 여러 번 사용하면 더 효율적일 수 있습니다.
구글은 장식가 한 쌍을 제공한 이 요지로 나를 이끌었습니다.mod_property
,cached_mod_property
간단한 구현이 가능합니다.제가 시도해봤는데 저를 위해 일을 해주더라고요.
저는 그 요지에서 코드를 가져왔고, 일부 코드는 디킨스에서 가져왔고, 여기서 완전한 데모와 함께 하나의 유틸리티 모듈로 결합했습니다.
매니페스트:
- 캐시(함수)
- cashed_property(예: 메서드)
- 모듈_
- 캐시된_module_
- 계급_
- 캐시된_클래스_
언급URL : https://stackoverflow.com/questions/880530/can-modules-have-properties-the-same-way-that-objects-can
'programing' 카테고리의 다른 글
안드로이드 스튜디오의 외부 라이브러리에 항아리를 추가하는 방법은? (0) | 2023.10.07 |
---|---|
다른 스키마에서 두 개의 테이블 쿼리 (0) | 2023.10.07 |
여러 테이블에서 하나의 쿼리에 여러 개의 완전한 조인 (0) | 2023.10.07 |
Null이거나 JavaScript에서 정의되지 않은 경우 값 바꾸기 (0) | 2023.10.07 |
두 열의 좌측 외측 접합 성능 문제 (0) | 2023.10.07 |