객체를 생성하고 속성을 추가하려면 어떻게해야합니까?


310

파이썬에서 동적 객체 (다른 객체 내부)를 만들고 속성을 추가하고 싶습니다.

나는 시도했다 :

obj = someobject
obj.a = object()
setattr(obj.a, 'somefield', 'somevalue')

그러나 이것은 효과가 없었습니다.

어떤 아이디어?

편집하다:

for값 목록을 반복하는 루프 에서 속성을 설정하고 있습니다.

params = ['attr1', 'attr2', 'attr3']
obj = someobject
obj.a = object()

for p in params:
   obj.a.p # where p comes from for loop variable

내가 얻을 것입니다 위의 예에서 obj.a.attr1, obj.a.attr2, obj.a.attr3.

루프 에서 setattr수행하는 방법을 몰랐기 때문에 함수를 사용했습니다 .obj.a.NAMEfor

p위의 예에서 값을 기준으로 속성을 어떻게 설정 합니까?


4
"작동하지 않았다"는 무슨 뜻입니까? AttributeError 예외가 발생했다고 가정합니다.
Josh Wright

1
네. 'object'객체는 'somefield'속성이 없습니다
John

6
왜 이런 짓을하는? 일반적인 "객체"는 실제 의미 가 없습니다 . 당신이 만들고있는 것의 의미 는 무엇입니까 ? 왜 적절한 수업이나 명명 된 튜플이 아닌가?
S.Lott

1
이 예는 최소한 나를 위해 혼동하지 않거나 일부와 일을하지 않는 이유는 표시되지 않습니다 a = object()당신이 필요합니다 obj.a = object(). 다시 한 번 예제에 대해 이야기하고 있습니다. 실제 코드에서 객체 내부의 객체가 유용 할 수 있습니다.
kon psych

답변:


215

내 고대 번치 레시피를 사용할 수 있지만 "번치 클래스"를 만들지 않으려면 파이썬에 이미 존재하는 매우 간단한 클래스가 있습니다. 모든 함수는 람다 함수를 포함하여 임의의 속성을 가질 수 있습니다. 따라서 다음과 같이 작동합니다.

obj = someobject
obj.a = lambda: None
setattr(obj.a, 'somefield', 'somevalue')

훌륭한 Bunch레시피 와 비교할 때 선명도의 손실이 괜찮은지 여부는 스타일 결정입니다.


25
@FogleBird, 내가 언급 한 스타일 결정. 예를 들어 교회의 람다 미적분학에서 훈련받은 일부 CS 전문가는 함수 (람다)를 모든 데이터의 기본 유형 (예 : 정수 23은와 동일하게 볼 수 있음)으로 생각하는 데 사용 되므로이 목적으로 s를 lambda: 23사용하는 전문가 lambda에게는 아마도 "해킹"과 같은 느낌이 들지 않을 것입니다. 개인적으로 저는 lambda 파이썬을 좋아하지 않지만 개인적 취향의 문제입니다.
Alex Martelli

그리고 어떤 경우에는 lambda패턴이 사용 사례에 맞는지 여부를 고려 하면 원래 데이터로 생각했던 것이 실제로는 함수와 같거나 어떤 경우에는 펀터와 같은 것임을 깨닫게 할 수 있습니다.
Kyle Strand

5
@ naught101에서 함수 파이썬에서 객체이므로 이의를 제기 할 수 없습니다.
Alex Martelli

6
@ naught101은 새로운 유형의 생성을 피하고 (기존 유형을 재사용하는) 복잡하지 않으므로 단순화합니다. 요즘에는 from argparse import Namespace다른 곳에서 살기를 원하지만 실제로는 더 선호 할 수 있습니다. 예 : collection)-기존 유형을 다시 사용하고 더 나은 유형을 다시 사용하고 여전히 새로운 유형의 생성을 피하십시오. 그러나 그때는 없었습니다 :-).
Alex Martelli

1
types 모듈의 SimpleNamespace에 대해서는 아래 "JF Sebastian"의 답변을 참조하십시오. 만약 당신의 파이썬 버전이 그것을 지원한다면, 이것이 최선의 솔루션입니다 (그리고 SimpleNamespace를 위해 설계된 것입니다)
Tim Richardson

333

내장 기능을 object인스턴스화 할 수 있지만 속성을 설정할 수는 없습니다. (이 정확한 목적을 위해 가능할 수 있기를 바랍니다.) __dict__속성을 보유 할 필요가 없습니다 .

나는 일반적으로 이것을한다 :

class Object(object):
    pass

a = Object()
a.somefield = somevalue

내가 할 수있을 때, Object어떤 종류의 데이터를 넣었는지에 따라 수업에 더 의미있는 이름을 부여 합니다.

어떤 사람들 dict은 속성 접근이 키를 얻을 수 있도록 하는 하위 클래스를 사용하는 다른 일을 합니다. ( d.key대신 d['key'])

편집 : 귀하의 질문에 추가하여 사용하는 setattr것이 좋습니다. 당신은 사용할 수 없습니다 setattrobject()인스턴스.

params = ['attr1', 'attr2', 'attr3']
for p in params:
    setattr(obj.a, p, value)

9
인스턴스화 할 있으며 일단 완료되면 유용한 것은 아닙니다. foo = object()작동하지만, 당신은 그것으로 아무것도 할 수 없습니다
Daniel DiPaolo

안녕하세요. 답변 해주셔서 감사합니다. 위의 문제를 업데이트했습니다. 편집을 참조하십시오. 이것에 대한 답을 알고 있습니까?
John

죄송하지만 여전히 객체에 설정하고 싶습니다. 위의 업데이트를 참조하십시오.
John

나는 당신의 대답을 정말로 좋아하며 앞으로이 방향을 기대할 것입니다. 나는 매우 간단하고 이해하기 쉽고 읽을 수있는 방법론을 제외하고이 게시물의 다른 모든 것에 대해 사용했습니다. type....내 코드의 텍스트 구토와 같이 람다를 사용 하거나 좋아하지 않았습니다. 그러나이 아이디어는 객체를 사용하여 속성을 유지하는 데 유용합니다. 람다를 볼 때 코드를 더 읽기 쉬운 b / c로 남겨 두십시오. 감사.
Marc

큰 대답은 내가 바꾼 유일한 것은 Struct클래스를 더 명확하게하기 위해 클래스 이름으로 사용하는 것이 었습니다. 타이핑을 절약 ["하고 "]건배!
pragman

137

types.SimpleNamespacePython 3.3+ 에는 클래스 가 있습니다 .

obj = someobject
obj.a = SimpleNamespace()
for p in params:
    setattr(obj.a, p, value)
# obj.a.attr1

collections.namedtuple, typing.NamedTuple불변의 객체에 사용될 수 있습니다. PEP 557-데이터 클래스 는 변경 가능한 대안을 제안합니다.

더 풍부한 기능을 위해 attrspackage을 사용해 볼 수 있습니다. 사용법 예를 참조하십시오 .


3
Python 2.7에서 작동하는 것이 필요하다면 argparse.Namespace클래스를 사용해 볼 수도 있습니다
RolKau

동의-여기에 단점이 있다면 궁금 할 것입니다. 그러나 이것은 매우 편리한 파이썬 3.3 + 여유입니다.
ghukill

제길! 이것은 2.7에서 사용할 수 없습니까?
Roel

@Roel attrs패키지는 파이썬 2.7 지원
JFS에게

이것은 unittest.mock보다 나에게 더 나은 해결책 인 것 같습니다. 후자는 약간 무겁고 약간 가단성입니다. 모의 객체를 사용하면 단순히 속성에 할당하면 속성이 존재하게됩니다. SimpleNamespace는이를 거부합니다.
jdzions

32

이 목표를 달성 할 수있는 몇 가지 방법이 있습니다. 기본적으로 확장 가능한 객체가 필요합니다.

obj.a = type('Test', (object,), {})  
obj.a.b = 'fun'  

obj.b = lambda:None

class Test:
  pass
obj.c = Test()

14
obj.a = type('', (), {})
iman

26

mock모듈은 기본적으로 그 위해 만들어졌다.

import mock
obj = mock.Mock()
obj.a = 5

3
단점은 외부 의존성입니다
Kangur

5
unittest.Mock파이썬 3.3 이후 표준 라이브러리의 일부입니다 ( docs.python.org/3/library/unittest.mock.html )
illagrenan

2
내가 생각하는 코드의 사용법에 달려 있습니다. 그것이 생산 코드라면, 나는 mock그것을 원하지 않을 것입니다. 나에게 이상하다고 느낀다.
Mike de Klerk

21

이제 할 수 있습니다 (evilpie와 같은 대답인지 확실하지 않음).

MyObject = type('MyObject', (object,), {})
obj = MyObject()
obj.value = 42

@evilpie의 답변은 귀하의 인스턴스가 아닌 MyObject (클래스)에 속성을 직접 설정합니다.
jfs

18

아래 코드를 사용해보십시오 :

$ python
>>> class Container(object):
...     pass 
...
>>> x = Container()
>>> x.a = 10
>>> x.b = 20
>>> x.banana = 100
>>> x.a, x.b, x.banana
(10, 20, 100)
>>> dir(x)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', 
'__getattribute__', '__hash__', '__init__', '__module__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__',     '__sizeof__', 
'__str__', '__subclasshook__', '__weakref__', 'a', 'b', 'banana']

1
이것이 무엇을 더 설명 할 수 있습니까? 코드는이 문제를 해결하는 데 유용 할 수 있지만 설명하면 한 가지 문제보다 훨씬 더 나아갈 수 있습니다.
DeadChex

1
@DeadChex 분명히 객체 속성을 가진 빈 클래스 인 새 클래스 (객체)를 생성하고 속성을 클래스 안에 저장합니다. 이것은 더 많은 모듈을 설치하거나 람다에 의존하는 것보다 낫습니다.
m3nda 2016 년

2
왜 더 많은 투표가 없는지 잘 모르겠습니다. 이것을 기본 컨테이너 클래스에 사용하지 않는 이유가 있습니까? Python 2.7, 2.6 및 3.4에서 제대로 작동하는 것 같습니다
user5359531

17

클래스 객체를 직접 사용할 수도 있습니다. 네임 스페이스를 만듭니다.

class a: pass
a.somefield1 = 'somevalue1'
setattr(a, 'somefield2', 'somevalue2')

9

문서에서 말하는 것처럼 :

참고 : object않습니다 하지__dict__할 수 있도록하지 할당 임의의 속성의 인스턴스, object클래스입니다.

더미 클래스 인스턴스를 사용할 수 있습니다.


2

이러한 솔루션은 테스트 중에 매우 유용합니다. 다른 사람의 답변을 바탕으로 파이썬 2.7.9 에서이 작업을 수행합니다 (정적 방법없이 TypeError (바인드되지 않은 메소드 ...)).

In [11]: auth = type('', (), {})
In [12]: auth.func = staticmethod(lambda i: i * 2)
In [13]: auth.func(2)
Out[13]: 4

1

어떤 개체를 사용하고 있습니까? 샘플 클래스를 사용하여 시도했지만 정상적으로 작동했습니다.

class MyClass:
  i = 123456
  def f(self):
    return "hello world"

b = MyClass()
b.c = MyClass()
setattr(b.c, 'test', 123)
b.c.test

그리고 나는 123대답으로 얻었다 .

내가 실패하는 유일한 상황 setattr은 내장 객체를 사용하는 경우입니다.

업데이트 : 의견에서 이것은 반복됩니다 : 왜 파이썬에서 객체에 속성을 추가 할 수 없습니까?


bc는 정의 된 클래스가 아닌 object ()로 설정 됨
John

0

늦은 시간에오고 있지만 여기에는 응용 프로그램에서 유용한 경로를 유지하는 객체가있는 제 돈이 있습니다. 그러나 getattr 및 도트 표기법으로 액세스 할 수있는 일종의 정보를 원하는 모든 곳에 적용 할 수 있습니다 (이 질문이 실제로 생각한 것입니다) :

import os

def x_path(path_name):
    return getattr(x_path, path_name)

x_path.root = '/home/x'
for name in ['repository', 'caches', 'projects']:
    setattr(x_path, name, os.path.join(x_path.root, name))

지금은 멋지다.

In [1]: x_path.projects
Out[1]: '/home/x/projects'

In [2]: x_path('caches')
Out[2]: '/home/x/caches'

따라서 위의 답변과 같은 함수 객체를 사용하지만 함수를 사용하여 값을 얻습니다 ( 원하는 경우 (getattr, x_path, 'repository')보다는 여전히 사용할 수 있음 x_path('repository')).


0

중첩 된 객체를 만들기 전에 모든 속성과 값을 결정하고 집계 할 수 있다면 생성시 사전 인수를 사용하는 새 클래스를 만들 수 있습니다.

# python 2.7

class NestedObject():
    def __init__(self, initial_attrs):
        for key in initial_attrs:
            setattr(self, key, initial_attrs[key])

obj = someobject
attributes = { 'attr1': 'val1', 'attr2': 'val2', 'attr3': 'val3' }
obj.a = NestedObject(attributes)
>>> obj.a.attr1
'val1'
>>> obj.a.attr2
'val2'
>>> obj.a.attr3
'val3'

키워드 인수도 허용 할 수 있습니다. 이 게시물을 참조하십시오 .

class NestedObject(object):
    def __init__(self, *initial_attrs, **kwargs):
        for dictionary in initial_attrs:
            for key in dictionary:
                setattr(self, key, dictionary[key])
        for key in kwargs:
            setattr(self, key, kwargs[key])


obj.a = NestedObject(attr1='val1', attr2='val2', attr3= 'val3')

-2
di = {}
for x in range(20):
    name = '_id%s' % x
    di[name] = type(name, (object), {})
    setattr(di[name], "attr", "value")

-2

내가 보는 다른 방법,이 방법 :

import maya.cmds

def getData(objets=None, attrs=None):
    di = {}
    for obj in objets:
        name = str(obj)
        di[name]=[]
        for at in attrs:
            di[name].append(cmds.getAttr(name+'.'+at)[0])
    return di

acns=cmds.ls('L_vest_*_',type='aimConstraint')
attrs=['offset','aimVector','upVector','worldUpVector']

getData(acns,attrs)

이 di [name] .append ([at, cmds.getAttr (name + '.'+ at) [0]]) attr을 추가 할 수 있습니다.
Pablo Emmanuel De Leo

1
이것은 매우 큰 비표준 의존성을 추가하는 반면 간단한 class a: pass것은 필요한 모든 힘을 제공합니다.
Alexis Paques
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.