Runing the program, you get very different results for the two classes. The class decorator version always does what's expected. Not so much for the metaclass. For example: bash % python3 bug.py ---- Class Decorator ---- Decorating f_4 Decorating f_8 Decorating f_7 Decorating f_3 Decorating f_6 Decorating f_2 Decorating f_5 Decorating f_1 ---- Metaclass ---- Decorating f_4 Decorating f_3 Decorating f_5 Decorating f_2 # Notice: Where is f_7? It's gone! Decorating f_1 Decorating f_6 Decorating f_8 Try running it again: ---- Class Decorator ---- Decorating f_3 Decorating f_7 Decorating f_5 Decorating f_1 Decorating f_8 Decorating f_6 Decorating f_4 Decorating f_2 ---- Metaclass ---- Decorating f_3 # <<<<<< Decorating f_7 Decorating f_1 Decorating f_3 # WHAT?!?! This was just wrapped above Decorating f_5 Decorating f_8 Decorating f_6 Decorating f_4 Decorating f_2 So yes, you're iterating over the class dictionary, changing the value assigned to some of the keys, and effectively seeing the dictionary "change size", dropping one or more keys or iterating over the same key more than once. It randomly changes run-to-run. Code behaves differently depending if it's invoked from a metaclass or not. Enjoy!