getattr ()이란 무엇이며 어떻게 사용합니까?


295

최근 getattr()함수 에 대해 읽었습니다 . 문제는 여전히 사용법에 대한 아이디어를 파악할 수 없다는 것입니다. 내가 대해 이해할 수있는 유일한 방법은 getattr()getattr(li, "pop")호출과 동일합니다 li.pop.

나는 책이 런타임까지 함수의 이름을 알지 못하고 함수에 대한 참조를 얻는 방법을 언급했을 때 이해하지 못했습니다. 어쩌면 이것은 일반적으로 프로그래밍에서 멍청한 것일 수도 있습니다. 누구든지 주제에 대해 약간의 빛을 비출 수 있습니까? 언제 어떻게 정확하게 사용해야합니까?


어느 부분에 문제가 있습니까? 문자열 속성? 일류 기능?
이그나시오 바스케스-아 브람스

1
내 문제는 getattr ()의 개념을 이해하고 있다고 생각합니다. 나는 아직도 그 목적을 이해하지 못한다.
Terence Ponce

@ Terence 내 대답이 더 명확하지 않습니까?
Alois Cochard 5

@Alois, 당신의 대답은 확실히 내 의심의 일부를 해결했지만 getattr ()이 무엇인지 완전히 이해할 수는 없습니다.
테렌스 폰세

6
@ S.Lott, 나는했다. 문서에는 정의 만 있었으므로 사용법에 대해 혼란 스러웠습니다. 그래도 getattr에 대해 더 많이 읽은 후에 이해합니다.
테렌스 폰세

답변:


88

getattr(object, 'x') 완전히 동등object.x.

있다 다음 두 가지 경우에만getattr 유용 할 수는.

  • object.x원하는 속성을 미리 알지 못하므로 (문자열에서 나옴) 쓸 수 없습니다 . 메타 프로그래밍에 매우 유용합니다.
  • 기본값을 제공하려고합니다. object.y가 없으면를 AttributeError발생 y시킵니다. 그러나 getattr(object, 'y', 5)돌아올 것이다 5.

2
나는 이것이 받아 들여야 할 답변이라고 생각합니다. 매우 명확하고 요점.
yuqli

290

파이썬의 객체는 속성 (데이터 속성 및 그와 함께 작동하는 함수)을 가질 수 있습니다. 실제로 모든 객체에는 내장 속성이 있습니다.

예를 들어 객체를 가지고 person, 그 몇 가지 속성이 있습니다 name, gender

이러한 속성은 (그 방법이나 데이터 객체 일) 보통 쓰기 액세스 : person.name, person.gender, person.the_method(), 등

그러나 프로그램을 작성할 때 속성의 이름을 모른다면 어떻게해야합니까? 예를 들어, 속성 이름이라는 변수에 저장되어 attr_name있습니다.

만약

attr_name = 'gender'

그런 다음 글을 쓰는 대신

gender = person.gender

당신은 쓸 수 있습니다

gender = getattr(person, attr_name)

연습 :

Python 3.4.0 (default, Apr 11 2014, 13:05:11)

>>> class Person():
...     name = 'Victor'
...     def say(self, what):
...         print(self.name, what)
... 
>>> getattr(Person, 'name')
'Victor'
>>> attr_name = 'name'
>>> person = Person()
>>> getattr(person, attr_name)
'Victor'
>>> getattr(person, 'say')('Hello')
Victor Hello

getattr올릴 AttributeError지정된 이름을 가지는 속성이 객체로 존재하지 않는 경우 :

>>> getattr(person, 'age')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Person' object has no attribute 'age'

그러나 세 번째 인수로 기본값을 전달할 수 있습니다. 이러한 속성이 존재하지 않으면 반환됩니다.

>>> getattr(person, 'age', 0)
0

당신은 사용할 수 getattr와 함께 dir모든 속성 이름을 반복하고 그 값을 얻을 :

>>> dir(1000)
['__abs__', '__add__', ..., '__trunc__', '__xor__', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']

>>> obj = 1000
>>> for attr_name in dir(obj):
...     attr_value = getattr(obj, attr_name)
...     print(attr_name, attr_value, callable(attr_value))
... 
__abs__ <method-wrapper '__abs__' of int object at 0x7f4e927c2f90> True
...
bit_length <built-in method bit_length of int object at 0x7f4e927c2f90> True
...

>>> getattr(1000, 'bit_length')()
10

이에 대한 실제적인 사용은 이름이로 시작하는 모든 방법을 찾을 것 test그들에게 전화를 .

유사에 getattrsetattr당신이 그 이름을 가진 개체의 속성을 설정할 수있는 :

>>> setattr(person, 'name', 'Andrew')
>>> person.name  # accessing instance attribute
'Andrew'
>>> Person.name  # accessing class attribute
'Victor'
>>>

9
따라서 getattr(..)두 가지 시나리오에서 사용해야 하는 것처럼 보입니다 . 1. 속성 이름이 변수 내부의 값일 getattr(person, some_attr)때 (예 :) 2. 기본값으로 세 번째 위치 인수를 사용해야 할 때 (예 :) getattr(person, 'age', 24). 내가 비슷한 시나리오 getattr(person, 'age')를 본다면 그것이 더 Pythonic person.age이라고 생각하게하는 것과 동일 하다고 생각 person.age됩니다. 그 맞습니까?
wpcarro

102

getattr에게이 방법을 설명하는 것이 가장 쉽습니다.

메소드 이름을 입력하는 대신 문자열 컨텐츠를 기반으로 메소드를 호출 할 수 있습니다.

예를 들어 다음을 수행 할 수 없습니다.

obj = MyObject()
for x in ['foo', 'bar']:
    obj.x()

x는 유형이 아니기 때문에 builtin,하지만 str. 그러나 다음을 수행 할 수 있습니다.

obj = MyObject()
for x in ['foo', 'bar']:
    getattr(obj, x)()

입력을 기반으로 객체와 동적으로 연결할 수 있습니다. 사용자 정의 객체 및 모듈을 다룰 때 유용하다는 것을 알았습니다.


2
이것은 매우 직설적이고 정확한 답변입니다.
user6037143

43

일반적인 사용 사례 getattr는 데이터를 함수에 매핑하는 것입니다.

예를 들어 Django 나 Pylons와 같은 웹 프레임 워크에서 getattr 에서 웹 요청의 URL을 처리 할 함수에 간단하게 매핑 할 수 있습니다. 예를 들어 Pylons의 라우팅을 살펴보면 최소한 기본적으로 다음과 같이 요청의 URL이 잘리는 것을 볼 수 있습니다.

http://www.example.com/customers/list

"고객"과 "목록"으로. 그런 다음 이름이 지정된 컨트롤러 클래스를 검색합니다.CustomerController . 클래스를 찾으면 클래스의 인스턴스를 작성한 다음 메소드 getattr를 얻는 데 사용 합니다 list. 그런 다음 해당 메소드를 호출하여 요청을 인수로 전달합니다.

이 아이디어를 이해하면 웹 애플리케이션의 기능을 확장하기가 쉽습니다. 컨트롤러 클래스에 새 메소드를 추가 한 다음 해당 메소드에 적합한 URL을 사용하는 페이지에 링크를 작성하십시오. 이 모든 것이 가능합니다 getattr.


13

다음은 클래스를 사용하여 실행되는 운영 체제에 따라 클래스가 다른 버전의 저장 메소드를 실행하는 방법에 대한 빠르고 더러운 예입니다 getattr().

import os

class Log(object):
    def __init__(self):
        self.os = os.name
    def __getattr__(self, name):
        """ look for a 'save' attribute, or just 
          return whatever attribute was specified """
        if name == 'save':
            try:
                # try to dynamically return a save 
                # method appropriate for the user's system
                return getattr(self, self.os)
            except:
                # bail and try to return 
                # a default save method
                return getattr(self, '_save')
        else:
            return getattr(self, name)

    # each of these methods could have save logic specific to 
    # the system on which the script is executed
    def posix(self): print 'saving on a posix machine'
    def nt(self): print 'saving on an nt machine'
    def os2(self): print 'saving on an os2 machine'
    def ce(self): print 'saving on a ce machine'
    def java(self): print 'saving on a java machine'
    def riscos(self): print 'saving on a riscos machine'
    def _save(self): print 'saving on an unknown operating system'

    def which_os(self): print os.name

이제이 클래스를 예제로 사용하자 :

logger = Log()

# Now you can do one of two things:
save_func = logger.save
# and execute it, or pass it along 
# somewhere else as 1st class:
save_func()

# or you can just call it directly:
logger.save()

# other attributes will hit the else 
# statement and still work as expected
logger.which_os()

7

여기에 모든 놀라운 답변 외에도 사용 방법이 있습니다. getattr 많은 코드 줄을 저장하고 아늑한 상태로 유지하는 데 수 . 이러한 생각은 때때로 필요할 수있는 끔찍한 코드 표현을 따르게되었습니다.

대본

디렉토리 구조가 다음과 같다고 가정하십시오.

- superheroes.py
- properties.py

그리고, 당신은에 대한 정보를 얻기위한 기능을 가지고 Thor, Iron Man, Doctor Strangesuperheroes.py. 당신은 매우 현명에서 그들 모두의 속성을 적어 properties.py소형에서 dict한 다음에 액세스 할 수 있습니다.

properties.py

thor = {
    'about': 'Asgardian god of thunder',
    'weapon': 'Mjolnir',
    'powers': ['invulnerability', 'keen senses', 'vortex breath'], # and many more
}
iron_man = {
    'about': 'A wealthy American business magnate, playboy, and ingenious scientist',
    'weapon': 'Armor',
    'powers': ['intellect', 'armor suit', 'interface with wireless connections', 'money'],
}
doctor_strange = {
    'about': ' primary protector of Earth against magical and mystical threats',
    'weapon': 'Magic',
    'powers': ['magic', 'intellect', 'martial arts'],
}

이제 요청시 각 기능을 반환한다고 가정 해 보겠습니다 superheroes.py. 따라서 다음과 같은 기능이 있습니다

from .properties import thor, iron_man, doctor_strange


def get_thor_weapon():
    return thor['weapon']


def get_iron_man_bio():
    return iron_man['about']


def get_thor_powers():
    return thor['powers']

... 키와 슈퍼 히어로에 따라 다른 값을 반환하는 더 많은 함수.

의 도움으로 getattr다음과 같은 작업을 수행 할 수 있습니다.

from . import properties


def get_superhero_weapon(hero):
    superhero = getattr(properties, hero)
    return superhero['weapon']


def get_superhero_powers(hero):
    superhero = getattr(properties, hero)
    return superhero['powers']

코드 줄, 함수 및 반복 수를 상당히 줄였습니다!

물론 properties_of_thor변수 와 같은 나쁜 이름이 있다면 간단히 수행하여 만들거나 액세스 할 수 있습니다

def get_superhero_weapon(hero):
    superhero = 'properties_of_{}'.format(hero)
    all_properties = getattr(properties, superhero)
    return all_properties['weapon']

참고 :이 특정 문제의 경우 상황을 처리하는 더 현명한 방법이있을 수 있지만 getattr올바른 위치에서보다 깨끗한 코드를 작성 하는 방법에 대한 통찰력을 얻는 것이 좋습니다 .


3
# getattr

class hithere():

    def french(self):
        print 'bonjour'

    def english(self):
        print 'hello'

    def german(self):
        print 'hallo'

    def czech(self):
        print 'ahoj'

    def noidea(self):
        print 'unknown language'


def dispatch(language):
    try:
        getattr(hithere(),language)()
    except:
        getattr(hithere(),'noidea')()
        # note, do better error handling than this

dispatch('french')
dispatch('english')
dispatch('german')
dispatch('czech')
dispatch('spanish')

2
제공하는 솔루션에 대한 설명을 조금 더 추가하여 답변을 더 자세히 설명해 주시겠습니까?
abarisone

3

때로는 getattr(..)코드에서 사용되기 직전에 2 차 중요 속성을 느리게 초기화하는 데 사용합니다.

다음을 비교하십시오.

class Graph(object):
    def __init__(self):
        self.n_calls_to_plot = 0

    #...
    #A lot of code here
    #...

    def plot(self):
        self.n_calls_to_plot += 1

이에:

class Graph(object):
    def plot(self):
        self.n_calls_to_plot = 1 + getattr(self, "n_calls_to_plot", 0)

두 번째 방법의 장점은 n_calls_to_plot코드가 사용되는 장소 주위에만 나타납니다. (1) 사용 방법을 읽을 때 어떤 값으로 시작하는지 즉시 확인할 수 있기 때문에 (2) __init__(..)방법에 방해가되지 않습니다. , 최적화와 같은 기술적 이유로 함수의 방법 중 하나에서만 사용되며 오브젝트의 의미와 관련이없는 일부 유틸리티 카운터보다는.


3

클래스에 저장된 데이터로 XML 파일을 만들 때 속성이 존재하지 않거나 유형 인 경우 종종 오류가 발생합니다 None. 이 경우 내 문제는 귀하의 질문에 명시된 바와 같이 속성 이름이 무엇인지 알지 못했지만 데이터가 해당 속성에 저장되었습니다.

class Pet:
    def __init__(self):
        self.hair = None
        self.color = None

내가 사용하는 경우 hasattr이 작업을 수행하기 위해서는 반환 True속성 값이 유형의 경우에도 None이 내 ElementTree의 원인이 set명령이 실패 할 수 있습니다.

hasattr(temp, 'hair')
>>True

속성 값이 유형 Nonegetattr경우 ElementTree set명령이 실패 하는 속성 값 도 반환합니다 .

c = getattr(temp, 'hair')
type(c)
>> NoneType

다음 방법을 사용하여 이러한 경우를 처리합니다.

def getRealAttr(class_obj, class_attr, default = ''):
    temp = getattr(class_obj, class_attr, default)
    if temp is None:
        temp = default
    elif type(temp) != str:
        temp = str(temp)
    return temp

언제 그리고 어떻게 사용 getattr합니다.


3

파이썬에서 switch 문을 구현할 때 getattr ()의 또 다른 사용. 리플렉션을 사용하여 케이스 유형을 가져옵니다.

import sys

class SwitchStatement(object):
    """ a class to implement switch statement and a way to show how to use gettattr in Pythion"""

    def case_1(self):
        return "value for case_1"

    def case_2(self):
        return "value for case_2"

    def case_3(self):
        return "value for case_3"

    def case_4(self):
        return "value for case_4"

    def case_value(self, case_type=1):
        """This is the main dispatchmethod, that uses gettattr"""
        case_method = 'case_' + str(case_type)
        # fetch the relevant method name
        # Get the method from 'self'. Default to a lambda.
        method = getattr(self, case_method, lambda: "Invalid case type")
        # Call the method as we return it
        return method()

def main(_):
    switch = SwitchStatement()
    print swtich.case_value(_)

if __name__ == '__main__':
    main(int(sys.argv[1]))

이 대답처럼 내가하지만 작은 오타를 수정하십시오
수도

2

setattr ()

setattr 을 사용 하여 클래스 인스턴스에 속성을 추가합니다. 클래스 인스턴스, 속성 이름 및 값을 전달합니다.

getattr ()

getattr 을 사용 하여 이러한 값을 검색합니다

예를 들어

Employee = type("Employee", (object,), dict())

employee = Employee()

# Set salary to 1000
setattr(employee,"salary", 1000 )

# Get the Salary
value = getattr(employee, "salary")

print(value)

1

이 예제는 설명이 필요하다고 생각합니다. 이름이 두 번째 매개 변수에 지정된 첫 번째 매개 변수의 메소드를 실행합니다.

class MyClass:
   def __init__(self):
      pass
   def MyMethod(self):
      print("Method ran")

# Create an object
object = MyClass()
# Get all the methods of a class
method_list = [func for func in dir(MyClass) if callable(getattr(MyClass, func))]
# You can use any of the methods in method_list
# "MyMethod" is the one we want to use right now

# This is the same as running "object.MyMethod()"
getattr(object,'MyMethod')()

0

https://www.programiz.com/python-programming/methods/built-in/getattr 에서 명확하게 설명합니다.

class Person:
    age = 23
    name = "Adam"

person = Person()
print('The age is:', getattr(person, "age"))
print('The age is:', person.age)

나이 : 23

나이 : 23

class Person:
    age = 23
    name = "Adam"

person = Person()

# when default value is provided
print('The sex is:', getattr(person, 'sex', 'Male'))

# when no default value is provided
print('The sex is:', getattr(person, 'sex'))

섹스는 : 남성

AttributeError : 'Person'개체에 'sex'특성이 없습니다.


0

나는 Python2.7.17에서 시도했다

동료 사람들 중 일부는 이미 대답했습니다. 그러나 getattr (obj, 'set_value')을 호출하려고 시도했지만 set_value 메소드를 실행하지 않았으므로 getattr (obj, 'set_value') ()->로 변경했습니다.

예제 코드 :

예 1 :

    class GETATT_VERIFY():
       name = "siva"
       def __init__(self):
           print "Ok"
       def set_value(self):
           self.value = "myself"
           print "oooh"
    obj = GETATT_VERIFY()
    print getattr(GETATT_VERIFY, 'name')
    getattr(obj, 'set_value')()
    print obj.value
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.