Reputation: 59624
__getattr__
and __setattr__
works well when i get or set an object's attributes using dot notation.
How do i intercept getting and setting module global variables from inside the module?
I subclass module type:
from types import ModuleType
class WUserModule(ModuleType):
def __init__(self, name):
super().__init__(name)
def __setattr__(self, name, value):
if name in self.__dict__:
super().__setattr__(name, value)
return
print('Set name {}, value {}'.format(name, str(value)))
def __getattr__(self, name):
print('Get name {}'.format(name))
Create an empty module and load code into it:
module = WUserModule('form_module')
with open('user_module.py', 'r', encoding='utf8') as f:
exec(f.read(), module.__dict__)
The code loaded from user_module.py
:
a=1
print(a)
I need somehow to intercept access to variable a
. In loaded code there is expected access to some variables which do not exist in module globals()
and i want to substitute requested values.
UPDATE:
The code above doesn't work as i need: access to variable a
is not reflected by print
.
I am using PyQt4 to write a 'platform', where other users (programmers) add forms and modules which handle interaction with these forms. The form itself is accessible in user module via 'injected' variable form
. I want to give users possibility to access values from form widgets and a simpler way. Instead of writing if form.myCheckbox.isChecked()
or form.myCheckbox.setChecked(myValue)
i want to provide the a shortcut: if myCheckbox
and myCheckbox = myValue
, intercepting values access and making needed work in the background:
def __getattr__(self, name):
formWidget = getatttr(form, name)
if isinstance(formWidget, QLineEdit):
formWidget.setText(value)
...
Upvotes: 3
Views: 1578
Reputation: 11
this works:
assignments = {}
# extending dict class
class WUserModule(dict):
def __init__(self, dict):
self.__dict__ = globals() | dict # to support of import statements inside exec
def __setitem__(self, key, value):
self.__dict__[key] = value
print(f"new assinment {key} = {value}")
assignments[key] = value
def __getitem__(self, key): # without this method doesn't work - don't know why ;)
return self.__dict__[key]
# initial values if needed
input_vars_dict={"a":0}
module = WUserModule(input_vars_dict)
with open('user_module.py', 'r', encoding='utf8') as f:
exec(f.read(), module)
# assignments filled with all assignment that happpened
print(assignments)
userland module:
print("user_module.py")
print(a)
a=1
b=2
output:
user_module.py
0
new assinment a = 1
new assinment b = 2
{'a': 1, 'b': 2}
Upvotes: 0
Reputation: 156198
You can't.
The basic problem is that attribute overloads only work when you are accessing an attribute, specifically that means:
expr . ident
Without the dot, there can be no attribute overload. Thus, no matter what you do, a sequence like
a
Can never invoke an attribute overload, no matter what else may equate to the value of a
.
Upvotes: 2
Reputation: 21055
What you're trying to do can't be done in the general case. You can't have an attribute both have a value and an attribute. You can either do form.myCheckbox = True
and bool(form.myCheckbox)
, or form.myCheckbox.setChecked(True)
and bool(form.myCheckbox.isChecked())
, not both. I mean, form.myCheckbox
can't be True
and a QCheckbox
object at the same time. You could make it work for bool
, int
and unicode
can be handled but inconveniently, while other types are generally impossible.
Other than that, you're confused about what __getattr__
does. It's not called for attributes that exist, __getattribute__
is. But using __getattribute__
is complicated, you might want to make your checkboxes descriptors or use properties, but then you'd have to give up on modules and use classes.
P.S. Why is form a module, and not an instance of some object?
Upvotes: 0