How should I understand the "Bunch class" in python? - python

Today I have learnt a Bunch class from the book < Python algorithm >
class Bunch(dict):
def __init__(self, *args, **kwds):
super(Bunch, self).__init__(*args, **kwds)
self.__dict__ = self
But I'm not quite understanding what does the third line do:
super(Bunch, self).__init__(*args, **kwds)
I know it will call the parent class, and do something like:
dict.__init__(self, *args, **kwds)
But I have no idea what does the __init__ function do to the dict.
How should I understand that?

You can think of dict.__init__ as the dictionary constructor. e.g. I can write:
d = dict(a=1, b=2)
or
d = dict([('a', 1), ('b', 2)])
Both create (initialize) the dictionary {'a': 1, 'b': 2}. Whenever I write those two statements, it calls dict.__init__ which is what does the job of adding the a and b items.
In the same way, with Bunch, it causes all of the keyword arguments (or an iterable of 2-sequences) to be turned into key-value pairs in the dictionary subclass (Bunch).

You don't need to know exactly what dict__init__ does. The way to think about it is that dict.__init__ does what is necessary to make the object "work like a dict". In general, when you subclass, you need to call the superclass __init__ to make the class "work like" its superclass, and the same is true when subclassing a builtin type like dict.

Related

Cannot create an instance of a namedtuple subclass: TypeError: __new__() takes exactly 4 arguments (3 given)

I seem to be unable to instantiate a namedtuple subclass:
from collections import namedtuple
foo = namedtuple("foo",["a","b","c"])
class Foo(foo):
def __init__(self, a, b):
super(Foo, self).__init__(a=a,b=b,c=a+b)
When I try to create an instance, I get:
>>> Foo(1,2)
TypeError: __new__() takes exactly 4 arguments (3 given)
I expected Foo(1,2,3).
There seems to be a workaround: using a class method instead of __init__:
class Foo(foo):
#classmethod
def get(cls, a, b):
return cls(a=a, b=b, c=a+b)
Now Foo.get(1,2) indeed returns foo(a=1, b=2, c=3).
However, this looks ugly.
Is this the only way?
Named tuples are immutable, you need to use the __new__ method instead:
class Foo(foo):
def __new__(cls, a, b):
return super(Foo, cls).__new__(cls, a=a, b=b, c=a+b)
(Note: __new__ is implicitly made a static method, so you need to pass on the cls argument explicitly; the method returns the newly created instance).
__init__ can't be used because that is called after the instance has already been created and so would not be able to mutate the tuple anymore.
Note that you should really add a __slots__ = () line to your subclass; a named tuple has no __dict__ dictionary cluttering up your memory, but your subclass will unless you add the __slots__ line:
class Foo(foo):
__slots__ = ()
def __new__(cls, a, b):
return super(Foo, cls).__new__(cls, a=a, b=b, c=a+b)
That way you get to keep the memory footprint of your named tuples low. See the __slots__ documentation:
The action of a __slots__ declaration is limited to the class where it is defined. As a result, subclasses will have a __dict__ unless they also define __slots__ (which must only contain names of any additional slots).

What happens when I loop a dict in python

I know Python will simply return the key list when I put a dict in for...in... syntax.
But what what happens to the dict?
When we use help(dict), we can not see __next()__ method in the method list. So if I want to make a derived class based on dict:
class MyDict(dict)
def __init__(self, *args, **kwargs):
super(MyDict, self).__init__(*args, **kwargs)
and return the value list with for...in...
d = Mydict({'a': 1, 'b': 2})
for value in d:
what should I do?
Naively, if all you want is for iteration over an instance of MyClass to yield the values instead of the keys, then in MyClass define:
def __iter__(self):
return self.itervalues()
In Python 3:
def __iter__(self):
return iter(self.values())
But beware! By doing this your class no longer implements the contract of collections.MutableMapping, even though issubclass(MyClass, collections.MutableMapping) is True. You might be better off not subclassing dict, if this is the behaviour you want, but instead have an attribute of type dict to hold the data, and implement only the functions and operators you need.

Python : Argument based Singleton

I'm following this link and trying to make a singleton class. But, taking arguments (passed while initiating a class) into account so that the same object is returned if the arguments are same.
So, instead of storing class name/class reference as a dict key, I want to store passed arguments as keys in dict. But, there could be unhashable arguments also (like dict, set itself).
What is the best way to store class arguments and class objects mapping? So that I can return an object corresponding to the arguments.
Thanks anyways.
EDIT-1 :
A little more explanation. Let's say there is class as follows
class A:
__metaclass__ == Singleton
def __init__(arg1, arg2):
pass
Now, A(1,2) should always return the same object. But, it should be different from A(3,4)
I think, the arguments very much define the functioning of a class. Let's say if the class is to make redis connections. I might want to create 2 singletons objects with diff redis hosts as parameters, but the underlying class/code could be common.
As theheadofabroom and me already mentioned in the comments, there are some odds when relying on non-hashable values for instance caching or memoization. Therefore, if you still want to do exactly that, the following example does not hide the memoization in the __new__ or __init__ method. (A self-memoizing class would be hazardous because the memoization criterion can be fooled by code that you don't control).
Instead, I provide the function memoize which returns a memoizing factory function for a class. Since there is no generic way to tell from non-hashable arguments, if they will result in an instance that is equivalent to an already existing isntance, the memoization semantics have to be provided explicitly. This is achieved by passing the keyfunc function to memoize. keyfunc takes the same arguments as the class' __init__ method and returns a hashable key, whose equality relation (__eq__) determines memoization.
The proper use of the memoization is in the responsibility of the using code (providing a sensible keyfunc and using the factory), since the class to be memoized is not modified and can still be instantiated normally.
def memoize(cls, keyfunc):
memoized_instances = {}
def factory(*args, **kwargs):
key = keyfunc(*args, **kwargs)
if key in memoized_instances:
return memoized_instances[key]
instance = cls(*args, **kwargs)
memoized_instances[key] = instance
return instance
return factory
class MemoTest1(object):
def __init__(self, value):
self.value = value
factory1 = memoize(MemoTest1, lambda value : value)
class MemoTest2(MemoTest1):
def __init__(self, value, foo):
MemoTest1.__init__(self, value)
self.foo = foo
factory2 = memoize(MemoTest2, lambda value, foo : (value, frozenset(foo)))
m11 = factory1('test')
m12 = factory1('test')
assert m11 is m12
m21 = factory2('test', [1, 2])
lst = [1, 2]
m22 = factory2('test', lst)
lst.append(3)
m23 = factory2('test', lst)
assert m21 is m22
assert m21 is not m23
I only included MemoTest2 as a sublclass of MemoTest1 to show that there is no magic involved in using regular class inheritance.

Overwriting Class Methods to define Kwargs - Which is Pythonic?

I'm working on an abstraction layer to a database, and I have a super class defined similar to this:
class Test():
__init__(self, object):
self.obj = object
#classmethod
def find_object(cls, **kwargs):
# Code to search for object to put in parameter using kwargs.
return cls(found_object)
I then break down that superclass into subclasses that are more specific to the objects they represent.
class Test_B(Test):
# Subclass defining more specific version of Test.
Now, each separate subclass of Test has predefined search criteria. For example, Test_B needs an object with a = 10, b = 30, c = "Pie".
Which would be more "Pythonic"? Using the find_object method from the super class:
testb = Test_B.find_object(a=10, b=30, c="Pie")
or to overwrite the find_object method to expect a, b, and c as parameters:
#classmethod
def find_object(cls, a, b, c):
return super().find_object(a=a, b=b, c=c)
testb = Test_B.find_object(10, 30, "Pie")
First one. "Explicit is better than implicit" - Zen of Python: line 2
Test.find_object isn't intended to be used directly, so I would name it
#classmethod
def _find_object(cls, **kwargs):
...
then have each child class call it to implement its own find_object:
#classmethod
def find_object(cls, a, b, c):
return super()._find_object(a=a, b=b, c=c)
When using super, it's a good idea to preserve the signature of a method if overriding it, because you can never be certain for which class super will return a proxy.
skilsuper - you're right about
Explicit is better than implicit
However, that doesn't mean the first answer is better - you can still apply the same principal on the second solution: find_object(10, 30, "Pie") is implicit, but nothing is stopping you from using find_object(a=10, b=30, c="Pie") (you should use it).
The first solution is problematic, because you might forget an argument (for example, find_object(a=10, b=30)). In that case, the first solution will let it slide, but the second solution will issue a TypeError saying that you're missing an argument.

python dynamically set non-instance class attributes

I am trying to add class attributes dynamically, but not at the instance level. E.g. what I can do manually as:
class Foo(object):
a = 1
b = 2
c = 3
I'd like to be able to do with:
class Foo(object):
dct = {'a' : 1, 'b' : 2, 'c' : 3}
for key, val in dct.items():
<update the Foo namespace here>
I'd like to be able to do this without a call to the class from outside the class (so it's portable), or without additional classes/decorators. Is this possible?
Judging from your example code, you want to do this at the same time you create the class. In this case, assuming you're using CPython, you can use locals().
class Foo(object):
locals().update(a=1, b=2, c=3)
This works because while a class is being defined, locals() refers to the class namespace. It's implementation-specific behavior and may not work in later versions of Python or alternative implementations.
A less dirty-hacky version that uses a class factory is shown below. The basic idea is that your dictionary is converted to a class by way of the type() constructor, and this is then used as the base class for your new class. For convenience of defining attributes with a minimum of syntax, I have used the ** convention to accept the attributes.
def dicty(*bases, **attrs):
if not bases:
bases = (object,)
return type("<from dict>", bases, attrs)
class Foo(dicty(a=1, b=2, c=3)):
pass
# if you already have the dict, use unpacking
dct = dict(a=1, b=2, c=3)
class Foo(dicty(**dct)):
pass
This is really just syntactic sugar for calling type() yourself. This works fine, for instance:
class Foo(type("<none>", (object,), dict(a=1, b=2, c=3))):
pass
Do you mean something like this:
def update(obj, dct):
for key, val in dct.items():
obj.setattr(key, val)
Then just go
update(Foo, {'a': 1, 'b': 2, 'c': 3})
This works, because a class is just an object too ;)
If you want to move everything into the class, then try this:
class Foo(object):
__metaclass__ = lambda t, p, a: return type(t, p, a['dct'])
dct = {'a': 1, 'b': 2, 'c': 3}
This will create a new class, with the members in dct, but all other attributes will not be present - so, you want to alter the last argument to type to include the stuff you want. I found out how to do this here: What is a metaclass in Python?
The accepted answer is a nice approach. However, one downside is you end up with an additional parent object in the MRO inheritance chain that isn't really necessary and might even be confusing:
>>> Foo.__mro__
(<class '__main__.Foo'>, <class '__main__.<from dict>'>, <class 'object'>)
Another approach would be to use a decorator. Like so:
def dicty(**attrs):
def decorator(cls):
vars(cls).update(**attrs)
return cls
return decorator
#dicty(**some_class_attr_namespace)
class Foo():
pass
In this way, you avoid an additional object in the inheritance chain. The #decorator syntax is just a pretty way of saying:
Foo = dicty(a=1, b=2, c=3)(Foo)

Categories