WedX - журнал о программировании и компьютерных науках

Что такое getattr () и как его использовать?

Недавно я прочитал о функции getattr(). Проблема в том, что я до сих пор не могу понять, как его использовать. Единственное, что я понимаю о getattr(), это то, что getattr(li, "pop") - это то же самое, что и вызов li.pop.

Я не понял, когда в книге упоминалось, как вы используете ее для получения ссылки на функцию, не зная ее имени до времени выполнения. Может быть, это вообще то, что я новичок в программировании. Может ли кто-нибудь пролить свет на эту тему? Когда и как именно это использовать?

02.11.2010

  • С какой частью у вас проблемы? Атрибуты в виде строк? Первоклассные функции? 02.11.2010
  • Я думаю, что моя проблема в понимании концепции getattr (). Я до сих пор не понимаю его цели. 02.11.2010
  • @ Теренс, разве мой ответ не проясняет ситуацию? 02.11.2010
  • @Alois, ваш ответ определенно развеял некоторые из моих сомнений, но я до сих пор не могу полностью понять, для чего нужен getattr (). 02.11.2010
  • @ S.Lott, да. В документации было только определение, поэтому я был немного смущен его использованием. Я понимаю getattr теперь, после того, как прочитал о нем больше. 02.11.2010
  • См. также: stackoverflow.com/questions/786412/ 08.12.2018

Ответы:


1

getattr(object, 'x') полностью эквивалентно object.x.

Есть только два случая, когда getattr может быть полезным.

  • вы не можете написать object.x, потому что заранее не знаете, какой атрибут вам нужен (он исходит из строки). Очень полезно для метапрограммирования.
  • вы хотите указать значение по умолчанию. object.y поднимет AttributeError, если нет y. Но getattr(object, 'y', 5) вернет 5.
10.04.2019
  • Неправильно ли я полагаю, что второй пункт не согласуется с начальным утверждением ответа? 02.07.2020
  • @skoh: ну, на самом деле, во вступительном заявлении упоминается getattr с двумя параметрами (что эквивалентно), а во втором маркере упоминается getattr с 3 параметрами. Даже если бы это было несистематично, я бы, наверное, оставил это, акцент важнее. 02.07.2020
  • ты потерял меня, потому что ты не знаешь заранее, какой атрибут тебе нужен (он исходит из строки) ... 21.08.2020
  • @UlfGjerdingen: подумайте о javascript. o.x эквивалентно o['x']. Но второе выражение можно использовать с любыми o[some_string], которые могут быть определены во время выполнения (например, из пользовательского ввода или проверки объекта), в то время как в первом выражении x фиксировано. 21.08.2020
  • @blue_note и что такое object.x 16.09.2020
  • Это атрибутный доступ объекта, как и в любом объектно-ориентированном языке. 16.09.2020
  • Другой вариант использования, чтобы оживить некро, - это когда идентификатор содержит недопустимый символ, например . или - (как я сейчас имею дело). getattr(obj, 'some.val') будет работать там, где obj.some.val не будет. 26.10.2020
  • Или вместо того, чтобы содержать недопустимый символ, имя атрибута могло бы быть зарезервированным словом. Чтобы упредить вопрос, и этот регистр, и случай пунктуации могут произойти либо из-за того, что setattr использовался ранее, либо из-за прямого взлома __dict__ объекта. Это может происходить неявно при использовании types.SimpleNamespace или argparse.Namespace. 28.03.2021

  • 2

    Объекты в Python могут иметь атрибуты - атрибуты данных и функции для работы с ними (методы). Собственно, у каждого объекта есть встроенные атрибуты.

    Например, у вас есть объект person, у которого есть несколько атрибутов: name, gender и т. Д.

    Вы получаете доступ к этим атрибутам (будь то методы или объекты данных), обычно записывая: person.name, person.gender, person.the_method() и т. Д.

    Но что, если вы не знаете имя атрибута во время написания программы? Например, имя атрибута хранится в переменной attr_name.

    if

    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 и позвоните им.

    Подобно getattr, есть _ 21_, который позволяет вам установить атрибут объекта, имеющего его имя:

    >>> setattr(person, 'name', 'Andrew')
    >>> person.name  # accessing instance attribute
    'Andrew'
    >>> Person.name  # accessing class attribute
    'Victor'
    >>>
    
    02.11.2010
  • Мне кажется, что getattr(..) следует использовать в двух сценариях: 1. когда имя атрибута является значением внутри переменной (например, getattr(person, some_attr)) и 2. когда нам нужно использовать третий позиционный аргумент для значения по умолчанию (например, getattr(person, 'age', 24) ). Если я вижу сценарий типа getattr(person, 'age'), мне кажется, что он идентичен person.age, что наводит меня на мысль, что person.age более питонический. Это верно? 25.10.2016
  • @wpcarro и person.age, и getattr(person, "age") идиоматичны для Python, поэтому трудно сделать вывод, что один из них более питоничен, чем другой. 19.07.2020
  • Читаемость имеет значение. Конечно person.age лучше, чем getattr(person, "age"). Имеет смысл использовать getattr, когда у вас есть имя атрибута в переменной. 10.06.2021

  • 3

    Для меня getattr проще всего объяснить так:

    Он позволяет вызывать методы на основе содержимого строки вместо ввода имени метода.

    Например, нельзя этого сделать:

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

    потому что x относится не к типу builtin, а к str. Однако вы МОЖЕТЕ сделать это:

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

    Это позволяет вам динамически подключаться к объектам на основе ваших входных данных. Я нашел это полезным при работе с пользовательскими объектами и модулями.

    30.08.2013
  • Это довольно прямой и точный ответ. 01.01.2019
  • что такое object.x 16.09.2020
  • @develarist У автора вопроса не было примера, на котором я мог бы основывать свой ответ, поэтому MyObject, obj и x (определение класса, экземпляр класса и атрибут соответственно) являются просто примерами / данными макета, где вы должны заполнить свои собственные классы и атрибуты, к которым вы хотите получить доступ. foo, bar и baz часто используются в качестве заполнителей в документации linux / unix / foss. 16.09.2020

  • 4

    Довольно распространенный вариант использования getattr - сопоставление данных с функциями.

    Например, в веб-фреймворке, таком как Django или Pylons, getattr упрощает сопоставление URL-адреса веб-запроса с функцией, которая будет его обрабатывать. Если вы посмотрите, например, под капот маршрутизации Pylons, вы увидите, что (по крайней мере, по умолчанию) он разбивает URL-адрес запроса, например:

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

    в «клиенты» и «список». Затем он ищет класс контроллера с именем CustomerController. Предполагая, что он находит класс, он создает экземпляр класса, а затем использует getattr для получения своего list метода. Затем он вызывает этот метод, передавая ему запрос в качестве аргумента.

    Как только вы усвоите эту идею, становится действительно легко расширить функциональность веб-приложения: просто добавьте новые методы в классы контроллеров, а затем создайте ссылки на своих страницах, которые используют соответствующие URL-адреса для этих методов. Все это стало возможным благодаря getattr.

    02.11.2010

    5

    Вот быстрый и грязный пример того, как класс может запускать разные версии метода сохранения в зависимости от того, в какой операционной системе он выполняется, используя 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()
    
    02.11.2010

    6

    Помимо всех замечательных ответов здесь, есть способ использовать getattr, чтобы сохранить обильные строки кода и сохранить его аккуратным. Эта мысль пришла после ужасного представления кода, которое иногда могло быть необходимостью.

    Сценарий

    Предположим, ваша структура каталогов выглядит следующим образом:

    - superheroes.py
    - properties.py
    

    И у вас есть функции для получения информации о Thor, Iron Man, Doctor Strange в superheroes.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 в нужных местах для написания более чистого кода.

    09.05.2018

    7

    Иногда я использую 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)
    

    Преимущество второго способа состоит в том, что n_calls_to_plot появляется только в том месте кода, где он используется. Это хорошо для удобочитаемости, потому что (1) вы можете сразу увидеть, с какого значения оно начинается, когда читаете, как оно используется, (2) это не отвлекает внимание от метода __init__(..), который в идеале должен быть связан с концептуальным состоянием класс, а не какой-то счетчик утилит, который используется только одним из методов функции по техническим причинам, например для оптимизации, и не имеет никакого отношения к значению объекта.

    11.06.2015

    8

    Довольно часто, когда я создаю 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.

    11.03.2016

    9

    Еще одно использование getattr () для реализации оператора switch в Python. Он использует оба отражения для получения типа дела.

    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]))
    
    28.01.2018
  • Мне нравится этот ответ, но исправьте небольшие опечатки 11.01.2020

  • 10

    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)
    
    05.12.2019

    11

    Я думаю, что этот пример не требует пояснений. Он запускает метод первого параметра, имя которого указано во втором параметре.

    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')()
    
    16.04.2020

    12

    Это также уточняется из 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'

    09.01.2019

    13

    Я пробовал в 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
    
    24.02.2020

    14

    Я получаю что-то для getattr(5,'__doc__'), но 5.__doc__ выдает ошибку, поэтому я не уверен, что они полностью эквивалентны ...

    04.06.2021

    15
  • Не могли бы вы уточнить свой ответ, добавив еще немного описания предлагаемого вами решения? 26.03.2015
  • Новые материалы

    Как создать диаграмму градиентной кисти с помощью D3.js
    Резюме: Из этого туториала Вы узнаете, как добавить градиентную кисть к диаграмме с областями в D3.js. Мы добавим градиент к значениям SVG и применим градиент в качестве заливки к диаграмме с..

    Я хотел выучить язык программирования MVC4, но не мог выучить его раньше, потому что это выглядит сложно…
    Просто начните и учитесь самостоятельно Я хотел выучить язык программирования MVC4, но не мог выучить его раньше, потому что он кажется мне сложным, и я бросил его. Это в основном инструмент..

    Лицензии с открытым исходным кодом: руководство для разработчиков и создателей
    В динамичном мире разработки программного обеспечения открытый исходный код стал мощной парадигмой, способствующей сотрудничеству, инновациям и прогрессу, движимому сообществом. В основе..

    Объяснение документов 02: BERT
    BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..


    Для любых предложений по сайту: [email protected]