Чтобы использовать методы и член объекта, вам сначала нужно создать этот объект. Если вы его не создали (переменная, которая должна содержать объект, не инициализируется), но вы пытаетесь использовать его методы или переменные, вы получите эту ошибку.
Иногда вы можете просто забыть инициализировать .
Отредактировано: new не может вернуть значение null, но исключение огня при ошибке. Давно это было на некоторых языках, но не больше. Спасибо @John Saunders за указание на это.
Если вы можете изменить способ вызова декораторов из
class Foo(object):
@many
@decorators
@here
def bar(self):
pass
на
class Foo(object):
@register(many,decos,here)
def bar(self):
pass
, вы можете зарегистрировать декораторы следующим образом:
def register(*decorators):
def register_wrapper(func):
for deco in decorators[::-1]:
func=deco(func)
func._decorators=decorators
return func
return register_wrapper
Например:
def many(f):
def wrapper(*args,**kwds):
return f(*args,**kwds)
return wrapper
decos = here = many
class Foo(object):
@register(many,decos,here)
def bar(self):
pass
foo=Foo()
Здесь мы обращаемся к кортежу декораторов:
print(foo.bar._decorators)
# (<function many at 0xb76d9d14>, <function decos at 0xb76d9d4c>, <function here at 0xb76d9d84>)
Здесь мы печатаем только имена декораторов:
print([d.func_name for d in foo.bar._decorators])
# ['many', 'decos', 'here']
Это невозможно, на мой взгляд. Декоратор - это не какой-то атрибут или метаданные метода. Декоратор - удобный синтаксис для замены функции результатом вызова функции. Подробнее см. http://docs.python.org/whatsnew/2.4.html?highlight=decorators#pep-318-decorators-for-functions-and-methods .
Как Фейсал отмечает , вы могли бы сами декораторы приложить метаданные к функции, но, насколько мне известно, это не делается автоматически.
Это невозможно сделать в общем виде, потому что
@foo
def bar ...
точно совпадает с
def bar ...
bar = foo (bar)
. Вы можете делать это в некоторых особых случаях, например, @staticmethod
путем анализа объектов функции, но не лучше этого.
Это потому, что декораторы являются «синтаксическим сахаром». Скажем, у вас есть следующий декоратор:
def MyDecorator(func):
def transformed(*args):
print "Calling func " + func.__name__
func()
return transformed
И вы применяете его к функции:
@MyDecorator
def thisFunction():
print "Hello!"
Это эквивалентно:
thisFunction = MyDecorator(thisFunction)
Вы могли бы встроить «историю» в объект функции, возможно, если вы контролируете декораторов. Бьюсь об заклад, есть еще один умный способ сделать это (возможно, переопределив назначение), но я не настолько хорошо разбираюсь в Python, к сожалению. : (
Я удивлен, что этот вопрос настолько старый, и никто не нашел времени, чтобы добавить фактический интроспективный способ сделать это, поэтому вот он:
Код, который вы хотите проверить .. .
def template(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
baz = template
che = template
class Foo(object):
@baz
@che
def bar(self):
pass
Теперь вы можете проверить этот класс Foo
с чем-то вроде этого ...
import ast
import inspect
def get_decorators(cls):
target = cls
decorators = {}
def visit_FunctionDef(node):
decorators[node.name] = []
for n in node.decorator_list:
name = ''
if isinstance(n, ast.Call):
name = n.func.attr if isinstance(n.func, ast.Attribute) else n.func.id
else:
name = n.attr if isinstance(n, ast.Attribute) else n.id
decorators[node.name].append(name)
node_iter = ast.NodeVisitor()
node_iter.visit_FunctionDef = visit_FunctionDef
node_iter.visit(ast.parse(inspect.getsource(target)))
return decorators
print get_decorators(Foo)
Это должно печатать что-то вроде этого ...
{'bar': ['baz', 'che']}
, или, по крайней мере, это было, когда я тестировал это с помощью Python 2.7.9, очень быстро:)
inspect.getsource()
, кажется, возвращается с пробелами перед def wrapper
, что затем дает неожиданную ошибку отступа в вызове ast.parse
.
– Jmons
19 January 2018 в 12:35
OSError: source code not available
, поэтому я подозреваю, что есть экземпляры (возможно, также bin работает), где этот процесс не будет работать. Возможно, это не сработает, если существуют бины только python?
– Jmons
19 January 2018 в 12:35
Вы не можете, по определению. Декоратор:
@dec
def foo():
return 1
является просто ярлыком для:
def foo_internal()
return 1
foo = dec(foo_internal)
Обратите внимание, что декоратор dec
- это просто какое-то вызываемое, возвращающее что-то (функция, возможно, какой-то другой вызываемый объект). Вы даже не знаете, имеет ли foo
какое-либо отношение к декорированному определению, например:
def dec(f):
def not_foo():
return 0
return not_foo
. Если вам нужно добавить дополнительную информацию о методах, классах и т. Д., Например, например. атрибуты в .NET --- просто установите для них некоторые атрибуты.
def foo()
return 1
foo.decorated = True
Или реализуйте декораторы, которые устанавливают эти атрибуты, если это действительно помогает читать.
def dec(f):
f.decorated = True
return f
Что ж. Python является открытым исходным кодом. Вы всегда можете расширить интерпретатор Python для отслеживания декораторов, применяемых к объекту. Поскольку (как показано выше) объект, возвращенный декоратором, не должен быть каким-либо образом связан с украшенным объектом, эта реализация должна будет хранить информацию от украшенного объекта до применения декоратора, применять декоратор, заменять информацию декоратора на возвращенный объект и добавлять информацию о последнем декораторе.
Можно сделать. Но я не уверен, действительно ли это полезно. И это добавляет некоторые накладные расходы для каждого декоратора. Поэтому я не ожидал такого механизма в основном Python, если только он не предоставляет некоторые другие преимущества, такие как упрощение реализации декораторов и т. Д.
import inspect
) выше. stackoverflow.com/a/31197273/1424877 Я предлагаю удалить этот ответ ... если я не пропущу что-то тонкое.
– Quuxplusone
17 April 2017 в 03:49
Вы не можете, но еще хуже, существуют библиотеки, которые помогут скрыть тот факт, что вы с самого начала украсили функцию. См. Functools или библиотеку декоратора (@decorator
, если я могу найти его) для получения дополнительной информации.