Если думают блокировка вне взглядов лучше, но осторожны, если Вы заканчиваете тем, что изменили код на:
return f(...)
, Если f () нужно назвать с блокировкой, сохраненной затем, это, очевидно, должно быть в блокировке, возвраты хранения как таковые в блокировке для непротиворечивости имеет смысл.
Это может быть сложно. Из документации hasattr :
Аргументы - это объект и строка. Результатом является True, если строка является именем одного из атрибутов объекта, и False, если нет. ( Это реализуется путем вызова getattr (object, name) и проверки, вызывает ли это исключение. )
Поскольку атрибуты могут быть сгенерированы динамически методом __ getattr __
, другого способа надежно проверить их наличие нет. В вашей особой ситуации, возможно, будет достаточно явного тестирования словарей:
any('bar' in d for d in (b.__dict__, b.__class__.__dict__))
Проблема в том, что 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.)
На что, похоже, пока никто не обратил внимания, так это то, что, возможно, лучше всего не использовать hasattr ()
. Вместо этого выберите EAFP (проще просить прощения, чем разрешения).
try:
x = foo.bar
except AttributeError:
# what went in your else-block
...
else:
# what went in your if hasattr(foo, "bar") block
...
Очевидно, что это не простая замена, и вам, возможно, придется немного переставить вещи, но, возможно, это «самое приятное» решение (субъективно из конечно).
Мне любопытно, зачем вам что-то подобное. Если 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
исправление немного хакерское, но оно состоит из следующего
def hasattr(obj, name):
try:
return obj._hasattr(name) or _hasattr(obj, name)
except:
return _hasattr(obj, name)
реализовать метод класса _hasattr с помощью проверка некоторой структуры данных (например, массива), которая заполнена всеми ленивыми атрибутами names (для массива вы бы сказали: name in lazyAttrArray)
наконец-то каким-то образом Декоратор @lazyattribute добавляет элементы в какую-то структуру (например, массив, о котором мы упоминали выше), а затем, когда вы вызываете _hasattr, вы смотрите в эту структуру