Hi Aman, I did a bit of debugging on Transform and posted something as a follow up of my earlier query in the code walkthru forum. You can find it here .
The answer in my understanding lies in _TfmMeta wherein the call function sets cls.encodes and cls.decodes if you donât pass along an enc or dec.
%%debug
bg = Transform()
If you follow the debugger along you will see that at the call of _TfmMeta the cls (which is the Transform class) has no attribute called encodes or decodes. Then the call sets cls.encodes and cls.decodes to be TypeDispatch(). Hopefully this clarifies.
NOTE: Enter 'c' at the ipdb> prompt to continue execution.
None
> <string>(2)<module>()
ipdb> s
--Call--
> /Users/i077725/Documents/GitHub/fastai_dev/dev/local/data/transform.py(122)__call__()
120 return res
121
--> 122 def __call__(cls, *args, **kwargs):
123 f = args[0] if args else None
124 n = getattr(f,'__name__',None)
ipdb> self
*** NameError: name 'self' is not defined
ipdb> cls
<class 'local.data.transform.Transform'>
ipdb> cls.encodes
*** AttributeError: type object 'Transform' has no attribute 'encodes'
ipdb> cls.decodes
*** AttributeError: type object 'Transform' has no attribute 'decodes'
ipdb> args
cls = <class 'local.data.transform.Transform'>
args = ()
kwargs = {}
ipdb> n
> /Users/i077725/Documents/GitHub/fastai_dev/dev/local/data/transform.py(123)__call__()
121
122 def __call__(cls, *args, **kwargs):
--> 123 f = args[0] if args else None
124 n = getattr(f,'__name__',None)
125 if not hasattr(cls,'encodes'): cls.encodes=TypeDispatch()
ipdb> n
> /Users/i077725/Documents/GitHub/fastai_dev/dev/local/data/transform.py(124)__call__()
122 def __call__(cls, *args, **kwargs):
123 f = args[0] if args else None
--> 124 n = getattr(f,'__name__',None)
125 if not hasattr(cls,'encodes'): cls.encodes=TypeDispatch()
126 if not hasattr(cls,'decodes'): cls.decodes=TypeDispatch()
ipdb> f
ipdb> getattr(f,'__name__',None)
ipdb> n
> /Users/i077725/Documents/GitHub/fastai_dev/dev/local/data/transform.py(125)__call__()
123 f = args[0] if args else None
124 n = getattr(f,'__name__',None)
--> 125 if not hasattr(cls,'encodes'): cls.encodes=TypeDispatch()
126 if not hasattr(cls,'decodes'): cls.decodes=TypeDispatch()
127 if isinstance(f,Callable) and n in ('decodes','encodes','_'):
ipdb> hasattr(cls,'encodes')
False
ipdb> n
> /Users/i077725/Documents/GitHub/fastai_dev/dev/local/data/transform.py(126)__call__()
124 n = getattr(f,'__name__',None)
125 if not hasattr(cls,'encodes'): cls.encodes=TypeDispatch()
--> 126 if not hasattr(cls,'decodes'): cls.decodes=TypeDispatch()
127 if isinstance(f,Callable) and n in ('decodes','encodes','_'):
128 getattr(cls,'encodes' if n=='_' else n).add(f)
ipdb> self.encodes
*** NameError: name 'self' is not defined
ipdb> cls.encodes
{}
ipdb> hasattr(cls,'decodes')
False
ipdb> n
> /Users/i077725/Documents/GitHub/fastai_dev/dev/local/data/transform.py(127)__call__()
125 if not hasattr(cls,'encodes'): cls.encodes=TypeDispatch()
126 if not hasattr(cls,'decodes'): cls.decodes=TypeDispatch()
--> 127 if isinstance(f,Callable) and n in ('decodes','encodes','_'):
128 getattr(cls,'encodes' if n=='_' else n).add(f)
129 return f
ipdb> cls.decodes
{}
ipdb> n
> /Users/i077725/Documents/GitHub/fastai_dev/dev/local/data/transform.py(130)__call__()
128 getattr(cls,'encodes' if n=='_' else n).add(f)
129 return f
--> 130 return super().__call__(*args, **kwargs)
131
132 @classmethod
ipdb> super
<class 'super'>
ipdb> s
--Call--
> /Users/i077725/Documents/GitHub/fastai_dev/dev/local/data/transform.py(139)__init__()
137 "Delegates (`__call__`,`decode`) to (`encodes`,`decodes`) if `filt` matches"
138 filt,init_enc,as_item_force,as_item,order = None,False,None,True,0
--> 139 def __init__(self, enc=None, dec=None, filt=None, as_item=False):
140 self.filt,self.as_item = ifnone(filt, self.filt),as_item
141 self.init_enc = enc or dec
ipdb> self
Transform: True {} {}
ipdb> enc
ipdb> dec
ipdb> as_item
False
ipdb> self.as_item
True
ipdb> n
> /Users/i077725/Documents/GitHub/fastai_dev/dev/local/data/transform.py(140)__init__()
138 filt,init_enc,as_item_force,as_item,order = None,False,None,True,0
139 def __init__(self, enc=None, dec=None, filt=None, as_item=False):
--> 140 self.filt,self.as_item = ifnone(filt, self.filt),as_item
141 self.init_enc = enc or dec
142 if not self.init_enc: return
ipdb> n
> /Users/i077725/Documents/GitHub/fastai_dev/dev/local/data/transform.py(141)__init__()
139 def __init__(self, enc=None, dec=None, filt=None, as_item=False):
140 self.filt,self.as_item = ifnone(filt, self.filt),as_item
--> 141 self.init_enc = enc or dec
142 if not self.init_enc: return
143
ipdb> n
> /Users/i077725/Documents/GitHub/fastai_dev/dev/local/data/transform.py(142)__init__()
140 self.filt,self.as_item = ifnone(filt, self.filt),as_item
141 self.init_enc = enc or dec
--> 142 if not self.init_enc: return
143
144 # Passing enc/dec, so need to remove (base) class level enc/dec
ipdb> self.init_enc
ipdb> not self.init_enc
True
ipdb> bool(self.init_enc)
False
ipdb> n
--Return--
None
> /Users/i077725/Documents/GitHub/fastai_dev/dev/local/data/transform.py(142)__init__()
140 self.filt,self.as_item = ifnone(filt, self.filt),as_item
141 self.init_enc = enc or dec
--> 142 if not self.init_enc: return
143
144 # Passing enc/dec, so need to remove (base) class level enc/dec
ipdb> n
--Return--
Transform: False {} {}
> /Users/i077725/Documents/GitHub/fastai_dev/dev/local/data/transform.py(130)__call__()
128 getattr(cls,'encodes' if n=='_' else n).add(f)
129 return f
--> 130 return super().__call__(*args, **kwargs)
131
132 @classmethod
ipdb> n
--Return--
None
> <string>(2)<module>()
ipdb> n