Changing Python class methods after class definition–is it harmful/harmless/useful/useless?

Viewed 24

I found out that it is possible to assign to class variables after class definitions and that methods are technically class variables. So I tried the following, which appeared to work.

class Fruit():
    def __init__(self, name, price):
        self.name = name
        self.price = price

a = Fruit('apple', 5)

Fruit.__init__ = lambda self: None
b = Fruit()

Can something like this potentially break things? On the other hand, is there a practical situation where this can be useful?

2 Answers

Of course it can and will break things. Any other code that tries to initialize a Fruit with a name and a price will now raise an exception, as the replaced constructor doesn't accept those parameters.

In general, the only practical situation is mocking/patching for tests (or certain, very rare runtime cases where there is no other way). However, that patching is best done with a library to deal with it, e.g. the standard library's unittest.mock.

It is very dangerous to have direct access to class instances for many reasons.

1- Changing the Name of an Instance Variable

The first problem with direct access is that changing the name of an instance variable will break any client code that uses the original name directly. if the developer changes the name of an instance variable in the class from self.originalName to self.newName, then any client software that uses the original name directly will break.

2- Changing an Instance Variable into a Calculation

A second situation where direct access is problematic is when the code of a class needs to change to meet new requirements. Suppose that when writing a class, you use an instance variable to represent a piece of data, but the functionality changes so that you need an algorithm to compute a value instead.

3- Validating Data

The third reason to avoid direct access when setting a value is that client code can too easily set an instance variable to an invalid value. A better approach is to call a method in the class, whose job is to set the value. As the developer, you can include validation code in that method to ensure that the value being set is appropriate.

So, it is always better to use getters and setters methods just in case an instance variable needs to be accessed from outside the class. But, there are certain circumstances where it is safe to use direct access: when it is absolutely clear what the instance variable means, little or no validation of the data is needed, and there is no chance that the name will ever change. A good example of this is the Rect (rectangle) class in the pygame package. A rectangle in pygame is defined using four values—x, y, width, and height—like this:

oRectangle = pygame.Rect(10, 20, 300, 300)

After creating that rectangle object, using oRectangle.x, oRectangle.y, oRectangle.width, and oRectangle.height directly as variables seems acceptable

Source: Object-oriented python by Irv Kalb

Related