I'm fairly new to Python. In programming a lot of PHP recently I got used to some creative use of __get and __set "magic" methods. These were only called when a public variable of the class wasn't present.
I'm trying to replicate the same behavior in Python, but seem to be failing miserably. Given there doesn't seem to be a way to actually define class variables in a C++/PHP way, when I try to use variables normally within my class (i.e. via self) it ends up calling __getattr__!
How do I define attributes of my class that I don't want affected by __getattr__?
Some sample code of what I'm trying to do is below, where I'd want self.Document and self.Filename NOT to invoke __getattr__.
Thanks for the help!
class ApplicationSettings(object):
RootXml = '<?xml version="1.0"?><Settings></Settings>'
def __init__(self):
self.Document = XmlDocument()
self.Document.LoadXml(RootXml)
def Load(self, filename):
self.Filename = filename
self.Document.Load(filename)
def Save(self, **kwargs):
# Check if the filename property is present
if 'filename' in kwargs:
self.Filename = kwargs['filename']
self.Document.Save(self.Filename)
def __getattr__(self, attr):
return self.Document.Item['Settings'][attr].InnerText
def __setattr__(self, attr, value):
if attr in self.Document.Item['Settings']:
# If the setting is already in the XML tree then simply change its value
self.Document.Item['Settings'][attr].InnerText = value
else:
# Setting is not in the XML tree, create a new element and add it
element = self.Document.CreateElement(attr)
element.InnerText = value
self.Document.Item['Settings'].AppendChild(element)
__getattr__ is only invoked when Python cannot find the attribute in the instance itself or in any of its base classes. The simple solution is to add Document and Filename to the class so it is found.
class ApplicationSettings(object):
Document = None
Filename = None
RootXml = '<?xml version="1.0"?><Settings></Settings>'
...
What you really need here is a descriptor. Hooking __getattr__ and __setattr__ like that is not really recommended method.
I would use Properties. Using the #property decorator makes it looks even nicer.
class C(object):
def __init__(self):
self._x = None
#property
def x(self):
"""I'm the 'x' property."""
return self._x
#x.setter
def x(self, value):
self._x = value
#x.deleter
def x(self):
del self._x
You can then access C.x and it will automatically call the getter for x, and automatically call the setter for x when you assign to C.x.
Apparently if I check for the attribute name in __setattr__ I can then call object's __setattr__ for the attributes I want to use normally. This feels pretty hoaky, but works.
def __setattr__(self, attr, value):
# Check for attributes we want to store normally
if attr == 'Document' or attr == 'Filename':
object.__setattr__(self, attr, value)
# If the setting is already in the XML tree then simply change its value
elif attr in self.Document.Item['Settings']:
self.Document.Item['Settings'][attr].InnerText = value
# Setting is not in the XML tree, create a new element and add it
else:
element = self.Document.CreateElement(attr)
element.InnerText = value
self.Document.Item['Settings'].AppendChild(element)
Related
I want to define a class containing read and write methods, which can be called as follows:
instance.read
instance.write
instance.device.read
instance.device.write
To not use interlaced classes, my idea was to overwrite the __getattr__ and __setattr__ methods and to check, if the given name is device to redirect the return to self. But I encountered a problem giving infinite recursions. The example code is as follows:
class MyTest(object):
def __init__(self, x):
self.x = x
def __setattr__(self, name, value):
if name=="device":
print "device test"
else:
setattr(self, name, value)
test = MyTest(1)
As in __init__ the code tried to create a new attribute x, it calls __setattr__, which again calls __setattr__ and so on. How do I need to change this code, that, in this case, a new attribute x of self is created, holding the value 1?
Or is there any better way to handle calls like instance.device.read to be 'mapped' to instance.read?
As there are always questions about the why: I need to create abstractions of xmlrpc calls, for which very easy methods like myxmlrpc.instance,device.read and similar can be created. I need to 'mock' this up to mimic such multi-dot-method calls.
You must call the parent class __setattr__ method:
class MyTest(object):
def __init__(self, x):
self.x = x
def __setattr__(self, name, value):
if name=="device":
print "device test"
else:
super(MyTest, self).__setattr__(name, value)
# in python3+ you can omit the arguments to super:
#super().__setattr__(name, value)
Regarding the best-practice, since you plan to use this via xml-rpc I think this is probably better done inside the _dispatch method.
A quick and dirty way is to simply do:
class My(object):
def __init__(self):
self.device = self
Or you can modify self.__dict__ from inside __setattr__():
class SomeClass(object):
def __setattr__(self, name, value):
print(name, value)
self.__dict__[name] = value
def __init__(self, attr1, attr2):
self.attr1 = attr1
self.attr2 = attr2
sc = SomeClass(attr1=1, attr2=2)
sc.attr1 = 3
You can also use object.
class TestClass:
def __init__(self):
self.data = 'data'
def __setattr__(self, name, value):
print("Attempt to edit the attribute %s" %(name))
object.__setattr__(self, name, value)
or you can just use #property:
class MyTest(object):
def __init__(self, x):
self.x = x
#property
def device(self):
return self
If you don't want to specify which attributes can or cannot be set, you can split the class to delay the get/set hooks until after initialization:
class MyTest(object):
def __init__(self, x):
self.x = x
self.__class__ = _MyTestWithHooks
class _MyTestWithHooks(MyTest):
def __setattr__(self, name, value):
...
def __getattr__(self, name):
...
if __name__ == '__main__':
a = MyTest(12)
...
As noted in the code you'll want to instantiate MyTest, since instantiating _MyTestWithHooks will result in the same infinite recursion problem as before.
I have a need to inspect attributes before they are set†. A naive implementation would be something like:
class C(object):
x = 5
def __setattr__(self, name, value):
if hasattr(self, name):
x = getattr(self, name)
if x == 5:
print 'do something'
object.__setattr__(self, name , value)
However, this would trigger the class' __getattribute__ method, which must be avoid here. From what i can tell, searching in the class' __dict__ directly might do the trick; but as this is a class that's meant to be subclassed by the user, i imagine that __slots__ and the MRO could add complications down the road.
Given these considerations, what's the best way to inspect an attribute before setting it?
† In the interest of full disclosure, this class is actually going to be written as a C extension; however, i don't imagine the strategy deviating too much from the python implementation for that to matter.
How about using the property decorator?
class C(object):
def __init__(self):
self._x = 5 # Default, for all
# Future updates should be done with self.x = ...
# To go through the approval below
#property
def x(self):
return self._x
#x.setter
def x(self, value):
if value == 5:
print 'do something'
else:
self._x = value
Is it possible in Python to get the name of property currently being accessed, modified for deleted inside the function? For example, I've got this code with some pseudo-code inside:
class C(object):
def __init__(self):
self._x = None
#property
def x(self):
"""I'm the 'x' property."""
prop = get_current_property() #prop is set to 'x'
return self._x
#x.setter
def x(self):
"""I'm the 'x' property."""
prop = get_current_property() #prop is set to 'x'
return self._x
#property
def y(self):
"""I'm the 'x' property."""
prop = get_current_property() #prop is set to 'y'
return self._x
So the pseudo-code here is the get_current_property(), which should work inside of the getter, setter and deleter methods for each property. Any way to do this?
So, there is no way to make it easy and sexy. Only dirty-inspecty magic, my friend.
import inspect
class A(object):
#property
def b(self):
print inspect.stack()[0][3]
A().b
will give you result you want, but you should do it only if there is no way you can deal with your things.
Btw, you can try to make a decorator, which will take a function, take its __name__ and send it as argument.
Here is implementation of idea:
def named_property(func):
return property(lambda *a, **kwa: func(*a, fname=func.__name__, **kwa))
class A(object):
#named_property
def b(self, fname):
print fname
A().b # will print 'b'
As #Martijn Pieters said, there is no straightforward way for the method to get a reference to itself.
I'm trying to understand why the property definition (written by you) wouldn't already know its own name. I'm guessing that you want to do this so that you can create a bunch of properties programmatically without a separate explicit defitinition for each one.
Try something like this to build a new class dynamically while creating some of its properties from a list:
def make_getter_setter(name):
# this function uses an implicit closure to "freeze" the local value of name
# within the scope of the getter/setter functions
def getter(self):
return name
def setter(self):
pass # your original code doesn't make clear that the setter should actually do anything
return getter, setter
class C(object):
def __init__(self):
# dictionary to store the values of the properties
# this doesn't do anything now, but I presume you'll want to allow
# setting the properties later, and you'll need somewhere to store
# their values
self._properties = {}
for name in ('spam', 'eggs', 'ham'):
getter, setter = make_getter_setter(name)
setattr(C, name, property(getter, setter, doc="I'm the '%s' property" % name))
foo = C()
print foo.eggs, foo.ham # shows their values
help(foo) # shows their doc strings
I'm just getting to grips with decorators in Python and using them to add callbacks to some instance variables using the following simple pattern:
class A(object):
def __init__(self):
self._var = 0
self.var_callbacks = []
#property
def var(self):
return self._var
#var.setter
def var(self, x):
self._var = x
for f in self.var_callbacks:
f(x)
The property decorator is a neat way of allowing me to introduce callbacks where necessary without changing the class interface. However, after the third or fourth variable it's making the code a bit repetitive.
Is there a way to refactor this pattern into something along the following:
class A(object):
def __init__(self):
self.var = 0
enable_callback(self, 'var', 'var_callbacks')
You'll need to set the property on the class (since it is a descriptor), so using a enable_callback call in the initializer is not going to work.
You could use a class decorator to set the properties from a pattern:
def callback_properties(callbacks_attribute, *names):
def create_callback_property(name):
def getter(self):
return getattr(self, '_' + name)
def setter(self, value):
setattr(self, '_' + name, value)
for f in getattr(self, callbacks_attribute):
f(value)
return property(getter, setter)
def add_callback_properties(cls):
for name in names:
setattr(cls, name, create_callback_property(name)
return cls
return add_callback_properties
Then use that as:
#add_callback_properties('var_callbacks', 'var1', 'var2')
class A(object):
# everything else
Have a look at the Python descriptor protocol. In essence, you can define a class that handles the getting, setting and deleting of a property. So you could define a descriptor that runs your callbacks on setting the attribute.
Descriptors are regular classes, and can be parameterized. So you could implement a descriptor that takes the destination variable its constructor. Something like the following:
class A(object):
var = CallbackDescriptor('var')
foo = CallbackDescriptor('foo')
Situation
Similar to this question, I want to replace a property. Unlike that question, I do not want to override it in a sub-class. I want to replace it in the init and in the property itself for efficiency, so that it doesn't have to call a function which calculates the value each time the property is called.
I have a class which has a property on it. The constructor may take the value of the property. If it is passed the value, I want to replace the property with the value (not just set the property). This is because the property itself calculates the value, which is an expensive operation. Similarly, I want to replace the property with the value calculated by the property once it has been calculated, so that future calls to the property do not have to re-calculate:
class MyClass(object):
def __init__(self, someVar=None):
if someVar is not None: self.someVar = someVar
#property
def someVar(self):
self.someVar = calc_some_var()
return self.someVar
Problem
The above code does not work because doing self.someVar = does not replace the someVar function. It tries to call the property's setter, which is not defined.
Potential Solution
I know I can achieve the same thing in a slightly different way as follows:
class MyClass(object):
def __init__(self, someVar=None):
self._someVar = someVar
#property
def someVar(self):
if self._someVar is None:
self._someVar = calc_some_var()
return self._someVar
This will be marginally less efficient as it will have to check for None every time the property is called. The application is performance critical, so this may or may not be good enough.
Question
Is there a way to replace a property on an instance of a class? How much more efficient would it be if I was able to do this (i.e. avoiding a None check and a function call)?
What you are looking for is Denis Otkidach's excellent CachedAttribute:
class CachedAttribute(object):
'''Computes attribute value and caches it in the instance.
From the Python Cookbook (Denis Otkidach)
This decorator allows you to create a property which can be computed once and
accessed many times. Sort of like memoization.
'''
def __init__(self, method, name=None):
# record the unbound-method and the name
self.method = method
self.name = name or method.__name__
self.__doc__ = method.__doc__
def __get__(self, inst, cls):
# self: <__main__.cache object at 0xb781340c>
# inst: <__main__.Foo object at 0xb781348c>
# cls: <class '__main__.Foo'>
if inst is None:
# instance attribute accessed on class, return self
# You get here if you write `Foo.bar`
return self
# compute, cache and return the instance's attribute value
result = self.method(inst)
# setattr redefines the instance's attribute so this doesn't get called again
setattr(inst, self.name, result)
return result
It can be used like this:
def demo_cache():
class Foo(object):
#CachedAttribute
def bar(self):
print 'Calculating self.bar'
return 42
foo=Foo()
print(foo.bar)
# Calculating self.bar
# 42
Notice that accessing foo.bar subsequent times does not call the getter function. (Calculating self.bar is not printed.)
print(foo.bar)
# 42
foo.bar=1
print(foo.bar)
# 1
Deleting foo.bar from foo.__dict__ re-exposes the property defined in Foo.
Thus, calling foo.bar again recalculates the value again.
del foo.bar
print(foo.bar)
# Calculating self.bar
# 42
demo_cache()
The decorator was published in the Python Cookbook and can also be found on ActiveState.
This is efficient because although the property exists in the class's __dict__, after computation, an attribute of the same name is created in the instance's __dict__. Python's attribute lookup rules gives precedence to the attribute in the instance's __dict__, so the property in class becomes effectively overridden.
Sure, you can set the attribute in the private dictionary of the class instance, which takes precedence before calling the property function foo (which is in the static dictionary A.__dict__)
class A:
def __init__(self):
self._foo = 5
self.__dict__['foo'] = 10
#property
def foo(self):
return self._foo
assert A().foo == 10
If you want to reset again to work on the property, just del self.__dict__['foo']
class MaskingProperty():
def __init__(self, fget=None, name=None, doc=None):
self.fget = fget
if fget is not None:
self.name = fget.__name__
self.__doc__ = doc or fget.__doc__
def __call__(self, func):
self.fget = func
self.name = func.__name__
if not self.__doc__:
self.__doc__ = func.__doc__
return self
def __get__(self, instance, cls):
if instance is None:
return self
if self.fget is None:
raise AttributeError("seriously confused attribute <%s.%s>" % (cls, self.name))
result = self.fget(instance)
setattr(instance, self.name, result)
return result
This is basically the same as Denis Otkidach's CachedAttribute, but slightly more robust in that it allows either:
#MaskingProperty
def spam(self):
...
or
#MaskingProperty() # notice the parens! ;)
def spam(self):
...
You can change what code a function has by replacing the functions's __code__object with the __code__ object from another function.
Here is a decorator function that I created to do just that for you. Feel free to modify it as you see fit. The big thing to remember though is that the both functions need to have the same number of 'free variables' to be swapped like this. This can easily be done by using nonlocal to force it (as shown below).
NULL = object()
def makeProperty(variable = None, default = NULL, defaultVariable = None):
"""Crates a property using the decorated function as the getter.
The docstring of the decorated function becomes the docstring for the property.
variable (str) - The name of the variable in 'self' to use for the property
- If None: uses the name of 'function' prefixed by an underscore
default (any) - What value to initialize 'variable' in 'self' as if it does not yet exist
- If NULL: Checks for a kwarg in 'function' that matches 'defaultVariable'
defaultVariable (str) - The name of a kwarg in 'function' to use for 'default'
- If None: Uses "default"
Note: this must be a kwarg, not an arg with a default; this means it must appear after *
___________________________________________________________
Example Use:
class Test():
#makeProperty()
def x(self, value, *, default = 0):
'''Lorem ipsum'''
return f"The value is {value}"
test = Test()
print(test.x) #The value is 0
test.x = 1
print(test.x) #The value is 1
Equivalent Use:
#makeProperty(defaultVariable = "someKwarg")
def x(self, value, *, someKwarg = 0):
Equivalent Use:
#makeProperty(default = 0)
def x(self, value):
___________________________________________________________
"""
def decorator(function):
_variable = variable or f"_{function.__name__}"
if (default is not NULL):
_default = default
elif (function.__kwdefaults__ is not None):
_default = function.__kwdefaults__.get(defaultVariable or "default")
else:
_default = None
def fget(self):
nonlocal fget_runOnce, fget, fset, _default #Both functions must have the same number of 'free variables' to replace __code__
return getattr(self, _variable)
def fget_runOnce(self):
if (not hasattr(self, _variable)):
fset(self, _default)
fget_runOnce.__code__ = fget.__code__
return getattr(self, _variable)
def fset(self, value):
setattr(self, _variable, function(self, value))
def fdel(self):
delattr(self, _variable)
return property(fget_runOnce, fset, fdel, function.__doc__)
return decorator