목표는 DB 결과 집합처럼 동작하는 모의 클래스를 만드는 것입니다.
예를 들어 dict 표현식을 사용하여 데이터베이스 쿼리가 반환 {'ab':100, 'cd':200}
되면 다음을보고 싶습니다.
>>> dummy.ab
100
처음에는 이런 식으로 할 수 있다고 생각했습니다.
ks = ['ab', 'cd']
vs = [12, 34]
class C(dict):
def __init__(self, ks, vs):
for i, k in enumerate(ks):
self[k] = vs[i]
setattr(self, k, property(lambda x: vs[i], self.fn_readyonly))
def fn_readonly(self, v)
raise "It is ready only"
if __name__ == "__main__":
c = C(ks, vs)
print c.ab
그러나 c.ab
대신 속성 객체를 반환합니다.
setattr
라인을 교체하는 k = property(lambda x: vs[i])
것은 전혀 쓸모 가 없습니다.
런타임에 인스턴스 속성을 만드는 올바른 방법은 무엇입니까?
추신 : 나는 방법이 어떻게 사용됩니까?에 제시된 대안을 알고 있습니다 .__getattribute__
답변
나는이 대답을 확장해야한다고 생각합니다. 이제 나이가 많고 현명하고 진행 상황을 알고 있습니다. 안하는 것보다 늦게하는 것이 낫다.
당신은 할 수 클래스 동적에 속성을 추가 할 수 있습니다. 그러나 그것은 캐치입니다. 클래스 에 추가해야합니다 .
>>> class Foo(object):
... pass
...
>>> foo = Foo()
>>> foo.a = 3
>>> Foo.b = property(lambda self: self.a + 1)
>>> foo.b
4
A property
는 실제로 descriptor 라고하는 것의 간단한 구현입니다 . 주어진 클래스에서 주어진 속성에 대한 사용자 정의 처리를 제공하는 객체입니다 . 큰 if
나무를 제거 하는 방법을 좋아합니다 __getattribute__
.
내가 부탁하면 foo.b
위의 예에서, 파이썬은 있다고 본다 b
클래스 구현에 정의 된 기술자 프로토콜 단지가와 객체의 의미 – 어떤 __get__
, __set__
또는 __delete__
방법을. 설명자는 해당 속성을 처리 할 책임이 있다고 주장하므로 Python은 호출 Foo.b.__get__(foo, Foo)
하고 반환 값은 속성 값으로 다시 전달됩니다. 의 경우 property
, 이러한 각각의 방법은 바로 호출 fget
, fset
또는 fdel
당신은 전달 property
생성자입니다.
설명자는 실제로 전체 OO 구현의 배관을 노출시키는 Python의 방법입니다. 사실,보다 일반적인 다른 유형의 설명자가 property
있습니다.
>>> class Foo(object):
... def bar(self):
... pass
...
>>> Foo().bar
<bound method Foo.bar of <__main__.Foo object at 0x7f2a439d5dd0>>
>>> Foo().bar.__get__
<method-wrapper '__get__' of instancemethod object at 0x7f2a43a8a5a0>
겸손한 방법은 또 다른 종류의 설명자입니다. 그 __get__
첫 번째 인수로 호출 인스턴스 침; 사실상, 이렇게합니다 :
def __get__(self, instance, owner):
return functools.partial(self.function, instance)
어쨌든, 이것이 디스크립터가 클래스에서만 작동하는 이유라고 생각합니다. 그것들은 규칙에 대한 예외이기도합니다 type
. 분명히 기술자를 클래스에 할당 할 수 있으며 클래스 자체는 인스턴스입니다 ! 실제로, Foo.b
여전히 전화 를 읽으려고 노력 property.__get__
; 클래스 속성으로 액세스 할 때 설명자가 자신을 반환하는 것은 관용적입니다.
거의 모든 파이썬의 OO 시스템이 파이썬으로 표현 될 수 있다는 것은 멋진 일이라고 생각합니다. 🙂
아, 그리고 당신이 관심이 있다면 한동안 설명자 에 관한 간단한 블로그 게시물을 썼습니다 .
답변
목표는 DB 결과 집합처럼 동작하는 모의 클래스를 만드는 것입니다.
그래서 당신이 원하는 것은 a [ ‘b’]를 ab로 철자 할 수있는 사전입니까?
쉽습니다.
class atdict(dict):
__getattr__= dict.__getitem__
__setattr__= dict.__setitem__
__delattr__= dict.__delitem__
답변
namedtuple
필드의 전체 목록을 미리 알고 있기 때문에이 문제를 훨씬 더 간단하게 해결할 수있는 것 같습니다 .
from collections import namedtuple
Foo = namedtuple('Foo', ['bar', 'quux'])
foo = Foo(bar=13, quux=74)
print foo.bar, foo.quux
foo2 = Foo() # error
자신 만의 세터를 작성해야하는 경우 클래스 수준에서 메타 프로그래밍을 수행해야합니다. property()
인스턴스에서는 작동하지 않습니다.
답변
이를 위해 속성을 사용할 필요는 없습니다. __setattr__
읽기 전용으로 재정의하십시오 .
class C(object):
def __init__(self, keys, values):
for (key, value) in zip(keys, values):
self.__dict__[key] = value
def __setattr__(self, name, value):
raise Exception("It is read only!")
타다
>>> c = C('abc', [1,2,3])
>>> c.a
1
>>> c.b
2
>>> c.c
3
>>> c.d
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'C' object has no attribute 'd'
>>> c.d = 42
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in __setattr__
Exception: It is read only!
>>> c.a = 'blah'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in __setattr__
Exception: It is read only!
답변
파이썬 클래스에 동적으로 속성을 추가하는 방법은 무엇입니까?
속성을 추가하려는 객체가 있다고 가정하십시오. 일반적으로 일관된 API를 유지할 수 있도록 다운 스트림 사용 코드의 속성에 대한 액세스 관리를 시작해야 할 때 속성을 사용하고 싶습니다. 이제는 일반적으로 객체가 정의 된 소스 코드에 추가하지만 액세스 권한이 없거나 프로그래밍 방식으로 함수를 동적으로 선택해야한다고 가정 해 보겠습니다.
수업 만들기
에 대한 문서를property
기반으로 한 예제를 사용하여 “hidden”속성을 가진 객체 클래스를 만들고 인스턴스를 만들어 봅시다.
class C(object):
'''basic class'''
_x = None
o = C()
파이썬에서는 일을하는 확실한 방법이있을 것으로 기대합니다. 그러나이 경우 데코레이터 표기법과없는 두 가지 방법을 보여 드리겠습니다. 먼저 데코레이터 표기법이 없습니다. 게터, 세터 또는 삭제 기의 동적 할당에 더 유용 할 수 있습니다.
동적 (일명 원숭이 패치)
우리 수업을 위해 몇 가지를 만들어 봅시다 :
def getx(self):
return self._x
def setx(self, value):
self._x = value
def delx(self):
del self._x
이제 우리는 이것을 속성에 할당합니다. 동적 질문에 답하면서 프로그래밍 방식으로 함수를 선택할 수 있습니다.
C.x = property(getx, setx, delx, "I'm the 'x' property.")
그리고 사용법 :
>>> o.x = 'foo'
>>> o.x
'foo'
>>> del o.x
>>> print(o.x)
None
>>> help(C.x)
Help on property:
I'm the 'x' property.
데코레이터
우리는 데코레이터 표기법으로 위에서했던 것처럼 똑같이 할 수 있지만이 경우 메서드 이름을 모두 같은 이름으로 지정 해야 하며 속성과 동일하게 유지하는 것이 좋습니다. 그래서 프로그래밍 방식의 할당은 그리 간단하지 않습니다. 위의 방법을 사용하고 있습니다 :
@property
def x(self):
'''I'm the 'x' property.'''
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
그리고 프로비저닝 된 setter 및 deleter가있는 특성 오브젝트를 클래스에 지정하십시오.
C.x = x
그리고 사용법 :
>>> help(C.x)
Help on property:
I'm the 'x' property.
>>> o.x
>>> o.x = 'foo'
>>> o.x
'foo'
>>> del o.x
>>> print(o.x)
None
답변
이 스택 오버플로 게시물에 비슷한 질문을 하여 간단한 유형을 만든 클래스 팩토리를 만들었습니다. 결과는 클래스 팩토리의 작동 버전이있는 이 답변 이었습니다 . 다음은 답변의 스 니펫입니다.
def Struct(*args, **kwargs):
def init(self, *iargs, **ikwargs):
for k,v in kwargs.items():
setattr(self, k, v)
for i in range(len(iargs)):
setattr(self, args[i], iargs[i])
for k,v in ikwargs.items():
setattr(self, k, v)
name = kwargs.pop("name", "MyStruct")
kwargs.update(dict((k, None) for k in args))
return type(name, (object,), {'__init__': init, '__slots__': kwargs.keys()})
>>> Person = Struct('fname', 'age')
>>> person1 = Person('Kevin', 25)
>>> person2 = Person(age=42, fname='Terry')
>>> person1.age += 10
>>> person2.age -= 10
>>> person1.fname, person1.age, person2.fname, person2.age
('Kevin', 35, 'Terry', 32)
>>>
이 변형을 사용하여 목표 인 기본값을 만들 수 있습니다 (이 질문 에이 문제를 해결하는 답변도 있습니다).
답변
질문을 완전히 이해했는지 확실하지 않지만 런타임에 내장 __dict__
클래스를 사용하여 인스턴스 속성을 수정할 수 있습니다 .
class C(object):
def __init__(self, ks, vs):
self.__dict__ = dict(zip(ks, vs))
if __name__ == "__main__":
ks = ['ab', 'cd']
vs = [12, 34]
c = C(ks, vs)
print(c.ab) # 12