Module (51%)
Section (92%)

Now let's create a function that will decorate a class with a method that issues alerts whenever the 'mileage' attribute is read.

Look at the code in the editor. Let's analyze it:

  • line 1: def object_counter(class_): – this line defines a decorating function that accepts one parameter 'class_' (note the underscore)
  • line 2: class_.__getattr__orig = class_.__getattribute__ – the decorator makes a copy of the reference to the __getattribute__ special method. This method is responsible for returning the attribute values. The reference to this original method will be used in a modified method;
  • line 4: def new_getattr(self, name): – a definition of the method playing the role of the new __getattribute__ method starts here. This method accepts an attribute name – it’s a string;
  • line 5: if name == 'mileage': – in case some code asks for the 'mileage' attribute, the next line will be executed;
  • line 6: print('We noticed that the mileage attribute was read') – a simple alert is issued;
  • line 7: return class_.__getattr__orig(self, name) – the original method __getattribute__ referenced by class.__getattr__orig is called. This ends the 'new_getattr' function definition;
  • line 9: class_.__getattribute__ = new_getattr – now the 'new_getattr' is defined, so it can now be referenced as the new '__getattribute__' method by a decorated class;
  • line 10: return class_ – every well behaved and developed decorator should return the decorated object – in our case it is a decorated class.

The last thing we should do is decorate the Car class:

@object_counter class Car:

When you run the code, you can see that access to the 'mileage' attribute has been detected:

We noticed that the mileage attribute was read The mileage is 0 The VIN is ABC123

output



Code

def object_counter(class_):
class_.__getattr__orig = class_.__getattribute__

def new_getattr(self, name):
if name == 'mileage':
print('We noticed that the mileage attribute was read')
return class_.__getattr__orig(self, name)

class_.__getattribute__ = new_getattr
return class_
{{ dockerServerErrorMsg }} ×
{{ errorMsg }} ×
{{ successMsg }} ×