正確にgetattr()とは何ですか?どのように使用しますか?


295

私は最近関数について読みましたgetattr()。問題は、その使い方のアイデアがまだ理解できないことです。私が理解してgetattr()いる唯一のことgetattr(li, "pop")は、を呼び出すことと同じli.popです。

この本で、実行時まで関数の名前を知らずに関数への参照を取得する方法が本で言及されているときは、理解できませんでした。多分これは私がプログラミングの初心者なのかもしれません。誰かがこの問題に光を当てることができますか?これをいつ、どのように正確に使用しますか?


どの部分に問題がありますか?文字列としての属性?ファーストクラスの機能?
Ignacio Vazquez-Abrams、

1
私の問題はgetattr()の概念を理解することだと思います。私はまだその目的を理解していません。
Terence Ponce、2010年

@テレンスは私の答えが物事をより明確にしないのですか?
Alois Cochard、2010年

@Alois、あなたの答えは間違いなく私の疑問のいくつかを解決しましたが、私はまだgetattr()が何のためにあるのか完全には理解できません。
Terence Ponce、2010年

6
@ S.Lott、やった。ドキュメンテーションは定義だけを持っていたので、私はその使用法についてちょっと混乱しました。それについてもっと読んだ後、私はgetattrを理解しました。
Terence Ponce

回答:


88

getattr(object, 'x') 完全に同等であるobject.x

役立つケース2つしかありませgetattr

  • 必要なobject.x属性(文字列から取得)が事前にわからないため、を書くことはできません。メタプログラミングに非常に役立ちます。
  • デフォルト値を提供したい。object.yAttributeErrorない場合はが発生しyます。しかしgetattr(object, 'y', 5)戻り5ます。

2
これは受け入れられる答えだと思います。非常に明確で要点があります。
yuqli

290

Pythonのオブジェクトは属性を持つことができます-データ属性とそれらを操作するための関数(メソッド)。実際、すべてのオブジェクトには組み込みの属性があります。

たとえば、あなたがオブジェクトを持ってperson、それはいくつかの属性がありますnamegenderなど

あなたは、通常の書き込み(それがメソッドまたはデータオブジェクトも)これらの属性にアクセス:person.nameperson.genderperson.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'

ただし、3番目の引数としてデフォルト値を渡すことができます。このような属性が存在しない場合に返されます。

>>> 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と、それらを呼び出すを

と同様にgetattr、はsetattr、その名前を持つオブジェクトの属性を設定できるようにします。

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

9
したがってgetattr(..)、2つのシナリオで使用する必要があるように思われます。1。属性名が変数内の値である場合(例getattr(person, some_attr))と2.デフォルト値に3番目の位置引数を使用する必要がある場合(例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などのWebフレームワークでgetattrは、WebリクエストのURLを、それを処理する関数に簡単にマッピングできます。たとえば、Pylonsのルーティングの内部を見ると、(デフォルトでは、少なくとも)リクエストのURLが次のように切り取られていることがわかります。

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

「顧客」と「リスト」に。次に、という名前のコントローラークラスを検索しますCustomerController。クラスが見つかったとすると、クラスのインスタンスを作成し、getattrそのlistメソッドを取得するために使用します。次に、そのメソッドを呼び出し、リクエストを引数として渡します。

このアイデアを理解すると、Webアプリケーションの機能を拡張するのが非常に簡単になります。コントローラークラスに新しいメソッドを追加し、それらのメソッドに適切なURLを使用するリンクをページに作成するだけです。これはすべてによって可能になりましたgetattr


13

以下は、を使用して実行されているオペレーティングシステムに応じて、クラスが異なるバージョンのsaveメソッドを起動する方法の簡単な例です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

そして、あなたはに関する情報を取得するための機能を持っているThorIron ManDoctor 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 2015年

3

私は時々使用しgetattr(..)、それらがコード内で使用されている直前に二次的に重要な属性の初期化怠惰に。

以下を比較してください:

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)

2番目の方法の利点は、n_calls_to_plotコード内で使用される場所の周りにしか表示されないことです。これは、(1)使用方法を読み取ると、どの値から始まるかがすぐにわかるため、(2)__init__(..)理想的には、クラスの概念的な状態に関するメソッドの邪魔にならないため、読みやすくなります。、最適化などの技術的な理由のために関数のメソッドの1つでのみ使用されるユーティリティカウンターではなく、オブジェクトの意味とは何の関係もありません。


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

Pythonでの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我々は、これらの値をretrive

例えば

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

この例は自明だと思います。名前が2番目のパラメーターで指定されている最初のパラメーターのメソッドを実行します。

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.