Можно ли вызвать поле моделей со строкой? Доступ к переменной-члену класса с помощью строки? [Дубликат]

В Java все переменные, которые вы объявляете, на самом деле являются «ссылками» на объекты (или примитивы), а не самими объектами.

При попытке выполнить один метод объекта , ссылка просит живой объект выполнить этот метод. Но если ссылка ссылается на NULL (ничего, нуль, void, nada), то нет способа, которым метод будет выполнен. Тогда runtime сообщит вам об этом, выбросив исключение NullPointerException.

Ваша ссылка «указывает» на нуль, таким образом, «Null -> Pointer».

Объект живет в памяти виртуальной машины пространство и единственный способ доступа к нему - использовать ссылки this. Возьмем этот пример:

public class Some {
    private int id;
    public int getId(){
        return this.id;
    }
    public setId( int newId ) {
        this.id = newId;
    }
}

И в другом месте вашего кода:

Some reference = new Some();    // Point to a new object of type Some()
Some otherReference = null;     // Initiallly this points to NULL

reference.setId( 1 );           // Execute setId method, now private var id is 1

System.out.println( reference.getId() ); // Prints 1 to the console

otherReference = reference      // Now they both point to the only object.

reference = null;               // "reference" now point to null.

// But "otherReference" still point to the "real" object so this print 1 too...
System.out.println( otherReference.getId() );

// Guess what will happen
System.out.println( reference.getId() ); // :S Throws NullPointerException because "reference" is pointing to NULL remember...

Это важно знать - когда больше нет ссылок на объект (в пример выше, когда reference и otherReference оба указывают на null), тогда объект «недоступен». Мы не можем работать с ним, поэтому этот объект готов к сбору мусора, и в какой-то момент VM освободит память, используемую этим объектом, и выделит другую.

194
задан Matthew Green 10 June 2015 в 19:22
поделиться

10 ответов

Здесь вы можете посмотреть полный пример:

Introspection может использоваться для разных целей, один из которых представлен в «Dive Into Python» - это просто способ динамически добавлять функциональность (плагин) в ваше приложение.

Динамически я имею в виду без сделать модификацию в основном приложении, чтобы добавить новую функцию.

Взяв пример «Dive Into Python» - простое приложение для извлечения атрибута из файла другого файла - вы можете добавить обработка нового формата файла без внесения изменений в исходное приложение.

Я рекомендую вам закончить книгу. Когда вы читаете, все станет более ясным.

53
ответ дан John McGehee 19 August 2018 в 03:35
поделиться
  • 1
    Я думаю, что могу понять концепцию самоанализа. Что действительно поражает меня, так это использование getattr (). Пойду ли я это лучше, если я просто буду читать дальше? – Terence Ponce 2 November 2010 в 07:01
  • 2
    Да, конечно, вы прочитали часть, которую я отправляю в качестве ссылки? у вас есть действительно конкретное использование getattr () внутри. diveintopython.org/object_oriented_framework/index.html – Alois Cochard 2 November 2010 в 07:03
  • 3
    Я еще не закончил читать. Спасибо за совет. Я приму это как ответ. – Terence Ponce 2 November 2010 в 07:08
  • 4
    Я думаю, что единственный способ полностью понять это - столкнуться с ситуацией, когда вы должны ее использовать или поддерживать. Так оно работает для меня, но я самообразован. – Alois Cochard 2 November 2010 в 07:10
  • 5
    Здесь также очень хороший ответ: bytes.com/topic/python/answers/832252-setattr-getattr-when-use – Josh Brown 23 November 2013 в 04:45

Довольно часто, когда я создаю файл 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 19 August 2018 в 03:35
поделиться

Я иногда использую 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__(..), который в идеале должен быть о концептуальном состоянии класса, а не некоторый счетчик коммунальных услуг, который используется только одним из методов функции по техническим причинам, таким как оптимизация, и не имеет ничего общего со значением объекта.

3
ответ дан Evgeni Sergeev 19 August 2018 в 03:35
поделиться

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

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]))
1
ответ дан hoefling 19 August 2018 в 03:35
поделиться

Вот быстрый и грязный пример того, как класс может запускать разные версии метода сохранения, в зависимости от того, какую операционную систему он выполняет при использовании 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()
12
ответ дан Josh Purvis 19 August 2018 в 03:35
поделиться
# 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 19 August 2018 в 03:35
поделиться
  • 1
    Не могли бы вы подробнее рассказать о своем решении, добавив немного подробного описания вашего решения? – abarisone 26 March 2015 в 14:30
  • 2
    да добавить другое объяснение другое удалить свой ответ – Para M 12 March 2018 в 10:40

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

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

Например , вы не можете этого сделать:

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

, поскольку x не относится к типу «builtin», а «str». Однако вы можете это сделать:

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

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

72
ответ дан NuclearPeon 19 August 2018 в 03:35
поделиться

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

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

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

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

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

40
ответ дан Robert Rossney 19 August 2018 в 03:35
поделиться
  • 1
    +1 для указания "отображения данных в функции" – Philip007 13 October 2012 в 19:53

Помимо всех удивительных ответов здесь есть способ использовать 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 в правильных местах, чтобы писать более чистый код.

4
ответ дан unixia 19 August 2018 в 03:35
поделиться

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

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

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

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

, если

attr_name = 'gender'

, вместо записи

gender = person.gender

вы можете write

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, если атрибут с заданным именем не существует в object:

>>> 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 , имеется setattr , что позволяет вам установить атрибут объекта, имеющего его имя:

>>> setattr(person, 'name', 'Andrew')
>>> person.name  # accessing instance attribute
'Andrew'
>>> Person.name  # accessing class attribute
'Victor'
>>>
225
ответ дан warvariuc 19 August 2018 в 03:35
поделиться
  • 1
    Поэтому мне кажется, что getattr(..) следует использовать в двух сценариях: 1. когда имя атрибута является значением внутри переменной (например, getattr(person, some_attr)) и 2. когда нам нужно использовать третий позиционный аргумент для значения по умолчанию значение (например, getattr(person, 'age', 24)). Если я вижу сценарий, подобный getattr(person, 'age'), мне кажется, что он идентичен person.age, что заставляет меня думать, что person.age более Pythonic. Это верно? – wpcarro 24 October 2016 в 22:01
  • 2
    @wpcarro да, правильно – warvariuc 14 August 2018 в 06:09
Другие вопросы по тегам:

Похожие вопросы: