web-dev-qa-db-ja.com

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

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

実行時までその名前を知らずに関数への参照を取得するためにどのようにそれを使用するかについて本が言及したとき私は理解していませんでした。多分これは私がプログラミングのノブであること、一般的にです。誰かが被写体に光を当てることができますか?いつ、どのように私はこれを正確に使いますか?

240
Terence Ponce

あなたはここで完全な例を見ることができます:

イントロスペクションはさまざまな目的に使用できます。 'Dive Into Python'で紹介されているものは、単にアプリケーションに機能(プラグイン)を動的に追加する方法です。

動的に動的に新しい機能を追加するためにコアアプリケーションに変更を加えることなく意味します。

「Dive Into Python」の例 - 異なるファイルのファイルから属性を抽出する簡単なアプリケーション - 元のアプリケーションに変更を加えることなく新しいファイル形式の処理を追加できます。

本を完成させることをお勧めします。あなたが読むにつれて、すべてがますます明確になるでしょう。

60
Alois Cochard

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

getattrdir とともに使用して、すべての属性名を反復処理してそれらの値を取得することができます。

>>> 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'
>>>
261
warvariuc

私にとって、getattrはこのように説明するのが最も簡単です。

メソッド名を入力する代わりに、文字列の内容に基づいてメソッドを呼び出すことができます。

たとえば、これはできません。

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

なぜならxは "builtin"型ではなく "str"型だからです。しかし、あなたはこれを行うことができます:

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

入力に基づいてオブジェクトと動的に接続することができます。カスタムオブジェクトやモジュールを扱うときに便利です。

88
NuclearPeon

getattrの非常に一般的な使用例は、データを関数にマッピングすることです。

例えば、DjangoやPylonsのようなWebフレームワークでは、getattrはWebリクエストのURLをそれを処理する関数にマッピングすることを簡単にします。たとえば、Pylonsのルーティングの中身を見ると、(少なくともデフォルトでは)それがリクエストのURLを切り取っていることがわかります。

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

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

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

43
Robert Rossney

getattr()を使用して実行されているオペレーティングシステムに応じて、クラスがsaveメソッドの異なるバージョンを起動する方法の簡単で汚い例です。

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()
12
Josh

ここにあるすべての驚くべき答え以外に、getattrを使用して大量のコード行を保存し、それを適切に保つ方法があります。この考えは、時には必要になるかもしれないコードの恐ろしい表現に続いて起こりました。

シナリオ

ディレクトリ構造が次のようになっているとします。

- superheroes.py
- properties.py

そしてIron ManThorDoctor 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を使うことについての洞察を与えることです。

6
unixia

二次的に重要な属性がコードで使用される直前に遅延初期化するために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つによってのみ使用され、オブジェクトの意味とは関係がないユーティリティカウンタではなく、class。

3
Evgeni Sergeev

クラスに格納されているデータからXMLファイルを作成しているときに、属性が存在しないかNone型であると、エラーが頻繁に発生します。この場合、私の問題はあなたの質問で述べたように属性名が何であるかを知らなかったのではなく、むしろその属性に保存されたデータでした。

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

これを行うためにhasattrを使用した場合、属性値がTrue型であってもNoneが返されるため、ElementTreeのsetコマンドが失敗します。

hasattr(temp, 'hair')
>>True

属性値がNone型の場合、getattrもそれを返し、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
btathalon

getattr(object, 'x')同等ですobject.x

getattrが役に立つことがある2つのケースがあります。

  • あなたはobject.xを書くことができません、(あなたがあなたが望む属性を前もって知らないので。
  • デフォルト値を指定します。 AttributeErrorがない場合、object.yyを発生させます。しかしgetattr(object, 'y', 5)5を返します。
3
blue_note

Pythonでswitch文を実装する際のgetattr()のもう1つの使用方法。ケースタイプを取得するために両方のリフレクションを使用します。

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 __== '__main__':
    main(int(sys.argv[1]))
2
Jules Damji
# 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
Kduyehj

https://www.programiz.com/python-programming/methods/build-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
Barny