# Customizing Attribute Access

## Hooking `__getattr__()`

The __getattr__ method works pretty much the same for persistent classes as it does for other classes. No special handling is needed. If an object is a ghost, then it will be activated before __getattr__ is called.

In this example, our objects returns a tuple with the attribute name, converted to upper case and the value of _p_changed, for any attribute that isn’t handled by the default machinery.

    >>> from persistent.tests.attrhooks import OverridesGetattr
    >>> o = OverridesGetattr()
    >>> o._p_changed
    False
    >>> o._p_oid
    >>> o._p_jar
    >>> o.spam
    ('SPAM', False)
    >>> o.spam = 1
    >>> o.spam
    1

We’ll save the object, so it can be deactivated:

    >>> from persistent.tests.attrhooks import _resettingJar
    >>> jar = _resettingJar()
    >>> jar.add(o)
    >>> o._p_deactivate()
    >>> o._p_changed

And now, if we ask for an attribute it doesn’t have,

    >>> o.eggs
    ('EGGS', False)

And we see that the object was activated before calling the `__getattr__()` method.

## Hooking All Access

In this example, we’ll provide an example that shows how to override the `__getattribute__()`, `__setattr__()`, and `__delattr__()` methods. We’ll create a class that stores it’s attributes in a secret dictionary within the instance dictionary.

The class will have the policy that variables with names starting with `tmp_` will be volatile.

Our sample class takes initial values as keyword arguments to the constructor:

    >>> from persistent.tests.attrhooks import VeryPrivate
    >>> o = VeryPrivate(x=1)

### Hooking `__getattribute__`()`

The `__getattribute__()` method is called for all attribute accesses. It overrides the attribute access support inherited from Persistent.

    >>> o._p_changed
    False
    >>> o._p_oid
    >>> o._p_jar
    >>> o.x
    1
    >>> o.y
    Traceback (most recent call last):
    ...
    AttributeError: y

Next, we’ll save the object in a database so that we can deactivate it:

    >>> from persistent.tests.attrhooks import _rememberingJar
    >>> jar = _rememberingJar()
    >>> jar.add(o)
    >>> o._p_deactivate()
    >>> o._p_changed

And we’ll get some data:

    >>> o.x
    1

which activates the object:

    >>> o._p_changed
    False

It works for missing attribes too:

    >>> o._p_deactivate()
    >>> o._p_changed

    >>> o.y
    Traceback (most recent call last):
    ...
    AttributeError: y

    >>> o._p_changed
    False

### Hooking `__setattr__`()`

The `__setattr__()` method is called for all attribute assignments. It overrides the attribute assignment support inherited from Persistent.

Implementors of `__setattr__()` methods:

1. Must call Persistent._p_setattr first to allow it to handle some attributes and to make sure that the object is activated if necessary, and
2. Must set _p_changed to mark objects as changed.

    >>> o = VeryPrivate()
    >>> o._p_changed
    False
    >>> o._p_oid
    >>> o._p_jar
    >>> o.x
    Traceback (most recent call last):
    ...
    AttributeError: x

    >>> o.x = 1
    >>> o.x
    1

Because the implementation doesn’t store attributes directly in the instance dictionary, we don’t have a key for the attribute:

    >>> 'x' in o.__dict__
    False

Next, we’ll give the object a “remembering” jar so we can deactivate it:

    >>> jar = _rememberingJar()
    >>> jar.add(o)
    >>> o._p_deactivate()
    >>> o._p_changed

We’ll modify an attribute

    >>> o.y = 2
    >>> o.y
    2

which reactivates it, and markes it as modified, because our implementation marked it as modified:

    >>> o._p_changed
    True

Now, if fake a commit:

    >>> jar.fake_commit()
    >>> o._p_changed
    False

And deactivate the object:

    >>> o._p_deactivate()
    >>> o._p_changed

and then set a variable with a name starting with `tmp_`, The object will be activated, but not marked as modified, because our `__setattr__()` implementation doesn’t mark the object as changed if the name starts with `tmp_`:

    >>> o.tmp_foo = 3
    >>> o._p_changed
    False
    >>> o.tmp_foo
    3

### Hooking `__delattr__`()`

The __delattr__ method is called for all attribute deletions. It overrides the attribute deletion support inherited from Persistent.

Implementors of `__delattr__()` methods:

1. Must call Persistent._p_delattr first to allow it to handle some attributes and to make sure that the object is activated if necessary, and
2. Must set _p_changed to mark objects as changed.

    >>> o = VeryPrivate(x=1, y=2, tmp_z=3)
    >>> o._p_changed
    False
    >>> o._p_oid
    >>> o._p_jar
    >>> o.x
    1
    >>> del o.x
    >>> o.x
    Traceback (most recent call last):
    ...
    AttributeError: x

Next, we’ll save the object in a jar so that we can deactivate it:

    >>> jar = _rememberingJar()
    >>> jar.add(o)
    >>> o._p_deactivate()
    >>> o._p_changed

If we delete an attribute:

    >>> del o.y

The object is activated. It is also marked as changed because our implementation marked it as changed.

    >>> o._p_changed
    True
    >>> o.y
    Traceback (most recent call last):
    ...
    AttributeError: y

    >>> o.tmp_z
    3

Now, if fake a commit:

    >>> jar.fake_commit()
    >>> o._p_changed
    False

And deactivate the object:

    >>> o._p_deactivate()
    >>> o._p_changed

and then delete a variable with a name starting with `tmp_`, The object will be activated, but not marked as modified, because our `__delattr__()` implementation doesn’t mark the object as changed if the name starts with `tmp_`:

    >>> del o.tmp_z
    >>> o._p_changed
    False
    >>> o.tmp_z
    Traceback (most recent call last):
    ...
    AttributeError: tmp_z