Course 1.1Lesson 3 of 5
An object has a state, which is the values of its attributes, and its methods read and change that state. A method can return an answer or change the data, and a good method does one of the two clearly. The rules of a thing belong inside the class: a bank account refuses a withdrawal of more money than it has, and refuses a deposit that is not more than zero, by raising a ValueError. A caller then needs no check of its own. Default values for parameters work in methods as in functions. Test a class by making objects and checking the state after each action.
Try the code and the simulations beside the lesson.
After this lesson you can
The values of an object's attributes, at a moment, are its state. A dog that is 3 years old is in a different state from the same dog at 4. A method often changes the state: birthday() adds one to the age. Other methods only look at the state and answer a question.
A bank account is the classic example. It has an owner and a balance. It can take a deposit and give a withdrawal. And it has rules: you cannot withdraw more than the balance, and a deposit must be a positive number.
Predict first. The account starts with 500, receives 250 and gives 100. What does show() say? Then which of the three actions in the loop are refused? Then run it.
The balance after the first three actions is 650. Look at the design.
__init__(self, owner, balance=0) has a default value: an account that is opened with no balance starts at 0. Defaults work in methods as they do in functions.deposit checks the rule first, and raises a ValueError if it is broken. Only then does it change the balance.withdraw refuses to give more than the balance. If it did not, the balance could become negative, and the account would be in a state that should be impossible.show only looks. It returns a text, and does not change anything.getattr(account, action) to call a method whose name is in a text. It is a neat trick for a table of tests. getattr(account, "deposit") is the same as account.deposit.The main program has no if for the rules. The class keeps its own rules. This is a great gain. Whoever uses the account, in any part of a big program, cannot break it.
A good method does one of two jobs.
deposit, withdraw, birthday.show, area, is_available.Mixing the two is a trap. A method called area that also changes the width would surprise everybody.
A test of a class follows the state: write the balance you expect after each call, then compare.
To test a class, make an object, perform actions, and check the state after each one, with the answers worked out by hand.
| Action | Balance should be |
|---|---|
| open with 500 | 500 |
| deposit 250 | 750 |
| withdraw 100 | 650 |
| withdraw 5000 | refused, still 650 |
| deposit -20 | refused, still 650 |
| deposit 40 | 690 |
The refused actions are the most important rows. The balance must not change when an action is refused. Does it? In withdraw, the check comes before the change, so yes.
In Python you can write account.balance = 1000000, and the rules are skipped. Python trusts the programmer. Many programmers mark an attribute that outsiders should not touch with an underscore, _balance, as a friendly warning. More advanced tools can protect it. For now, the habit is: change the state through the methods, and only read the attributes directly.
self. before the attribute in self.balance = self.balance + amount.Start with two quick questions. Each New numbers gives you a fresh one, so you can practise as long as you like.
Then the labs and the problems:
Try each one on your own first. If you are stuck, open a hint. Then check with Show the answer.
withdraw check the balance before it changes it?show() change?Every lesson is open to read. Enrolling also lets you:
Log in to join the discussion.
Loading…
This lesson is free to read. Enroll free to keep your place and take the tests.