2015-05-28 5 views
2

Итак, я пытаюсь научиться использовать декораторы Python (2.x), и, столкнувшись с ними, я столкнулся ... странно. Подводя итог, я думаю, что я пытаюсь использовать декоратор, чтобы добавить украшенную функцию в хранилище где-то еще.Python: Decorators, scoping и module import

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

Предположим, у меня есть модуль (что я бегу как сценарий), как это:

# -*- coding: utf-8 -*- 
# main.py 

d = {} 
b = [] 
def mydecorator(name): 
    b.append(name) 
    def decorator(fun): 
     d[name] = fun 
     print 'in here', d, b 
     return fun 
    print 'and here', d, b 
    return decorator 

class SomeClass: 
    @mydecorator('a thing') 
    def working_func(self, params): 
     # do stuff 
     pass 

def main(): 
    # do stuff 
    print 'out there', d, b 


if __name__ == '__main__': 
    main() 

печать, как и ожидалось:

and here {} ['a thing'] 
in here {'a thing': <function working_func at 0x7fd6b69e0758>} ['a thing'] 
out there {'a thing': <function working_func at 0x7fd6b69e0758>} ['a thing'] 

Однако, если я перееду класс в отдельный модуль

# -*- coding: utf-8 -*- 
# module.py 

from main import mydecorator 

class AnotherClass: 
    @mydecorator('boo') 
    def not_workin_func(self, params): 
     # do stuff 
     pass 

и импортировать его в main.py

# -*- coding: utf-8 -*- 
# main.py 
import module 

d = {} 
b = [] 
def mydecorator(name): 
    b.append(name) 
    def decorator(fun): 
     d[name] = fun 
     print 'in here', d, b 
     return fun 
    print 'and here', d, b 
    return decorator 

def main(): 
    # do stuff 
    print 'out there', d, b 


if __name__ == '__main__': 
    main() 

изменения в списке и Словаре не сохраняются:

and here {} ['boo'] 
in here {'boo': <function not_workin_func at 0x7fd1009917d0>} ['boo'] 
out there {} [] 

Я полагаю, что это что-то делать с тем, как импорт питона ручки обзорное/модуля?

+3

У вас есть круговой импорт, из-за которого очень сложно разобраться - попробуйте переместить mydecorator из 'main.py' в' module.py' или другой модуль. –

+0

Спасибо, перемещая все предметы декоратора в другой модуль (в том смысле, что если я тогда, например, импортирую 'b',' d' в 'main.py', они имеют то же содержимое, что и в первом случае). Итак, основная проблема заключается в круговом импорте? – kekkonen

ответ

1

Проблема заключается в циклическом импорте, а словарь d и список b заменяются пустым списком после инициализации module.

Вы можете увидеть порядок выполнения, добавив некоторые операторы печати:

module.py:

# -*- coding: utf-8 -*- 
# module.py 
print(' module - init') 

print(' module - importing from main') 
from main import mydecorator 
#import main 


print(' module - definiting class') 
class AnotherClass: 
    @mydecorator('boo') 
    def not_workin_func(self, params): 
     # do stuff 
     pass 

main.py:

# -*- coding: utf-8 -*- 
# main.py 

print('main - importing module') 
import module 

print('main - making empty d,b') 
d = {} 
b = [] 

print('main - definiting mydecorator') 
def mydecorator(name): 
    b.append(name) 
    def decorator(fun): 
     d[name] = fun 
     print 'in here', d, b 
     return fun 
    print 'and here', d, b 
    return decorator 

print('main - defining main') 
def main(): 
    # do stuff 
    print 'out there', d, b 

if __name__ == '__main__': 
    print('main - running main') 
    main() 

Теперь при запуске python main.py вы можете Посмотрите, что произойдет в каком порядке:

main - importing module 
    module - init 
    module - importing from main 
main - importing module 
main - making empty d,b 
main - definiting mydecorator 
main - defining main 
    module - definiting class 
and here {} ['boo'] 
in here {'boo': <function not_workin_func at 0x100ca4aa0>} ['boo'] 
main - making empty d,b 
main - definiting mydecorator 
main - defining main 
main - running main 
out there {} [] 

Вы можете видеть, что d и b были переназначены пустым списком и словарями после декоратор был применен в определении класса.

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