Ленивые атрибуты Python, которые не делают оценки на hasattr ()

Если думают блокировка вне взглядов лучше, но осторожны, если Вы заканчиваете тем, что изменили код на:

return f(...)

, Если f () нужно назвать с блокировкой, сохраненной затем, это, очевидно, должно быть в блокировке, возвраты хранения как таковые в блокировке для непротиворечивости имеет смысл.

5
задан Tim Dumol 17 August 2009 в 07:15
поделиться

5 ответов

Это может быть сложно. Из документации hasattr :

hasattr (object, name)

Аргументы - это объект и строка. Результатом является True, если строка является именем одного из атрибутов объекта, и False, если нет. ( Это реализуется путем вызова getattr (object, name) и проверки, вызывает ли это исключение. )

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

any('bar' in d for d in (b.__dict__, b.__class__.__dict__))
4
ответ дан 15 December 2019 в 01:07
поделиться

Проблема в том, что hasattr использует getattr , поэтому ваш атрибут всегда будет оцениваться, когда вы используете hasattr . Если вы разместите код для своей магии lazyattribute , надеюсь, кто-нибудь может предложить альтернативный способ проверки наличия атрибута, который не требует hasattr или getattr . См. Справку для hasattr :

>>> help(hasattr)
Help on built-in function hasattr in module __builtin__:

hasattr(...)
    hasattr(object, name) -> bool

    Return whether the object has an attribute with the given name.
    (This is done by calling getattr(object, name) and catching exceptions.)
0
ответ дан 15 December 2019 в 01:07
поделиться

На что, похоже, пока никто не обратил внимания, так это то, что, возможно, лучше всего не использовать hasattr () . Вместо этого выберите EAFP (проще просить прощения, чем разрешения).

try:
    x = foo.bar
except AttributeError:
    # what went in your else-block
    ...
else:
    # what went in your if hasattr(foo, "bar") block
    ...

Очевидно, что это не простая замена, и вам, возможно, придется немного переставить вещи, но, возможно, это «самое приятное» решение (субъективно из конечно).

2
ответ дан 15 December 2019 в 01:07
поделиться

Мне любопытно, зачем вам что-то подобное. Если hasattr в конечном итоге вызывает вашу «вычислительную функцию», то пусть будет так. Насколько ленивым должно быть ваше свойство в любом случае?

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

import inspect

class lazyattribute(object):
    def __init__(self, func):
        self.func = func

    def __get__(self, obj, kls=None):
        if obj is None or inspect.stack()[1][4][0].startswith('hasattr'):
            return None
        value = self.func(obj)
        setattr(obj, self.func.__name__, value)
        return value

class Foo(object):
    @lazyattribute
    def bar(self):
        return 42
0
ответ дан 15 December 2019 в 01:07
поделиться

исправление немного хакерское, но оно состоит из следующего

  1. переименовать hasattr (скажем, как _hasattr)
  2. переиндексировать hasattr следующим образом:


   def hasattr(obj, name):
     try:
       return obj._hasattr(name) or _hasattr(obj, name)
     except:
       return _hasattr(obj, name)
  1. реализовать метод класса _hasattr с помощью проверка некоторой структуры данных (например, массива), которая заполнена всеми ленивыми атрибутами names (для массива вы бы сказали: name in lazyAttrArray)

  2. наконец-то каким-то образом Декоратор @lazyattribute добавляет элементы в какую-то структуру (например, массив, о котором мы упоминали выше), а затем, когда вы вызываете _hasattr, вы смотрите в эту структуру

    • , это шаг, который я не совсем уверен, как вы бы реализовали потому что я не работал над созданием собственных декораторов
-2
ответ дан 15 December 2019 в 01:07
поделиться
Другие вопросы по тегам:

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