Pythonic alias for instance variable? - python

I have a class in which I store data in a list for inheritance reasons. I would like to know, and I have done my share of googling, is there a cleaner way other than creating getter/setter functions and properties to give a alias to the element in this list?
For example...
class Serializable(object):
"""Adds serialization to from binary string"""
def encode(self):
"""Pack into struct"""
return self.encoder.pack(*self)
def decode(self, data_str):
"""Unpack from struct"""
self.data = self.encoder.unpack(data_str)
return self.data
class Ping(Serializable):
encoder = Struct("!16sBBBL")
def __init__(self, ident=create_id(), ttl=TTL, hops=0, length=0):
self.data = [ident, 1, ttl, hops, length]
self.ident = property(self.data[0])
def __getitem__(self, index):
return self.data[index]
#property
def ident(self):
return self.data[0]
#ident.setter
def ident(self, value):
self.data[0] = value
#property
def protocol(self):
return self.data[1]
#protocol.setter
def protocol(self, protocol):
self.data[1]
I would prefer a more compact solution to reference object.ident while maintaining the ability to pack and unpack as above.

If you store your values/properties in a dictionary instead:
def __init__(self, ident=create_id(), ttl=TTL, hops=0, length=0):
self.data = {
'ident': ident,
'protocol': 1,
'ttl': hops,
'length': length,
}
And then override __getattr__ and __setattr__:
def __getattr__(self, attr):
return self.data[attr]
def __setattr__(self, attr, value):
if attr == 'data':
object.__setattr__(self, attr, value)
else:
self.data[attr] = value
Now you can do this:
>>> ping = Ping()
>>> ping.protocol
1
>>> ping.protocol = 2
>>> ping.protocol
2
If self.data absolutely has to be a list, you can do this instead:
class Ping(Serializable):
mapping = ('ident', 'protocol', 'ttl', 'hops', 'length')
encoder = Struct("!16sBBBL")
def __init__(self, ident=create_id(), ttl=TTL, hops=0, length=0):
self.data = [ident, 1, ttl, hops, length]
def __getitem__(self, index):
return self.data[index]
def __getattr__(self, attr):
index = self.mapping.index(attr)
return self.data[index]
def __setattr__(self, attr, value):
if attr == 'data':
object.__setattr__(self, attr, value)
else:
index = self.mapping.index(attr)
self.data[index] = value

def alias_property(key):
return property(
lambda self: getattr(self, key),
lambda self, val: setattr(self, key, val),
lambda self: delattr(self, key))
class A(object):
def __init__(self, prop):
self.prop = prop
prop_alias = alias_property('prop')

If your problem is just shorten the code to access ident, you may just use "property" in the "old style" - that is, you pass to it, as parameters, the getter and setter functions, instead of using it as a decorator.
In this case, the functions are so small, they can be lambda functions, without affecting code readbility.
class Ping(Serializable):
encoder = Struct("!16sBBBL")
def __init__(self, ident=None, ttl=TTL, hops=0, length=0):
if ident is None:
ident = create_id()
self.data = [ident, 1, ttl, hops, length]
# The line bellow looks like garbage -
# it does not even make sense as a call to `property`
# should have a callable as first parameter
# returns an object that is designed to work as a class attribute
# self.ident = property(self.data[0])
# rather:
self.ident = ident
# this will use the property defined bellow
def __getitem__(self, index):
return self.data[index]
ident = property(lambda s: s.data[0], lambda s, v: s.data[0].__setitem__(0, v)
protocol = property(lambda s: s.data[1], lambda s, v: s.data[1].__setitem__(1, v)

Related

Count reads from python dictionary with unpacking

I am interested in counting the number of accesses to a dictionary's values. I am unsure how to include dictionary unpacking in the counter. Any tips?
from collections import defaultdict
class LDict(dict):
def __init__(self, *args, **kwargs):
'''
This is a read-counting dictionary
'''
super().__init__(*args, **kwargs)
self._lookup = defaultdict(lambda : 0)
def __getitem__(self, key):
retval = super().__getitem__(key)
self._lookup[key] += 1
return retval
def __setitem__(self, key, value):
super().__setitem__(key, value)
self._lookup[key] = self._lookup.default_factory()
def __delitem__(self, key):
super().__delitem__(self, key)
_ = self._lookup[key]
del self._lookup[key]
def list_unused(self):
return [key for key in self if self._lookup[key] == 0]
l = LDict(a='apple', b='bugger')
print({**l, **l})
print(l.list_unused())
_ = l['a']
print(l.list_unused())
You need to override more methods. Access is not centralized through __getitem__(): other methods like copy(), items(), etc. access the keys without going through __getitem()__. I would assume the ** operator uses items(), but you will need to handle ALL of the methods to keep track of EVERY access. In many cases you will have to make a judgement call. For example, does __repr__() count as an access? The returned string contains every key and value formatted, so I think it does.
I would recommend overriding all of these methods, because you have to do bookkeeping on assignment too.
def __repr__(self):
def __len__(self):
def __iter__(self):
def clear(self):
def copy(self):
def has_key(self, k):
def update(self, *args, **kwargs):
def keys(self):
def values(self):
def items(self):
EDIT: So apparently there's an important caveat here that directly relates to your implementation. if LDict extends dict, then none of these methods are invoked during the dictionary unpacking { **l, **l}.
Apparently you can follow the advice here though, and implement LDict without extending dict. This worked for me:
from collections import MutableMapping
class LDict(MutableMapping):
def __init__(self, *args, **kwargs):
'''
This is a read-counting dictionary
'''
self._lookup = defaultdict(lambda : 0)
self.data = {}
if kwargs:
self.data.update(kwargs)
def __getitem__(self, key):
retval = self.data[key]
self._lookup[key] += 1
return retval
def __setitem__(self, key, value):
self.data[key] = value
self._lookup[key] = self._lookup.default_factory()
def __delitem__(self, key):
del self.data[key]
_ = self._lookup[key]
del self._lookup[key]
def items(self):
print('items is being called!')
yield from self.data.items()
def __iter__(self):
print('__iter__ is being called!')
yield from self.data
def __len__(self):
return len(self.data)
def list_unused(self):
return [key for key in self if self._lookup[key] == 0]
l = LDict(a='apple', b='bugger')
print({**l, **l})
print(l.list_unused())
_ = l['a']
print(l.list_unused())
which produces the output:
__iter__ is being called!
__iter__ is being called!
{'b': 'bugger', 'a': 'apple'}
__iter__ is being called!
[]
__iter__ is being called!
[]
(I only implemented the bare minimum to get example to work, I still recommend implementing the set of methods I listed about if you want your counts to be correct!)
So I guess the answer to your question is you have to
Implement the __iter__(self) method
DO NOT inherit from dict().

Implement _del_ method for a class with __getattribute__ overriden

Taking this question as a pointer, let's say there exists a class like the following:
class Container(object):
def __init__(self, **kwargs):
self._meta = defaultdict(lambda: None)
for attr, value in kwargs.iteritems():
self._meta[attr] = value
def __getattr__(self, key):
try:
return self._meta[key]
except KeyError:
raise AttributeError(key)
def __setattr__(self, key, value):
if key in ('_meta', '_hasattr'):
super(Container, self).__setattr__(key, value)
else:
self._meta[key] = value
This allows the following behavior:
c = Container()
c.a = 1
print(c.a) # 1
print(c.b) # None
Question: What is the best way to implement an operator such that the following works:
# Should delete the value of a from Container._meta
del c.a
Of course, one could obviously implement a method like,
def _delete(self, key):
...
But is there way to re-use a python operator to do this?
Just define the __delattr__ method:
def __delattr__(self, key):
del self._meta[key]

Using __setattr__ + __slots__ in a python3 class

I am trying to be all fancy with sub element attribute access in a custom class hierarchy.
My fanciness works in that I can successfully use descriptors to do this.
I want to be even more fancy and make the class RefHolder (shown below in the testcase) use slots to save space.
When I try to use slots though, I get RuntimeError: maximum recursion depth exceeded
Note that I have already tried looking at existing solutions for this, the most closely matching I could find being this one:
https://stackoverflow.com/a/19566973/1671693
I have tried this in the testcase below but I am still get the runtimeerror.
Note that in the testcase, if the commented lines are used instead of the ones directly beneath them and __slots__ is removed from RefHolder,
The testcase passes.
Any suggestions?
Additionally, I am creating an object for every attribute access which seems expensive, are there any suggestions on a more efficient way of achieving the same behavior? Thanks!
import unittest
class RefHolder():
__slots__ = ['__obj', 'get_value']
def __init__(self, obj, get_value=False):
self.__dict__['__obj'] = obj
self.__dict__['get_value']=get_value
def get_sub(self, name):
#attr = self.__dict__['__obj'].find_by_name(name)
attr = self.__dict__['__obj'].__get__(self, RefHolder).find_by_name(name)
if attr is None:
raise AttributeError("Can't find field {}".format(name))
return attr
def __getattr__(self, name):
attr = self.get_sub(name)
#if self.__dict__['get_value']:
if self.__dict__['get_value'].__get__(self, RefHolder):
return attr.Value
else:
return attr
def __setattr__(self, name, value):
attr = self.get_sub(name)
#if self.__dict__['get_value']:
if self.__dict__['get_value'].__get__(self, RefHolder):
attr.Value = value
else:
raise AttributeError("{} is read only in this context".format(name))
class ContainerAccess():
__slots__ = ['get_value']
def __init__(self, get_value=False):
self.get_value = get_value
def __get__(self, obj, objtype=None):
if obj is None:
return self
return RefHolder(obj, self.get_value)
def __set__(self, obj, value):
raise AttributeError("Read Only attribute".format(value))
class PropVal():
def __init__(self, val):
self.Value = val
#property
def Value(self):
return self._value
#Value.setter
def Value(self, value):
self._value = value
class T():
get = ContainerAccess()
getv = ContainerAccess(get_value=True)
def __init__(self):
self.store = {}
self._value = 0
def find_by_name(self, name):
return self.store.get(name)
class T2(T):
pass
class TestDesc(unittest.TestCase):
def test_it(self):
t = T()
t2 = T2()
t.store['my_val'] = PropVal(5)
t.store['my_val2'] = PropVal(6)
t2.store['my_val'] = PropVal(1)
self.assertEqual(t.get.my_val.Value, 5)
self.assertEqual(t.get.my_val2.Value, 6)
self.assertEqual(t2.get.my_val.Value, 1)
t.get.my_val.Value = 6
self.assertEqual(t.get.my_val.Value, 6)
with self.assertRaises(AttributeError):
t.get.blah.Value = 6
#self.assertEqual(t.get.my_other_val.Value, None)
self.assertEqual(t.getv.my_val, 6)
t.getv.my_val = 7
self.assertEqual(t.getv.my_val, 7)
with self.assertRaises(AttributeError):
t.get.my_val = 7

A dict-like class that uses transformed keys

I'd like a dict-like class that transparently uses transformed keys on lookup, so that I can write
k in d # instead of f(k) in d
d[k] # instead of d[f(k)]
d.get(k, v) # instead of d.get(f(k), v)
etc. (Imagine for example that f does some kind of canonicalization, e.g. f(k) returns k.lower().)
It seems that I can inherit from dict and override individual operations, but not that there is a centralized spot for such transformation that all keys go through. That means I have to override all of __contains__, __getitem__, get, and possibly __missing__, etc. This gets too tedious and error-prone, and not very attractive unless this overhead outweighs that of manually substituting f(k) for every call on a plain dict.
Well, the idiomatic way to do it is probably using dimo414's answer. For the case where the transform is not pure (do not always evaluates the same result value given the same argument):
class Foo(dict):
def __init__(self, transform, *args, **kwargs):
super(Foo, self).__init__(self, *args, **kwargs)
assert isfunction(transform), u'Transform argument must be a function.'
self._transform = transform
def get(self, k, d=None):
return super(Foo, self).get(self._transform(k), d)
def __getitem__(self, item):
return super(Foo, self).__getitem__(self._transform(item))
def __contains__(self, item):
return super(Foo, self).__contains__(self._transform(item))
def __repr__(self):
return '<Foo instance {}>'.format(id(self))
Testing:
>>> import datetime
>>> # {0: '0', 1: '1', 2: '2' ... 99: '99'}
>>> x = Foo(lambda x: (datetime.datetime.now() - x).seconds, ((i, str(i)) for i in range(10)))
>>> t = datetime.datetime.now()
>>> x.get(t)
'5'
>>> x[t]
'12'
Not that tedious but I don't like how it smells (in terms of design).
I'm not sure why your question is being downvoted, it's a reasonable thing to want. In Java, Guava provides several map transformation utilities which provide views into the backing map like you're describing. However they don't provide a Maps.transformKeys() method because it's actually not a very useful function. See How to convert Map<String, String> to Map<Long, String> using guava and Why Guava does not provide a way to transform map keys for details as to why.
In short, it's not possible to efficiently provide key transformations in the general case. Rather than creating the complex and possibly inconsistent data structure you're envisioning, the best thing to do is likely to just create a new dict applying your key transformation, e.g.:
{ f(k): v for k, v in d.iteritems() }
Since you want to maintain the exact same signature as dict(), I
propose creating a factory function to wrap a TransformDict to provide
the same signature.
def transform_dict(transform_key):
def _transform_dict(*args, **kwargs):
return TransformDict(transform_key, *args, **kwargs)
return _transform_dict
Which can be used as:
>>> LowerDict = transform_dict(lambda k: k.lower())
>>> lower_dict = LowerDict({'FOO': 1}, BaR=2)
TransformDict(<function <lambda> at 0x12345678>, {'foo': 1, 'bar': 2})
The TransformDict should implement the MutableMapping abstract
base class so that any potentially missed dict method will not pass
silently. All methods dealing with transforming the key can be
implemented in terms of __contains__(), __getitem__(),
__setitem__(), and __delitem__().
import collections
import sys
class TransformDict(collections.MutableMapping):
def __init__(self, __transform_key, *args, **kwargs):
self.data = dict(*args, **kwargs)
self.transform_key = __transform_key
# Key methods.
def __contains__(self, key):
key = self.transform_key(key)
return key in self.data
def __getitem__(self, key):
key = self.transform_key(key)
return self.data[key]
def __setitem__(self, key, value):
key = self.transform_key(key)
self.data[key] = value
def __delitem__(self, key):
key = self.transform_key(key)
del self.data[key]
# Operator methods.
def __iter__(self):
return iter(self.data)
def __len__(self):
return len(self.data)
def __eq__(self, other):
if isinstance(other, TransformDict):
other = other.data
return self.data == other
def __ne__(self, other):
return not (self == other)
def __repr__(self):
return "{}({!r}, {!r})".format(self.__class__.__name__, self.transform_key, self.data)
# Accessor methods.
def get(self, key, default=None):
if key in self:
return self[key]
return default
def keys(self):
return self.data.keys()
def items(self):
return self.data.items()
def values(self):
return self.data.values()
if sys.version_info[0] == 2:
def iterkeys(self):
return self.data.iterkeys()
def itervalues(self):
return self.data.itervalues()
def iteritems(self):
return self.data.iteritems()
def viewkeys(self):
return self.data.viewkeys()
def viewvalues(self):
return self.data.viewvalues()
def viewitems(self):
return self.data.viewitems()
# Mutable methods.
def clear(self):
self.data.clear()
def pop(self, key, default=KeyError):
if key in self or default is KeyError:
value = self[key]
del self[key]
return value
return default
def popitem(self):
return self.data.popitem()
def setdefault(self, key, default=None):
if key not in self:
self[key] = default
return default
return self[key]
def update(self, other):
for key for other:
self[key] = other[key]
# Miscellaneous methods.
def copy(self):
return self.__class__(self.transform_key, self.data)

Looking for a solution to detect value change in class attribute with a list and append

Looking for a solution to detect value change when I do : class_instance.list.append(value).
I wrote a little example to illustrate my problem.
class Foo(object):
def __setattr__(self, key, value):
print('set -> ', key, value)
self.__dict__[key] = value
if __name__ == '__main__':
f = Foo()
#set/change detected
f.bar = ['foo']
# change not detected
f.bar.append('bar')
#change detected
f.bar = ['foo', 'bar']
Thank you for your help.
With help of #harobed, I found this solution http://code.activestate.com/recipes/306864-list-and-dictionary-observer/, credits goes to Bernhard Mulder for the observer class.
Here is a working sample of what I want to achieve
class Foo(object):
def __init__(self):
self._dirty = False
def __setattr__(self, key, value):
if key != '_dirty':
if isinstance(value, list):
self.__dict__[key] = list_observer(value, self.observer(self))
else:
self.__dict__[key] = value
self._make_dirty()
def _make_dirty(self):
self._dirty = True
print('is dirty')
def _not_dirty(self):
self._dirty = False
print('is no more dirty')
class observer(object):
"""
If a call to a method is made, this class prints the name of the method
and all arguments.
"""
def __init__(self, instance):
self.instance = instance
def p(self, *args):
print self.attr, args
self.instance._make_dirty()
def __getattr__(self, attr):
self.attr = attr
return self.p
class list_observer(list):
"""
Send all changes to an observer.
"""
def __init__(self, value, observer):
list.__init__(self, value)
self.set_observer(observer)
def set_observer(self, observer):
"""
All changes to this list will trigger calls to observer methods.
"""
self.observer = observer
def __setitem__(self, key, value):
"""
Intercept the l[key]=value operations.
Also covers slice assignment.
"""
try:
oldvalue = self.__getitem__(key)
except KeyError:
list.__setitem__(self, key, value)
self.observer.list_create(self, key)
else:
list.__setitem__(self, key, value)
self.observer.list_set(self, key, oldvalue)
def __delitem__(self, key):
oldvalue = list.__getitem__(self, key)
list.__delitem__(self, key)
self.observer.list_del(self, key, oldvalue)
def __setslice__(self, i, j, sequence):
oldvalue = list.__getslice__(self, i, j)
self.observer.list_setslice(self, i, j, sequence, oldvalue)
list.__setslice__(self, i, j, sequence)
def __delslice__(self, i, j):
oldvalue = list.__getitem__(self, slice(i, j))
list.__delslice__(self, i, j)
self.observer.list_delslice(self, i, oldvalue)
def append(self, value):
list.append(self, value)
self.observer.list_append(self)
def pop(self):
oldvalue = list.pop(self)
self.observer.list_pop(self, oldvalue)
def extend(self, newvalue):
list.extend(self, newvalue)
self.observer.list_extend(self, newvalue)
def insert(self, i, element):
list.insert(self, i, element)
self.observer.list_insert(self, i, element)
def remove(self, element):
index = list.index(self, element)
list.remove(self, element)
self.observer.list_remove(self, index, element)
def reverse(self):
list.reverse(self)
self.observer.list_reverse(self)
def sort(self, cmpfunc=None):
oldlist = self[:]
list.sort(self, cmpfunc)
self.observer.list_sort(self, oldlist)
if __name__ == '__main__':
f = Foo()
#change detected, f is dirty
f.bar = ['foo']
f._not_dirty()
#change detected, f is dirty again
f.bar.append('bar')
EDIT
Is better to Rely on isinstance(a, list) to detect type according to this post -> Differences between isinstance() and type() in python

Categories