When calling copy , defaultdict calls the constructor with arguments to pass the default_factory function and data.
Your constructor takes no arguments, so it can only create empty dict with a fixed factory.
Correct your constructor as follows:
def __init__(self,*args):
But you must pass args to the mother class, or your copied dictionary will be empty (not what you want).
Since you specialize in the default factory, you need to make a special case if args empty:
class A(defaultdict): def __init__(self,*args): if args: super(A, self).__init__(*args) else: super(A, self).__init__(int) # better than lambda : 0
Or maybe simpler with a triple:
class A(defaultdict): def __init__(self,*args): super(A, self).__init__(*(args or (int,)))
- When
args not empty (called from copy ), then the copy takes the properties of the original (function and data). - When
args empty, it means you are creating a new dict, so it just fixes the factory argument by default.
Alternatively, you can replace (lambda :0) with (int) .
EDIT: a more complex way, but which ensures that the user cannot change the default value, was to ignore the first argument and force int (possibly with a warning if the first argument is not int ):
super(A, self).__init__(*([int]+list(args[1:])))
This will work, but I don't like the idea of strongly ignoring the argument.
As a conclusion, inheritance for built-in types is generally complex and should be used with caution (see another example trying to do this using pandas dataframe: building a class from an existing one ). Sometimes, creating a class with the defaultdict argument as an argument and that mimics / relays only the methods you plan to use will lead to less side effects.