Reputation: 6189
How do I write a decorator in Python, which has some import from Foo import Foo
, which is needed, when I want to use it for methods of a class, which also has this import?
Putting the import into both separate files will cause an error, telling me that Foo cannot be imported from Foo.
If it's not possible then this: Is it a good idea, if the decorator is not going to be used anywhere else, to put the decorator into the same file as the class, so that I only have to write the import once and it can't conflict with any other import?
In my real example, I want to write a decorator, which simply changes a flag, which indicates whether a list has been changed or not. Every method in that class, which modifies the list would be decorated using that decorator.
EDIT#1:
After changing the structure of my code, I now have only two participating source code files. Those are the following:
# -*- coding: utf-8 -*-
from AppSettings import AppSettings
from FileManager import FileManager
from decorators.changesvocables import changesvocables
from exceptions.DuplicateVocableException import DuplicateVocableException
from exceptions.UnknownVocableException import UnknownVocableException
__author__ = 'xiaolong'
class VocableManager:
vocables = []
search_result = []
vocables_changed = False
test_counter = 0
test_call_counter = 0
def __init__(self):
pass
@classmethod
@changesvocables
def remove_vocable(cls, vocable):
VocableManager.test_call_counter += 1
if vocable in VocableManager.vocables:
VocableManager.test_counter += 1
VocableManager.vocables.remove(vocable)
# del vocable
else:
print(vocable)
raise UnknownVocableException('Vocable not found.')
# VocableManager.vocables_changed = True
@classmethod
@changesvocables
def remove_vocable_by_index(cls, index):
del VocableManager.vocables[index]
# VocableManager.vocables_changed = True
@classmethod
@changesvocables
def add_vocable(cls, vocable):
if vocable not in VocableManager.vocables:
VocableManager.vocables.append(vocable)
else:
raise DuplicateVocableException('The vocable already exists.')
# VocableManager.vocables_changed = True
After that the class still goes on, but there are no other methods with the changesvocables
decoration. If wanted, I can add the whole class.
And the decorator:
# -*- coding: utf-8 -*-
from functools import wraps
from VocableManager import VocableManager as VocMan
__author__ = 'xiaolong'
def changesvocables(function):
@wraps(function)
def wrapper(*args, **kw):
result = function(*args, **kw)
VocMan.vocables_changed = True
return result
return wrapper
This causes the following error, when I am trying to run the application:
** (__main__.py:16991): WARNING **: Couldn't connect to accessibility bus: Failed to connect to socket /tmp/dbus-sQwlsgyRi2: Connection refused
Traceback (most recent call last):
File "/home/xiaolong/development/pycharm-workspace/gtkplus-tool/gtkplustool/__main__.py", line 1, in <module>
from Application import Application
File "/home/xiaolong/development/pycharm-workspace/gtkplus-tool/gtkplustool/Application.py", line 8, in <module>
from VocableManager import VocableManager
File "/home/xiaolong/development/pycharm-workspace/gtkplus-tool/gtkplustool/VocableManager.py", line 4, in <module>
from decorators.changesvocables import changesvocables
File "/home/xiaolong/development/pycharm-workspace/gtkplus-tool/gtkplustool/decorators/changesvocables.py", line 3, in <module>
from VocableManager import VocableManager as VocMan
ImportError: cannot import name 'VocableManager'
EDIT#3:
Here is a MCVE:
main.py:
# -*- coding: utf-8 -*-
from mcve.ListManager import ListManager
__author__ = 'xiaolong'
if __name__ == '__main__':
list_manager = ListManager()
list_manager.add_item('item1')
decorator:
# -*- coding: utf-8 -*-
from functools import wraps
from mcve.ListManager import ListManager as ListMan
__author__ = 'xiaolong'
def changesitems(function):
@wraps(function)
def wrapper(*args, **kw):
result = function(*args, **kw)
ListMan.vocables_changed = True
return result
return wrapper
ListManager:
# -*- coding: utf-8 -*-
from mcve.changesitems import changesitems
class ListManager:
list_of_items = []
def __init__(self):
pass
@changesitems
def add_item(self, item):
if item not in ListManager.list_of_items:
ListManager.add_item(item)
Same error as before:
Traceback (most recent call last):
File "/home/xiaolong/development/pycharm-workspace/MCVE/mcve/main.py", line 2, in <module>
from mcve.ListManager import ListManager
File "/home/xiaolong/development/pycharm-workspace/MCVE/mcve/ListManager.py", line 2, in <module>
from mcve.changesitems import changesitems
File "/home/xiaolong/development/pycharm-workspace/MCVE/mcve/changesitems.py", line 3, in <module>
from mcve.ListManager import ListManager as ListMan
ImportError: cannot import name 'ListManager'
Process finished with exit code 1
Upvotes: 2
Views: 1564
Reputation: 1524
Try:
from Foo import Foo as foo
Now you will have access to the package, as Foo
, and to the decorator, as foo
.
Upvotes: 2