Sorry, it’s not like I’m not addressing it but I don’t recomend it.
The main issue  here is that module is a nn.Module. Then it’s hidden in _modules private dict. The way they designed to gather nn.Modules is through getattr. As you are overwritting getattr it gets into a infinity recursion.
I really really doubt that workaround won’t lead to further bugs. You can fix it doing the following. Basically I am invoking the parent getattr method (the way they originally created to gather nn.Modules) in case you try to get the object ‘module’. Otherwise it directly goes to the children’s objects.
class MyDataParallel(nn.DataParallel):
    def __getattr__(self, name):
        if name == 'module':
            return super().__getattr__('module')
        else:
            return getattr(self.module, name)

You can also do:
class MyDataParallel(nn.DataParallel):
    def __getattr__(self, name):
        if name == 'module':
            return self._modules['module']
        else:
            return getattr(self.module, name)

But anyway if you want a safer code I would do the following.
class MyDataParallel(nn.DataParallel):
    def __init__(self, my_methods, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._mymethods = my_methods

    def __getattr__(self, name):
        if name in self._mymethods:
            return getattr(self.module, name)

        else:
            return super().__getattr__(name)

You just need to pass a list of the methods you defined. This way you ensure that if it’s one of your methods it comes from the proper object. The same error you found for a nn.Module will raise if you store tensors in the DataParallel object (as those objects are also hidden in _buffers and _parameters and properly gathered through getattr)
Btw @albanD could you have a look at it to fix the tutorial?