2013-03-08 7 views
1

클래스의 속성을 동적으로 업데이트하고 싶습니다만 setattr과 getattr의 조합이 사용하지 못하는 것 같습니다. setattr과 getattr을 결합한 Python

class Container(object): 
    def __init__(self): 
     pass 
container = Container() 
attributes = ['a', 'b', 'c', 'd'] 
values = [[1, 2, 3, 4, 5], [True, False], ['red', 'blue', 'green'], [0, 1, -1, -5, 99]] 

내가 명시 적 속성과 해당 값 목록을 구성하는 예제의 목적을 위해주의하시기 바랍니다 :

여기 내 주요 클래스입니다. 그러나이 코드의 실제 적용에서 나는 사전에 아무 것도 모른다. 번호, 이름 또는 값이 아닙니다. 이것은 동적으로 그렇게 할 필요성을 요구합니다. 나는이 코드를 실행하면

for key, value in zip(attributes, values): 
    setattr(container, key, []) 
    for val in value: 
     setattr(container, key, getattr(container, key).append(val)) 

이 부분은 작동하지 않습니다 여기에

코드의 나머지 부분입니다. getattr 부분을 tmp 변수에 저장 한 다음 setattr을 호출하기 전에 목록에 대한 append 메서드를 호출 할 수 있지만 가능한 경우이를 응축하고 싶습니다.

누구나 왜 이것이 작동하지 않는지 설명 할 수 있습니까? 어떤 대안이 있습니까?

도움 주셔서 감사합니다.

+0

"* 코드를 실행할 때 *이 부분이 작동하지 않습니다." 또한, 당신은 무엇을 기대합니까? – Blender

답변

3

현재 위치에 목록을 추가하고 있습니다. 모든 현재 위치에서 돌연변이 기능과 마찬가지로, .append() 반환 None, 그래서 당신의 마지막 줄 :

for key, value in zip(attributes, values): 
    setattr(container, key, values[:]) 
:

setattr(container, key, None) 

그냥 클래스에있는 목록의 사본을 설정

setattr(container, key, getattr(container, key).append(val)) 

궁극적으로 평가

여기서 [:]은 0에서 len(values)까지의 길이로 슬라이스하여 values 사본을 만듭니다. hout는 반복 할 필요가있다.

당신이 원하는 모든의 (a dict 아직 대신 항목에 액세스 속성 액세스 할 많은처럼), 당신은 또한 사용할 수있는 속성과 키와 값을 제공하는 객체를 생성하는 경우 :

class Container(object): 
    def __init__(self, names, values): 
     self.__dict__.update(zip(names, values)) 

다음 실행 루프에서 setattr()를 호출 할 필요가 없어

Container(attributes, values) 

합니다.

+0

나는'defaultdict (list)'가 여기 적당한 후보자라고 생각하고 있었다. ... –

+0

설명해 주셔서 감사합니다. 왜 getattr (container, key, value)가 setattr (container, key, value)와 같은 기능을하는 지 알고 싶습니까? – user1713952

+0

@ user1713952 : 그것은'getattr (container, key, default)'입니다; 'key' 속성이'container'에 설정되어 있지 않으면 대신'default'가 리턴됩니다. 이미 * set *되어 있으므로,'key','getattr (container, key)'로 충분합니다. –

1

그것은 각 단계의 진행 상황을 볼 수 있다면 당신은 무슨 일이 일어나고 있는지 이해하는 데 도움이 될 수 있습니다 이제 print container을 할 수

class Container(object): 
    def __init__(self): 
     pass 
    def __str__(self): 
     return '%s(%s)' % (self.__class__.__name__, 
      ', '.join(['%s = %s' % (attr, getattr(self, attr)) 
       for attr in self.__dict__])) 

.당신이 중첩 루프에서이 작업을 수행 할 경우에 당신은 (마티가 언급 한 바와 같이) setattr에 첫 번째 시도 후 container.a에 저장된 원본 목록을 사방 한 것을 볼 수 있습니다 :

for key, value in zip(attributes, values): 
    setattr(container, key, []) 
    for val in value: 
     print 'before:', container 
     setattr(container, key, getattr(container, key).append(val)) 
     print 'after:', container 

before: Container(a = []) 
after: Container(a = None) 
before: Container(a = None) 
Traceback (most recent call last): ... 

이 작업을 수행하는 "최고"의 방법을 분명히 실제 문제에 달려있다. Martijn의 버전이 상당히 적절하지만, 아마도 초기 container 인스턴스를 생성 한 후 어느 시점에 하나의 항목을 추가하거나 여러 항목으로 확장해야 할 수도있다.