사용자 시스템의 다양한 데이터 모음과 인터페이스하기 위해 여러 가지 사용자 지정 클래스가있는 프로젝트에서 작업하고 있습니다. 이 클래스는 사용자 지향 속성으로 만 properties
입니다. 이러한 속성 중 일부는 상당한 리소스를 필요로하므로 생성 코드를 한 번만 실행하고 반환 된 값을 디스크에 저장 (즉, 캐시)하여 후속 실행에서 더 빠르게 검색 할 수 있습니다. 약자로, 이것이 내가이 달성하고 어떻게 : 나는 그것을 필요로하는디스크의 속성 사전을 자동으로 업데이트하는 클래스 데코레이터?
def stored_property(func):
"""This ``decorator`` adds on-disk functionality to the `property`
decorator. This decorator is also a Method Decorator.
Each key property of a class is stored in a settings JSON file with
a dictionary of property names and values (e.g. :class:`MyClass`
stores its properties in `my_class.json`).
"""
@property
@functools.wraps(func)
def func_wrapper(self):
print('running decorator...')
try:
var = self.properties[func.__name__]
if var:
# property already written to disk
return var
else:
# property written to disk as `null`
return func(self)
except AttributeError:
# `self.properties` does not yet exist
return func(self)
except KeyError:
# `self.properties` exists, but property is not a key
return func(self)
return func_wrapper
class MyClass(object):
def __init__(self, wf):
self.wf = wf
self.properties = self._properties()
def _properties(self):
# get name of class in underscore format
class_name = convert(self.__class__.__name__)
# this is a library used (in Alfred workflows) for interacted with data stored on disk
properties = self.wf.stored_data(class_name)
# if no file on disk, or one of the properties has a null value
if properties is None or None in properties.values():
# get names of all properties of this class
propnames = [k for (k, v) in self.__class__.__dict__.items()
if isinstance(v, property)]
properties = dict()
for prop in propnames:
# generate dictionary of property names and values
properties[prop] = getattr(self, prop)
# use the external library to save that dictionary to disk in JSON format
self.wf.store_data(class_name, properties,
serializer='json')
# return either the data read from file, or data generated in situ
return properties
#this decorator ensures that this generating code is only run if necessary
@stored_property
def only_property(self):
# some code to get data
return 'this is my property'
이 코드는 정확하게 작동하지만, 여전히 나는 현재 (이 기능이 필요 특징으로 수동으로 각 클래스에 _properties(self)
방법을 추가하는 저를 강제로, 나는 3)을 가지고있다. 내가 원하는 것은이 기능을 모든 클래스에 "삽입"하는 방법입니다. 나는 클래스 데코레이터가이 일을 끝낼 수 있다고 생각하지만, 내가 할 수도있는 것처럼 시도해 보았다. 어떻게 그 일을 처리 할지를 알 수 없다.
명확성을 위해 (그리고 내가 원하는 것을 얻기위한 데코레이터가 최선의 방법이 아닌 경우) 필자는 이후의 전반적인 기능을 설명하려고 노력할 것입니다. 몇 가지 속성이 포함 된 클래스를 작성하고 싶습니다. 이러한 속성의 값은 다양한 정도의 복잡한 코드를 통해 생성됩니다 (한 예로, 특정 앱의 기본 설정 파일을 검색 한 다음 3 가지 기본 설정 (검색 결과 중 하나는 존재할 수도 있고 존재하지 않을 수도 있음)을 검색하고 가장 우수한 단일 이러한 기본 설정의 결과). 속성 코드의 본문에 데이터 찾기 알고리즘 만 포함되기를 원합니다. 하지만 그 속성에 액세스 할 때마다 알고리즘 코드를 실행하고 싶지는 않습니다. 한 번 값을 생성하고 나면 디스크에 기록한 다음 모든 후속 호출에서이 값을 읽으 려합니다. 그러나 각 값을 자체 파일에 쓰지 않으려 고합니다. 위의 예에서 my_class.json
에 하나의 키, 값 쌍이있는 JSON 사전이 포함될 수 있도록 단일 클래스의 모든 속성에 대한 모든 값의 사전을 하나의 파일에 작성해야합니다. 속성에 직접 액세스 할 때 먼저 디스크의 사전에 이미 있는지 확인해야합니다. 그렇다면 단순히 그 값을 읽고 리턴하십시오. 존재하지만 null 값을 가진 경우 생성 코드 (즉, 속성 메소드에 실제로 작성된 코드)를 실행하고 지금 찾을 수 있는지 확인하십시오 (그렇지 않은 경우 메소드는 None
을 반환하고 다시 한번 파일에 기록). 사전이 존재하고 해당 속성이 키가 아닐 경우 (현재 코드는 실제로 가능하지 않지만 미안한 것보다 안전합니다) 생성 코드를 실행하고 키, 값 쌍을 추가하십시오. 사전이 없으면 (즉, 클래스의 첫 번째 인스턴스 생성시) 모든 속성에 대해 모든 생성 코드를 실행하고 JSON 파일을 만듭니다. 이상적으로 코드는 모든 생성 코드를 다시 실행하지 않고 (즉, _properties()
을 다시 실행하지 않고) JSON 파일에서 하나의 속성을 업데이트 할 수 있습니다.
나는 이것이 약간 특이한 것을 알고 있지만, 나는 인간의 읽을 수있는 내용과 우아한 코드를 모두 필요로한다. 나는 정말로 내 목표를 타협하지 않아도됩니다. 바라기를 원하는 것의 설명은 충분히 명확합니다. 그렇지 않다면, 내가 이해하지 못하는 것에 대한 의견을 나에게 알려 주어 명확히하려고 노력할 것입니다. 하지만 클래스 데코레이터는 아마도 어떤 클래스에 _properties()
메서드를 삽입하고 인스턴스화시 실행하고 해당 값을 클래스의 properties
특성에 매핑하여 클래스 데코레이터를 얻을 수 있다고 생각합니다.
위대한 포인트. 나는 단지'_properties()'메소드를 완전히 추상화 시켰을 뿐이며 일단 추상화하면 기본 클래스를 사용할 수 있다는 것을 깨닫지 못했습니다. 이것은 또한 클래스 장식자를 사용하는 것보다 더 깨끗하고 의사 소통이되는 것처럼 보일 것입니다. – smargh