![]() |
|
attrdict.py - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: General (https://python-forum.io/forum-1.html) +--- Forum: Code sharing (https://python-forum.io/forum-5.html) +--- Thread: attrdict.py (/thread-15082.html) Pages:
1
2
|
attrdict.py - Skaperen - Jan-02-2019 a while back, i got help here on PFio regarding accessing a dictionary like attributes. i coded up a full class for it. i haven't tested it thoroughly but it basically seems to be working. attrdict.py class attrdict:
'''Class that is like a dictionary with items usable like attributes.
#---------------------------------------------------------------
# purpose class that is like a dictionary with items
# usable like attributes
#
# init usage object = attrdict(dictionary_ref)
# object = attrdict(dictionary_ref,key=value)
# object = attrdict(key=value)
#
# attr usage object.name
#
# dict usage object[key] = value
# value = object[key]
#
# note attribute usage is like string keys that are
# limited to what can be a valid identifier.
#
# note the referenced dictionary is shared with this
# object so changes to either are in effect for
# the other
#---------------------------------------------------------------
'''
def __init__(self,*args,**opts):
if args:
if not isinstance(args[0],(dict,attrdict)):
raise TypeError('attrdict: passed a non-dictionary inital reference')
self.__dict__ = args[0]
else:
self.__dict__ = {}
if isinstance(opts,dict):
if opts:
self.__dict__.update(opts)
if isinstance(opts,attrdict):
if opts.__dict__:
self.__dict__.update(opts.__dict__)
def __eq__ (self,other):
if isinstance(other,attrdict):
return self.__dict__ == other
return NotImplemented
def __ne__ (self,other):
if isinstance(other,attrdict):
return self.__dict__ != other
return NotImplemented
def __setitem__(self,key,value):
self.__dict__[key] = value
return
def __delitem__(self,key):
del self.__dict__[key]
return
def __getitem__(self,key):
return self.__dict__[key]
def items(self):
return self.__dict__.items()
def keys(self):
return self.__dict__.keys()
def values(self):
return self.__dict__.values()
def __hash__(self):
return hash(self.__dict__)
def __contains__(self,value):
return value in self.__dict__
def __repr__(self):
return repr(self.__dict__)
def __str__(self):
return str(self.__dict__)
def __len__(self):
return len(self.__dict__)
def __bool__(self):
return bool(self.__dict__)
def __le__(self,other):
return NotImplemented
def __lt__(self,other):
return NotImplemented
def __ge__(self,other):
return NotImplemented
def __gt__(self,other):
return NotImplemented
def __bytes__(self,*args):
return NotImplemented
def __format__(self,*args):
return NotImplemented
RE: attrdict.py - scidam - Jan-05-2019 At least one method will rise an exception (unhashable type): def __hash__(self):
return hash(self.__dict__)Another issue is original dict instances are iterable, but attrdict ones aren't.So, you probably need to accomplish the class with __iter__ and __next__ methods.
RE: attrdict.py - Skaperen - Jan-09-2019 i just removed __hash__() (i can't reason why that was in there) and made __iter__() and __next__() do their thing on the dictionary itself. class attrdict:
'''Class that is like a dictionary with items usable like attributes.
#---------------------------------------------------------------
# purpose class that is like a dictionary with items
# usable like attributes
#
# init usage object = attrdict(dictionary_ref)
# object = attrdict(dictionary_ref,key=value)
# object = attrdict(key=value)
#
# attr usage object.name
#
# dict usage object[key] = value
# value = object[key]
#
# note attribute usage is like string keys that are
# limited to what can be a valid identifier.
#
# note the referenced dictionary is shared with this
# object so changes to either are in effect for
# the other
#---------------------------------------------------------------
'''
def __init__(self,*args,**opts):
if args:
if not isinstance(args[0],(dict,attrdict)):
raise TypeError('attrdict: passed a non-dictionary inital reference')
self.__dict__ = args[0]
else:
self.__dict__ = {}
if isinstance(opts,dict):
if opts:
self.__dict__.update(opts)
if isinstance(opts,attrdict):
if opts.__dict__:
self.__dict__.update(opts.__dict__)
def __eq__ (self,other):
if isinstance(other,attrdict):
return self.__dict__ == other
return NotImplemented
def __ne__ (self,other):
if isinstance(other,attrdict):
def __ne__ (self,other):
if isinstance(other,attrdict):
return self.__dict__ != other
return NotImplemented
def __setitem__(self,key,value):
self.__dict__[key] = value
return
def __delitem__(self,key):
del self.__dict__[key]
return
def __getitem__(self,key):
return self.__dict__[key]
def items(self):
return self.__dict__.items()
def keys(self):
return self.__dict__.keys()
def values(self):
return self.__dict__.values()
def __iter__(self):
return self.__dict__.__iter__()
def __next__(self):
return self.__dict__.__next__()
def __contains__(self,value):
return value in self.__dict__
def __repr__(self):
return repr(self.__dict__)
def __str__(self):
return str(self.__dict__)
def __len__(self):
return len(self.__dict__)
def __bool__(self):
return bool(self.__dict__)
def __le__(self,other):
return NotImplemented
def __lt__(self,other):
return NotImplemented
def __ge__(self,other):
return NotImplemented
def __gt__(self,other):
return NotImplemented
def __bytes__(self,*args):
return NotImplemented
def __format__(self,*args):
return NotImplementedi'm wondering if it will be just as easy to read with those empty lines removed.class attrdict:
'''Class that is like a dictionary with items usable like attributes.
#---------------------------------------------------------------
# purpose class that is like a dictionary with items
# usable like attributes
#
# init usage object = attrdict(dictionary_ref)
# object = attrdict(dictionary_ref,key=value)
# object = attrdict(key=value)
#
# attr usage object.name
#
# dict usage object[key] = value
# value = object[key]
#
# note attribute usage is like string keys that are
# limited to what can be a valid identifier.
#
# note the referenced dictionary is shared with this
# object so changes to either are in effect for
# the other
#---------------------------------------------------------------
'''
def __init__(self,*args,**opts):
if args:
if not isinstance(args[0],(dict,attrdict)):
raise TypeError('attrdict: passed a non-dictionary inital reference')
self.__dict__ = args[0]
else:
self.__dict__ = {}
if isinstance(opts,dict):
if opts:
self.__dict__.update(opts)
if isinstance(opts,attrdict):
if opts.__dict__:
self.__dict__.update(opts.__dict__)
def __eq__ (self,other):
if isinstance(other,attrdict):
return self.__dict__ == other
return NotImplemented
def __ne__ (self,other):
if isinstance(other,attrdict):
return self.__dict__ != other
return NotImplemented
def __setitem__(self,key,value):
self.__dict__[key] = value
return
def __delitem__(self,key):
del self.__dict__[key]
return
def __getitem__(self,key):
return self.__dict__[key]
def items(self):
return self.__dict__.items()
def keys(self):
return self.__dict__.keys()
def values(self):
return self.__dict__.values()
def __iter__(self):
return self.__dict__.__iter__()
def __next__(self):
return self.__dict__.__next__()
def __contains__(self,value):
return value in self.__dict__
def __repr__(self):
return repr(self.__dict__)
def __str__(self):
return str(self.__dict__)
def __len__(self):
return len(self.__dict__)
def __bool__(self):
return bool(self.__dict__)
def __le__(self,other):
return NotImplemented
def __lt__(self,other):
return NotImplemented
def __ge__(self,other):
return NotImplemented
def __gt__(self,other):
return NotImplemented
def __bytes__(self,*args):
return NotImplemented
def __format__(self,*args):
return NotImplemented
RE: attrdict.py - nilamo - Jan-09-2019 That seems like a lot of work. Why not just use dict as a the parent class, and add in __getattr__ and __setattr__ methods?>>> class attrdict(dict):
... def __getattr__(self, key):
... return self[key]
... def __setattr__(self, key, value):
... self[key] = value
...
>>> spam = attrdict({"foo": "bar", 42: "carrots"})
>>> spam
{'foo': 'bar', 42: 'carrots'}
>>> spam.foo
'bar'
>>> spam[42]
'carrots'
>>> print(spam)
{'foo': 'bar', 42: 'carrots'}
>>> spam.cat = "dog"
>>> spam
{'foo': 'bar', 42: 'carrots', 'cat': 'dog'}
>>> spam.items()
dict_items([('foo', 'bar'), (42, 'carrots'), ('cat', 'dog')])
>>> for key in spam:
... print(key)
...
foo
42
cat
RE: attrdict.py - Skaperen - Jan-10-2019 because i didn't know about that? now that i know what, i can go read more about how. but what you are suggesting makes sense as the simpler way to do it. RE: attrdict.py - Skaperen - Jan-10-2019 i added an __init__() method which handles zero or more arguments of dict/attrdict or list/tuple of zero or more key:value 2-sequence pairs. class attrdict(dict):
'''Class that is like a dictionary with items usable like attributes.
#---------------------------------------------------------------
# purpose class that is a dictionary with items usable
# like attributes
#
# init usage object = attrdict(dictionary)
# object = attrdict(dictionary,key=value...)
# object = attrdict(key=value...)
#
# attr usage object.name
#
# dict usage object[key]
#
# note attribute usage is like string keys that are
# limited to what can be a valid identifier.
#
# thanks nilamo@python-forum.io
#---------------------------------------------------------------
'''
def __init__(self,*args,**opts):
arn = 0
for arg in args:
arn += 1
if isinstance(arg,(attrdict,dict)):
self.update(arg)
elif arg and isinstance(arg,(list,tuple)):
an = -1
for ar in arg:
an += 1
if isinstance(ar,(list,tuple)) and len(ar)==2:
self[ar[0]] = ar[1]
else:
raise TypeError('not a 2-sequence at ['+str(an)+'] of argument '+str(arn))
else:
raise TypeError('argument '+str(arn)+' is not a sequence')
if opts:
if isinstance(opts,(attrdict,dict)):
self.update(opts)
else:
raise TypeError('options ('+repr(opts)+') is not a dictionary')
def __getattr__(self, key):
return self[key]
def __setattr__(self, key, value):
self[key] = value
RE: attrdict.py - Gribouillis - Jan-10-2019 The rule of least surprise suggests that the __init__ method has the same behaviour as dict's __init__ method, why not simply inherit this method? RE: attrdict.py - Skaperen - Jan-11-2019 i need to create attrdict objects from existing dictionaries because most of my existing code that uses attrdict does it that way. in some cases i don't know that i can easily avoid that. does dict.__init__() do that? RE: attrdict.py - nilamo - Jan-11-2019 >>> x = {"a": 1}
>>> b = dict(x)
>>> b
{'a': 1}
>>> #or using keyword expansion:
>>> c = dict(**x)
>>> c
{'a': 1}
>>> #make sure they aren't just shallow copies
>>> x["b"] = 2
>>> x
{'a': 1, 'b': 2}
>>> b
{'a': 1}
>>> c
{'a': 1}
RE: attrdict.py - Skaperen - Jan-12-2019 would .update() do that? (make a deep copy) |