<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://teaching.healthtech.dtu.dk:443/22118/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=WikiSysop</id>
	<title>22118 - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://teaching.healthtech.dtu.dk:443/22118/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=WikiSysop"/>
	<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php/Special:Contributions/WikiSysop"/>
	<updated>2026-04-14T18:30:37Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.41.0</generator>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=309</id>
		<title>Beginning unit test</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=309"/>
		<updated>2026-04-14T16:37:28Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Exercises to be handed in */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Intermediate classes]]&lt;br /&gt;
|Next: [[Intermediate unit test]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_09-Testing.ppt Testing]&amp;lt;br&amp;gt;&lt;br /&gt;
Online: [https://docs.pytest.org/ pytest documentation]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Example code - Unit test]]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Unit test - start of reverse polish notation class]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installation of pytest ===&lt;br /&gt;
If you are using an anaconda python installation pytest is included. You can test in your python has pytest.&lt;br /&gt;
 # On command line both should work or none&lt;br /&gt;
 python3 -c &amp;quot;import pytest&amp;quot;&lt;br /&gt;
 which pytest&lt;br /&gt;
 # It is pretty clear if you fail. Success can be more obscure.&lt;br /&gt;
 # Here is a fail test, so you can compare&lt;br /&gt;
 python3 -c &amp;quot;import yptest&amp;quot;&lt;br /&gt;
 which yptest&lt;br /&gt;
To install pytest, you need to be root/administrator.&lt;br /&gt;
 # An install on a basic system&lt;br /&gt;
 pip install -U pytest&lt;br /&gt;
 # or maybe (depending on your system)&lt;br /&gt;
 sudo pip install -U pytest&lt;br /&gt;
 # Using ubuntu, which is also WSL in this situation, there is a package&lt;br /&gt;
 apt install python3-pytest&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Overview of test methods&amp;lt;br&amp;gt;&lt;br /&gt;
Unit test using pytest framework.&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
You should make a special folder for the exercises. I will refer to my special folder as &#039;&#039;unittest&#039;&#039; in these exercises. You will also see some &#039;&#039;__pycache__&#039;&#039; folders appear in places. This is Pythons cache for &amp;quot;compiled&amp;quot; programs. It is safe to ignore and also to delete, because it may become outdated.&amp;lt;br&amp;gt;&lt;br /&gt;
In some of these exercise you need to hand in not just a single file, but multiple files in a folder hierarchy. Zip the folder structure for your entire solution folder. Make sure it is clear to see what exercise your code/data is solving. And learn to zip :-)&lt;br /&gt;
# Use your &#039;&#039;&#039;normalize&#039;&#039;&#039; function from exercise 3 in [[Functions, namespace, memory management]]. If you did not do so already, change it to use exceptions instead of &#039;&#039;&#039;sys.exit()&#039;&#039;&#039;, when an error occurs. Now make simple unit tests for the following test cases: a list of positive numbers, a list of negative numbers, a list of integers, a list of mixed floats and integers, a single number in the list, empty list, a list with at least one non-number (string, list, set), a set containing numbers, and a dict where the keys are numbers. Get other ideas if you can. The &#039;&#039;&#039;normalize&#039;&#039;&#039; function and all test functions must be in one single file (&#039;&#039;normalize_test.py&#039;&#039; in &#039;&#039;unittest&#039;&#039;), which you can run &#039;&#039;pytest&#039;&#039; on.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Now remove the &#039;&#039;&#039;normalize&#039;&#039;&#039; function from &#039;&#039;normalize_test.py&#039;&#039; and put it in its own file &#039;&#039;normalize.py&#039;&#039;. Import it from the &#039;&#039;normalize_test.py&#039;&#039; like &#039;&#039;&#039;from normalize import normalize&#039;&#039;&#039;. The first &#039;&#039;normalize&#039;&#039; is the name of the .py file, the second &#039;&#039;normalize&#039;&#039; is the name of your normalize function. Just run &#039;&#039;pytest&#039;&#039; (no file name) in the folder to check it works. It is more normal to have test and function separated.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Above we removed test code from function code by creating two files. Next, put the files in their own folder in &#039;&#039;unittest&#039;&#039;. I would put my &#039;&#039;normalize.py&#039;&#039; in &#039;&#039;unittest/src&#039;&#039; and &#039;&#039;normalize_test.py&#039;&#039; in &#039;&#039;unittest/test&#039;&#039;. This way there is a very clear separation between function and test. The problem is making sure the test code loads the function code. Do it wrong a couple of times - it is very instructive for how the search path works. Try to run the test from a different folder (unittest), like &amp;quot;pytest test/normalize_test.py&amp;quot; to see how vulnerable just using the path is.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# You hopefully remember the &#039;&#039;&#039;MyMath&#039;&#039;&#039; class you made in exercise 1 &amp;amp; 2 in [[Beginning classes]]. Make a folder &#039;&#039;classes&#039;&#039; in your &#039;&#039;unittest/src&#039;&#039; folder and put the &#039;&#039;MyMath&#039;&#039; class in a file &#039;&#039;MyMath.py&#039;&#039; in &#039;&#039;unittest/src/classes&#039;&#039;. Now make a unit test file &#039;&#039;MyMath_factorial_test.py&#039;&#039; in &#039;&#039;unittest/test&#039;&#039; that - surprise - tests your factorial method. Test it with at least these input: 12, 2, 1, 0, -1, 3.0, 3.4, &amp;quot;3&amp;quot;, &amp;quot;3.1.&amp;quot;, &amp;quot;ABC&amp;quot;. Parametrize at least the tests that should succeed. Bonus for parametrizing the exceptions.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# &#039;&#039;MyMath&#039;&#039; class also contains the &#039;&#039;supply&#039;&#039; method. Make unit tests for that method in the file &#039;&#039;unittest/test/MyMath_supply_test.py&#039;&#039;. Make the &amp;quot;usual&amp;quot; tests, which are the same as you did in the first exercise.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Now make unit tests for the &#039;&#039;average&#039;&#039; method in &#039;&#039;&#039;MyMath&#039;&#039;&#039;. Make the tests in the file &#039;&#039;unittest/test/MyMath_average_test.py&#039;&#039;. Notice how that interacts with the &#039;&#039;supply&#039;&#039; unit tests because &#039;&#039;average&#039;&#039; depends on correct working of &#039;&#039;supply&#039;&#039;. Sometimes you won&#039;t even find the flaw in one method before you test another that depends on it. I am not going to tell you this time what unit tests you should make. You should know by now.&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=308</id>
		<title>Beginning unit test</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=308"/>
		<updated>2026-04-14T16:36:12Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Exercises to be handed in */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Intermediate classes]]&lt;br /&gt;
|Next: [[Intermediate unit test]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_09-Testing.ppt Testing]&amp;lt;br&amp;gt;&lt;br /&gt;
Online: [https://docs.pytest.org/ pytest documentation]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Example code - Unit test]]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Unit test - start of reverse polish notation class]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installation of pytest ===&lt;br /&gt;
If you are using an anaconda python installation pytest is included. You can test in your python has pytest.&lt;br /&gt;
 # On command line both should work or none&lt;br /&gt;
 python3 -c &amp;quot;import pytest&amp;quot;&lt;br /&gt;
 which pytest&lt;br /&gt;
 # It is pretty clear if you fail. Success can be more obscure.&lt;br /&gt;
 # Here is a fail test, so you can compare&lt;br /&gt;
 python3 -c &amp;quot;import yptest&amp;quot;&lt;br /&gt;
 which yptest&lt;br /&gt;
To install pytest, you need to be root/administrator.&lt;br /&gt;
 # An install on a basic system&lt;br /&gt;
 pip install -U pytest&lt;br /&gt;
 # or maybe (depending on your system)&lt;br /&gt;
 sudo pip install -U pytest&lt;br /&gt;
 # Using ubuntu, which is also WSL in this situation, there is a package&lt;br /&gt;
 apt install python3-pytest&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Overview of test methods&amp;lt;br&amp;gt;&lt;br /&gt;
Unit test using pytest framework.&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
You should make a special folder for the exercises. I will refer to my special folder as &#039;&#039;unittest&#039;&#039; in these exercises. You will also see some &#039;&#039;__pycache__&#039;&#039; folders appear in places. This is Pythons cache for &amp;quot;compiled&amp;quot; programs. It is safe to ignore and also to delete, because it may become outdated.&amp;lt;br&amp;gt;&lt;br /&gt;
In some of these exercise you need to hand in not just a single file, but multiple files in a folder hierarchy. Zip the folder structure for your entire solution folder. Make sure it is clear to see what exercise your code/data is solving. And learn to zip :-)&lt;br /&gt;
# Use your &#039;&#039;&#039;normalize&#039;&#039;&#039; function from exercise 3 in [[Functions, namespace, memory management]]. If you did not do so already, change it to use exceptions instead of &#039;&#039;&#039;sys.exit()&#039;&#039;&#039;, when an error occurs. Now make simple unit tests for the following test cases: a list of positive numbers, a list of negative numbers, a list of integers, a list of mixed floats and integers, a single number in the list, empty list, a list with at least one non-number (string, list, set), a set containing numbers, and a dict where the keys are numbers. Get other ideas if you can. The &#039;&#039;&#039;normalize&#039;&#039;&#039; function and all test functions must be in one single file (&#039;&#039;normalize_test.py&#039;&#039; in &#039;&#039;unittest&#039;&#039;), which you can run &#039;&#039;pytest&#039;&#039; on.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Now remove the &#039;&#039;&#039;normalize&#039;&#039;&#039; function from &#039;&#039;normalize_test.py&#039;&#039; and put it in its own file &#039;&#039;normalize.py&#039;&#039;. Import it from the &#039;&#039;normalize_test.py&#039;&#039; like &#039;&#039;&#039;from normalize import normalize&#039;&#039;&#039;. The first &#039;&#039;normalize&#039;&#039; is the name of the .py file, the second &#039;&#039;normalize&#039;&#039; is the name of your normalize function. Just run &#039;&#039;pytest&#039;&#039; (no file name) in the folder to check it works. It is more normal to have test and function separated.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Above we removed test code from function code by creating two files. Next, put the files in their own folder in &#039;&#039;unittest&#039;&#039;. I would put my &#039;&#039;normalize.py&#039;&#039; in &#039;&#039;unittest/src&#039;&#039; and &#039;&#039;normalize_test.py&#039;&#039; in &#039;&#039;unittest/test&#039;&#039;. This way there is a very clear separation between function and test. The problem is making sure the test code loads the function code. Do it wrong a couple of times - it is very instructive for how the search path works. Try to run the test from a different folder, like &amp;quot;pytest test/normalize_test.py&amp;quot; to see how vulnerable just using the path is.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# You hopefully remember the &#039;&#039;&#039;MyMath&#039;&#039;&#039; class you made in exercise 1 &amp;amp; 2 in [[Beginning classes]]. Make a folder &#039;&#039;classes&#039;&#039; in your &#039;&#039;unittest/src&#039;&#039; folder and put the &#039;&#039;MyMath&#039;&#039; class in a file &#039;&#039;MyMath.py&#039;&#039; in &#039;&#039;unittest/src/classes&#039;&#039;. Now make a unit test file &#039;&#039;MyMath_factorial_test.py&#039;&#039; in &#039;&#039;unittest/test&#039;&#039; that - surprise - tests your factorial method. Test it with at least these input: 12, 2, 1, 0, -1, 3.0, 3.4, &amp;quot;3&amp;quot;, &amp;quot;3.1.&amp;quot;, &amp;quot;ABC&amp;quot;. Parametrize at least the tests that should succeed. Bonus for parametrizing the exceptions.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# &#039;&#039;MyMath&#039;&#039; class also contains the &#039;&#039;supply&#039;&#039; method. Make unit tests for that method in the file &#039;&#039;unittest/test/MyMath_supply_test.py&#039;&#039;. Make the &amp;quot;usual&amp;quot; tests, which are the same as you did in the first exercise.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Now make unit tests for the &#039;&#039;average&#039;&#039; method in &#039;&#039;&#039;MyMath&#039;&#039;&#039;. Make the tests in the file &#039;&#039;unittest/test/MyMath_average_test.py&#039;&#039;. Notice how that interacts with the &#039;&#039;supply&#039;&#039; unit tests because &#039;&#039;average&#039;&#039; depends on correct working of &#039;&#039;supply&#039;&#039;. Sometimes you won&#039;t even find the flaw in one method before you test another that depends on it. I am not going to tell you this time what unit tests you should make. You should know by now.&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=307</id>
		<title>Beginning unit test</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=307"/>
		<updated>2026-04-14T14:54:42Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Exercises to be handed in */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Intermediate classes]]&lt;br /&gt;
|Next: [[Intermediate unit test]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_09-Testing.ppt Testing]&amp;lt;br&amp;gt;&lt;br /&gt;
Online: [https://docs.pytest.org/ pytest documentation]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Example code - Unit test]]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Unit test - start of reverse polish notation class]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installation of pytest ===&lt;br /&gt;
If you are using an anaconda python installation pytest is included. You can test in your python has pytest.&lt;br /&gt;
 # On command line both should work or none&lt;br /&gt;
 python3 -c &amp;quot;import pytest&amp;quot;&lt;br /&gt;
 which pytest&lt;br /&gt;
 # It is pretty clear if you fail. Success can be more obscure.&lt;br /&gt;
 # Here is a fail test, so you can compare&lt;br /&gt;
 python3 -c &amp;quot;import yptest&amp;quot;&lt;br /&gt;
 which yptest&lt;br /&gt;
To install pytest, you need to be root/administrator.&lt;br /&gt;
 # An install on a basic system&lt;br /&gt;
 pip install -U pytest&lt;br /&gt;
 # or maybe (depending on your system)&lt;br /&gt;
 sudo pip install -U pytest&lt;br /&gt;
 # Using ubuntu, which is also WSL in this situation, there is a package&lt;br /&gt;
 apt install python3-pytest&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Overview of test methods&amp;lt;br&amp;gt;&lt;br /&gt;
Unit test using pytest framework.&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
You should make a special folder for the exercises. I will refer to my special folder as &#039;&#039;unittest&#039;&#039; in these exercises. You will also see some &#039;&#039;__pycache__&#039;&#039; folders appear in places. This is Pythons cache for &amp;quot;compiled&amp;quot; programs. It is safe to ignore and also to delete, because it may become outdated.&amp;lt;br&amp;gt;&lt;br /&gt;
In some of these exercise you need to hand in not just a single file, but multiple files in a folder hierarchy. Zip the folder structure for your entire solution folder. Make sure it is clear to see what exercise your code/data is solving. And learn to zip :-)&lt;br /&gt;
# Use your &#039;&#039;&#039;normalize&#039;&#039;&#039; function from exercise 3 in [[Functions, namespace, memory management]]. If you did not do so already, change it to use exceptions instead of &#039;&#039;&#039;sys.exit()&#039;&#039;&#039;, when an error occurs. Now make simple unit tests for the following test cases: a list of positive numbers, a list of negative numbers, a list of integers, a list of mixed floats and integers, a single number in the list, empty list, a list with at least one non-number (string, list, set), a set containing numbers, and a dict where the keys are numbers. Get other ideas if you can. The &#039;&#039;&#039;normalize&#039;&#039;&#039; function and all test functions must be in one single file (&#039;&#039;normalize_test.py&#039;&#039; in &#039;&#039;unittest&#039;&#039;), which you can run &#039;&#039;pytest&#039;&#039; on.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Now remove the &#039;&#039;&#039;normalize&#039;&#039;&#039; function from &#039;&#039;normalize_test.py&#039;&#039; and put it in its own file &#039;&#039;normalize.py&#039;&#039;. Import it from the &#039;&#039;normalize_test.py&#039;&#039; like &#039;&#039;&#039;from normalize import normalize&#039;&#039;&#039;. The first &#039;&#039;normalize&#039;&#039; is the name of the .py file, the second &#039;&#039;normalize&#039;&#039; is the name of your normalize function. Just run &#039;&#039;pytest&#039;&#039; (no file name) in the folder to check it works. It is more normal to have test and function separated.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Above we removed test code from function code by creating two files. Next, put the files in their own folder in &#039;&#039;unittest&#039;&#039;. I would put my &#039;&#039;normalize.py&#039;&#039; in &#039;&#039;unittest/src&#039;&#039; and &#039;&#039;normalize_test.py&#039;&#039; in &#039;&#039;unittest/test&#039;&#039;. This way there is a very clear separation between function and test. The problem is making sure the test code loads the function code. Do it wrong a couple of times - it is very instructive.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# You hopefully remember the &#039;&#039;&#039;MyMath&#039;&#039;&#039; class you made in exercise 1 &amp;amp; 2 in [[Beginning classes]]. Make a folder &#039;&#039;classes&#039;&#039; in your &#039;&#039;unittest/src&#039;&#039; folder and put the &#039;&#039;MyMath&#039;&#039; class in a file &#039;&#039;MyMath.py&#039;&#039; in &#039;&#039;unittest/src/classes&#039;&#039;. Now make a unit test file &#039;&#039;MyMath_factorial_test.py&#039;&#039; in &#039;&#039;unittest/test&#039;&#039; that - surprise - tests your factorial method. Test it with at least these input: 12, 2, 1, 0, -1, 3.0, 3.4, &amp;quot;3&amp;quot;, &amp;quot;3.1.&amp;quot;, &amp;quot;ABC&amp;quot;. Parametrize at least the tests that should succeed. Bonus for parametrizing the exceptions.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# &#039;&#039;MyMath&#039;&#039; class also contains the &#039;&#039;supply&#039;&#039; method. Make unit tests for that method in the file &#039;&#039;unittest/test/MyMath_supply_test.py&#039;&#039;. Make the &amp;quot;usual&amp;quot; tests, which are the same as you did in the first exercise.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Now make unit tests for the &#039;&#039;average&#039;&#039; method in &#039;&#039;&#039;MyMath&#039;&#039;&#039;. Make the tests in the file &#039;&#039;unittest/test/MyMath_average_test.py&#039;&#039;. Notice how that interacts with the &#039;&#039;supply&#039;&#039; unit tests because &#039;&#039;average&#039;&#039; depends on correct working of &#039;&#039;supply&#039;&#039;. Sometimes you won&#039;t even find the flaw in one method before you test another that depends on it. I am not going to tell you this time what unit tests you should make. You should know by now.&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=306</id>
		<title>Beginning unit test</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=306"/>
		<updated>2026-04-14T14:52:37Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Exercises to be handed in */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Intermediate classes]]&lt;br /&gt;
|Next: [[Intermediate unit test]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_09-Testing.ppt Testing]&amp;lt;br&amp;gt;&lt;br /&gt;
Online: [https://docs.pytest.org/ pytest documentation]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Example code - Unit test]]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Unit test - start of reverse polish notation class]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installation of pytest ===&lt;br /&gt;
If you are using an anaconda python installation pytest is included. You can test in your python has pytest.&lt;br /&gt;
 # On command line both should work or none&lt;br /&gt;
 python3 -c &amp;quot;import pytest&amp;quot;&lt;br /&gt;
 which pytest&lt;br /&gt;
 # It is pretty clear if you fail. Success can be more obscure.&lt;br /&gt;
 # Here is a fail test, so you can compare&lt;br /&gt;
 python3 -c &amp;quot;import yptest&amp;quot;&lt;br /&gt;
 which yptest&lt;br /&gt;
To install pytest, you need to be root/administrator.&lt;br /&gt;
 # An install on a basic system&lt;br /&gt;
 pip install -U pytest&lt;br /&gt;
 # or maybe (depending on your system)&lt;br /&gt;
 sudo pip install -U pytest&lt;br /&gt;
 # Using ubuntu, which is also WSL in this situation, there is a package&lt;br /&gt;
 apt install python3-pytest&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Overview of test methods&amp;lt;br&amp;gt;&lt;br /&gt;
Unit test using pytest framework.&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
You should make a special folder for the exercises. I will refer to my special folder as &#039;&#039;unittest&#039;&#039; in these exercises. You will also see some &#039;&#039;__pycache__&#039;&#039; folders appear in places. This is Pythons cache for &amp;quot;compiled&amp;quot; programs. It is safe to ignore and also to delete, because it may become outdated.&amp;lt;br&amp;gt;&lt;br /&gt;
In some of these exercise you need to hand in not just a single file, but multiple files in a folder hierarchy. Zip the folder structure for your entire solution folder. Make sure it is clear to see what exercise your code/data is solving. And learn to zip :-)&lt;br /&gt;
# Use your &#039;&#039;&#039;normalize&#039;&#039;&#039; function from exercise 3 in [[Functions, namespace, memory management]]. If you did not do so already, change it to use exceptions instead of &#039;&#039;&#039;sys.exit()&#039;&#039;&#039;, when an error occurs. Now make simple unit tests for the following test cases: a list of positive numbers, a list of negative numbers, a list of integers, a list of mixed floats and integers, a single number in the list, empty list, a list with at least one non-number (string, list, set), a set containing numbers, and a dict where the keys are numbers. Get other ideas if you can. The &#039;&#039;&#039;normalize&#039;&#039;&#039; function and all test functions must be in one single file (&#039;&#039;normalize_test.py&#039;&#039; in &#039;&#039;unittest&#039;&#039;), which you can run &#039;&#039;pytest&#039;&#039; on.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Now remove the &#039;&#039;&#039;normalize&#039;&#039;&#039; function from &#039;&#039;normalize_test.py&#039;&#039; and put it in its own file &#039;&#039;normalize.py&#039;&#039;. Import it from the &#039;&#039;normalize_test.py&#039;&#039; like &#039;&#039;&#039;from normalize import normalize&#039;&#039;&#039;. The first &#039;&#039;normalize&#039;&#039; is the name of the .py file, the second &#039;&#039;normalize&#039;&#039; is the name of your normalize function. Just run &#039;&#039;pytest&#039;&#039; (no file name) in the folder to check it works. It is more normal to have test and function separated.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Above we removed test code from function code by creating two files. Next, put the files in their own folder in &#039;&#039;unittest&#039;&#039;. I would put my &#039;&#039;normalize.py&#039;&#039; in &#039;&#039;unittest/src&#039;&#039; and &#039;&#039;normalize_test.py&#039;&#039; in &#039;&#039;unittest/test&#039;&#039;. This way there is a very clear separation between function and test. The problem is making sure the test code loads the function code. Do it wrong a couple of times - it is very instructive.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# You hopefully remember the &#039;&#039;&#039;MyMath&#039;&#039;&#039; class you made in exercise 1 &amp;amp; 2 in [[Beginning classes]]. Make a folder &#039;&#039;classes&#039;&#039; in your &#039;&#039;unittest/src&#039;&#039; folder and put the &#039;&#039;MyMath&#039;&#039; class in a file &#039;&#039;MyMath.py&#039;&#039; in &#039;&#039;unittest/src/classes&#039;&#039;. Now make a unit test file &#039;&#039;MyMath_factorial_test.py&#039;&#039; in &#039;&#039;unittest/test&#039;&#039; that - surprise - tests your factorial method. Test it with at least these input: 12, 2, 1, 0, -1, 3.0, 3.4, &amp;quot;3&amp;quot;, &amp;quot;3.1.&amp;quot;, &amp;quot;ABC&amp;quot;. Parametrize at least the tests that should succeed. Bonus for parametrizing the exceptions.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# &#039;&#039;MyMath&#039;&#039; class also contains the &#039;&#039;supply&#039;&#039; method. Make unit tests for that method in the file &#039;&#039;unittest/test/MyMath_supply_test.py&#039;&#039;. Make the &amp;quot;usual&amp;quot; tests, which are the same as you did in the first exercise.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Now make unit tests for the &#039;&#039;average&#039;&#039; method in &#039;&#039;&#039;MyMath&#039;&#039;&#039;. Use the file &#039;&#039;unittest/test/MyMath_average_test.py&#039;&#039;. Notice how that interacts with the &#039;&#039;supply&#039;&#039; unit tests because &#039;&#039;average&#039;&#039; depends on correct working of &#039;&#039;supply&#039;&#039;. Sometimes you won&#039;t even find the flaw in one method before you test another that depends on it.&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=305</id>
		<title>Beginning unit test</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=305"/>
		<updated>2026-04-14T14:50:46Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Exercises to be handed in */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Intermediate classes]]&lt;br /&gt;
|Next: [[Intermediate unit test]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_09-Testing.ppt Testing]&amp;lt;br&amp;gt;&lt;br /&gt;
Online: [https://docs.pytest.org/ pytest documentation]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Example code - Unit test]]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Unit test - start of reverse polish notation class]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installation of pytest ===&lt;br /&gt;
If you are using an anaconda python installation pytest is included. You can test in your python has pytest.&lt;br /&gt;
 # On command line both should work or none&lt;br /&gt;
 python3 -c &amp;quot;import pytest&amp;quot;&lt;br /&gt;
 which pytest&lt;br /&gt;
 # It is pretty clear if you fail. Success can be more obscure.&lt;br /&gt;
 # Here is a fail test, so you can compare&lt;br /&gt;
 python3 -c &amp;quot;import yptest&amp;quot;&lt;br /&gt;
 which yptest&lt;br /&gt;
To install pytest, you need to be root/administrator.&lt;br /&gt;
 # An install on a basic system&lt;br /&gt;
 pip install -U pytest&lt;br /&gt;
 # or maybe (depending on your system)&lt;br /&gt;
 sudo pip install -U pytest&lt;br /&gt;
 # Using ubuntu, which is also WSL in this situation, there is a package&lt;br /&gt;
 apt install python3-pytest&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Overview of test methods&amp;lt;br&amp;gt;&lt;br /&gt;
Unit test using pytest framework.&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
You should make a special folder for the exercises. I will refer to my special folder as &#039;&#039;unittest&#039;&#039; in these exercises. You will also see some &#039;&#039;__pycache__&#039;&#039; folders appear in places. This is Pythons cache for &amp;quot;compiled&amp;quot; programs. It is safe to ignore and also to delete, because it may become outdated.&amp;lt;br&amp;gt;&lt;br /&gt;
In some of these exercise you need to hand in not just a single file, but multiple files in a folder hierarchy. Zip the folder structure for your entire solution folder. Make sure it is clear to see what exercise your code/data is solving. And learn to zip :-)&lt;br /&gt;
# Use your &#039;&#039;&#039;normalize&#039;&#039;&#039; function from exercise 3 in [[Functions, namespace, memory management]]. If you did not do so already, change it to use exceptions instead of &#039;&#039;&#039;sys.exit()&#039;&#039;&#039;, when an error occurs. Now make simple unit tests for the following test cases: a list of positive numbers, a list of negative numbers, a list of integers, a list of mixed floats and integers, a single number in the list, empty list, a list with at least one non-number (string, list, set), a set containing numbers, and a dict where the keys are numbers. Get other ideas if you can. The &#039;&#039;&#039;normalize&#039;&#039;&#039; function and all test functions must be in one single file (&#039;&#039;normalize_test.py&#039;&#039; in &#039;&#039;unittest&#039;&#039;), which you can run &#039;&#039;pytest&#039;&#039; on.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Now remove the &#039;&#039;&#039;normalize&#039;&#039;&#039; function from &#039;&#039;normalize_test.py&#039;&#039; and put it in its own file &#039;&#039;normalize.py&#039;&#039;. Import it from the &#039;&#039;normalize_test.py&#039;&#039; like &#039;&#039;&#039;from normalize import normalize&#039;&#039;&#039;. The first &#039;&#039;normalize&#039;&#039; is the name of the .py file, the second &#039;&#039;normalize&#039;&#039; is the name of your normalize function. Just run &#039;&#039;pytest&#039;&#039; (no file name) in the folder to check it works. It is more normal to have test and function separated.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Above we removed test code from function code by creating two files. Next, put the files in their own folder in &#039;&#039;unittest&#039;&#039;. I would put my &#039;&#039;normalize.py&#039;&#039; in &#039;&#039;unittest/src&#039;&#039; and &#039;&#039;normalize_test.py&#039;&#039; in &#039;&#039;unittest/test&#039;&#039;. This way there is a very clear separation between function and test. The problem is making sure the test code loads the function code. Do it wrong a couple of times - it is very instructive.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# You hopefully remember the &#039;&#039;&#039;MyMath&#039;&#039;&#039; class you made in exercise 1 &amp;amp; 2 in [[Beginning classes]]. Make a folder &#039;&#039;classes&#039;&#039; in your &#039;&#039;unittest/src&#039;&#039; folder and put the &#039;&#039;MyMath&#039;&#039; class in a file &#039;&#039;MyMath.py&#039;&#039; in &#039;&#039;unittest/src/classes&#039;&#039;. Now make a unit test file &#039;&#039;MyMath_factorial_test.py&#039;&#039; in &#039;&#039;unittest/test&#039;&#039; that - surprise - tests your factorial method. Test it with at least these input: 12, 2, 1, 0, -1, 3.0, 3.4, &amp;quot;3&amp;quot;, &amp;quot;3.1.&amp;quot;, &amp;quot;ABC&amp;quot;. Parametrize at least the tests that should succeed. Bonus for parametrizing the exceptions.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# &#039;&#039;MyMath&#039;&#039; class also contains the &#039;&#039;supply&#039;&#039; method. Make unit tests for that method in the file &#039;&#039;unittest/test/MyMath_supply_test.py&#039;&#039;. Make the &amp;quot;usual&amp;quot; tests, which are the same as you did in the first exercise.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Now make unit tests for the &#039;&#039;average&#039;&#039; method in &#039;&#039;MyMath&#039;&#039;. Use the file &#039;&#039;unittest/test/MyMath_average_test.py&#039;&#039;. Notice how that interacts with the &#039;&#039;supply&#039;&#039; unit tests because &#039;&#039;average&#039;&#039; depends on correct working of &#039;&#039;supply&#039;&#039;. Sometimes you won&#039;t even find the flaw in one method before you test another dependency.&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=304</id>
		<title>Beginning unit test</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=304"/>
		<updated>2026-04-14T14:50:20Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Exercises to be handed in */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Intermediate classes]]&lt;br /&gt;
|Next: [[Intermediate unit test]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_09-Testing.ppt Testing]&amp;lt;br&amp;gt;&lt;br /&gt;
Online: [https://docs.pytest.org/ pytest documentation]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Example code - Unit test]]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Unit test - start of reverse polish notation class]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installation of pytest ===&lt;br /&gt;
If you are using an anaconda python installation pytest is included. You can test in your python has pytest.&lt;br /&gt;
 # On command line both should work or none&lt;br /&gt;
 python3 -c &amp;quot;import pytest&amp;quot;&lt;br /&gt;
 which pytest&lt;br /&gt;
 # It is pretty clear if you fail. Success can be more obscure.&lt;br /&gt;
 # Here is a fail test, so you can compare&lt;br /&gt;
 python3 -c &amp;quot;import yptest&amp;quot;&lt;br /&gt;
 which yptest&lt;br /&gt;
To install pytest, you need to be root/administrator.&lt;br /&gt;
 # An install on a basic system&lt;br /&gt;
 pip install -U pytest&lt;br /&gt;
 # or maybe (depending on your system)&lt;br /&gt;
 sudo pip install -U pytest&lt;br /&gt;
 # Using ubuntu, which is also WSL in this situation, there is a package&lt;br /&gt;
 apt install python3-pytest&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Overview of test methods&amp;lt;br&amp;gt;&lt;br /&gt;
Unit test using pytest framework.&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
You should make a special folder for the exercises. I will refer to my special folder as &#039;&#039;unittest&#039;&#039; in these exercises. You will also see some &#039;&#039;__pycache__&#039;&#039; folders appear in places. This is Pythons cache for &amp;quot;compiled&amp;quot; programs. It is safe to ignore and also to delete, because it may become outdated.&amp;lt;br&amp;gt;&lt;br /&gt;
In some of these exercise you need to hand in not just a single file, but multiple files in a folder hierarchy. Zip the folder structure for your entire solution folder. Make sure it is clear to see what exercise your code/data is solving. And learn to zip :-)&lt;br /&gt;
# Use your &#039;&#039;&#039;normalize&#039;&#039;&#039; function from exercise 3 in [[Functions, namespace, memory management]]. If you did not do so already, change it to use exceptions instead of &#039;&#039;&#039;sys.exit()&#039;&#039;&#039;, when an error occurs. Now make simple unit tests for the following test cases: a list of positive numbers, a list of negative numbers, a list of integers, a list of mixed floats and integers, a single number in the list, empty list, a list with at least one non-number (string, list, set), a set containing numbers, and a dict where the keys are numbers. Get other ideas if you can. The &#039;&#039;&#039;normalize&#039;&#039;&#039; function and all test functions must be in one single file (&#039;&#039;normalize_test.py&#039;&#039; in &#039;&#039;unittest&#039;&#039;), which you can run &#039;&#039;pytest&#039;&#039; on.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Now remove the &#039;&#039;&#039;normalize&#039;&#039;&#039; function from &#039;&#039;normalize_test.py&#039;&#039; and put it in its own file &#039;&#039;normalize.py&#039;&#039;. Import it from the &#039;&#039;normalize_test.py&#039;&#039; like &#039;&#039;&#039;from normalize import normalize&#039;&#039;&#039;. The first &#039;&#039;normalize&#039;&#039; is the name of the .py file, the second &#039;&#039;normalize&#039;&#039; is the name of your normalize function. Just run &#039;&#039;pytest&#039;&#039; (no file name) in the folder to check it works. It is more normal to have test and function separated.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Above we removed test code from function code by creating two files. Next, put the files in their own folder in &#039;&#039;unittest&#039;&#039;. I would put my &#039;&#039;normalize.py&#039;&#039; in &#039;&#039;unittest/src&#039;&#039; and &#039;&#039;normalize_test.py&#039;&#039; in &#039;&#039;unittest/test&#039;&#039;. This way there is a very clear separation between function and test. The problem is making sure the test code loads the function code. Do it wrong a couple of times - it is very instructive.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# You hopefully remember the &#039;&#039;&#039;MyMath&#039;&#039;&#039; class you made in exercise 1 &amp;amp; 2 in [[Beginning classes]]. Make a folder &#039;&#039;classes&#039;&#039; in your &#039;&#039;unittest/src&#039;&#039; folder and put the &#039;&#039;MyMath&#039;&#039; class in a file &#039;&#039;MyMath.py&#039;&#039; in &#039;&#039;unittest/src/classes&#039;&#039;. Now make a unit test file &#039;&#039;MyMath_factorial_test.py&#039;&#039; in &#039;&#039;unittest/test&#039;&#039; that - surprise - tests your factorial method. Test it with at least these input: 12, 2, 1, 0, -1, 3.0, 3.4, &amp;quot;3&amp;quot;, &amp;quot;3.1.&amp;quot;, &amp;quot;ABC&amp;quot;. Parametrize at least the tests that should succeed. Bonus for parametrizing the exceptions.&lt;br /&gt;
# &#039;&#039;MyMath&#039;&#039; class also contains the &#039;&#039;supply&#039;&#039; method. Make unit tests for that method in the file &#039;&#039;unittest/test/MyMath_supply_test.py&#039;&#039;. Make the &amp;quot;usual&amp;quot; tests, which are the same as you did in the first exercise.&lt;br /&gt;
# Now make unit tests for the &#039;&#039;average&#039;&#039; method in &#039;&#039;MyMath&#039;&#039;. Use the file &#039;&#039;unittest/test/MyMath_average_test.py&#039;&#039;. Notice how that interacts with the &#039;&#039;supply&#039;&#039; unit tests because &#039;&#039;average&#039;&#039; depends on correct working of &#039;&#039;supply&#039;&#039;. Sometimes you won&#039;t even find the flaw in one method before you test another dependency.&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=303</id>
		<title>Beginning unit test</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=303"/>
		<updated>2026-04-14T14:39:24Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Installation of pytest */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Intermediate classes]]&lt;br /&gt;
|Next: [[Intermediate unit test]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_09-Testing.ppt Testing]&amp;lt;br&amp;gt;&lt;br /&gt;
Online: [https://docs.pytest.org/ pytest documentation]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Example code - Unit test]]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Unit test - start of reverse polish notation class]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installation of pytest ===&lt;br /&gt;
If you are using an anaconda python installation pytest is included. You can test in your python has pytest.&lt;br /&gt;
 # On command line both should work or none&lt;br /&gt;
 python3 -c &amp;quot;import pytest&amp;quot;&lt;br /&gt;
 which pytest&lt;br /&gt;
 # It is pretty clear if you fail. Success can be more obscure.&lt;br /&gt;
 # Here is a fail test, so you can compare&lt;br /&gt;
 python3 -c &amp;quot;import yptest&amp;quot;&lt;br /&gt;
 which yptest&lt;br /&gt;
To install pytest, you need to be root/administrator.&lt;br /&gt;
 # An install on a basic system&lt;br /&gt;
 pip install -U pytest&lt;br /&gt;
 # or maybe (depending on your system)&lt;br /&gt;
 sudo pip install -U pytest&lt;br /&gt;
 # Using ubuntu, which is also WSL in this situation, there is a package&lt;br /&gt;
 apt install python3-pytest&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Overview of test methods&amp;lt;br&amp;gt;&lt;br /&gt;
Unit test using pytest framework.&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
You should make a special folder for the exercises. I will refer to my special folder as &#039;&#039;unittest&#039;&#039; in these exercises. You will also see some &#039;&#039;__pycache__&#039;&#039; folders appear in places. This is Pythons cache for &amp;quot;compiled&amp;quot; programs. It is safe to ignore and also to delete, because it may become outdated.&amp;lt;br&amp;gt;&lt;br /&gt;
In some of these exercise you need to hand in not just a single file, but multiple files in a folder hierarchy. Zip the folder structure for your entire solution folder. Make sure it is clear to see what exercise your code/data is solving. And learn to zip :-)&lt;br /&gt;
# Use your &#039;&#039;&#039;normalize&#039;&#039;&#039; function from exercise 3 in [[Functions, namespace, memory management]]. If you did not do so already, change it to use exceptions instead of &#039;&#039;&#039;sys.exit()&#039;&#039;&#039;, when an error occurs. Now make simple unit tests for the following test cases: a list of positive numbers, a list of negative numbers, a list of integers, a list of mixed floats and integers, a single number in the list, empty list, a list with at least one non-number (string, list, set), a set containing numbers, and a dict where the keys are numbers. Get other ideas if you can. The &#039;&#039;&#039;normalize&#039;&#039;&#039; function and all test functions must be in one single file (&#039;&#039;normalize_test.py&#039;&#039; in &#039;&#039;unittest&#039;&#039;), which you can run &#039;&#039;pytest&#039;&#039; on.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Now remove the &#039;&#039;&#039;normalize&#039;&#039;&#039; function from &#039;&#039;normalize_test.py&#039;&#039; and put it in its own file &#039;&#039;normalize.py&#039;&#039;. Import it from the &#039;&#039;normalize_test.py&#039;&#039; like &#039;&#039;&#039;from normalize import normalize&#039;&#039;&#039;. The first &#039;&#039;normalize&#039;&#039; is the name of the .py file, the second &#039;&#039;normalize&#039;&#039; is the name of your normalize function. Just run &#039;&#039;pytest&#039;&#039; (no file name) in the folder to check it works. It is more normal to have test and function separated.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Above we removed test code from function code by creating two files. Next, put the files in their own folder in &#039;&#039;unittest&#039;&#039;. I would put my &#039;&#039;normalize.py&#039;&#039; in &#039;&#039;unittest/src&#039;&#039; and &#039;&#039;normalize_test.py&#039;&#039; in &#039;&#039;unittest/test&#039;&#039;. This way there is a very clear separation between function and test. The problem is making sure the test code loads the function code. Do it wrong a couple of times - it is very instructive.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# You hopefully remember the &#039;&#039;&#039;MyMath&#039;&#039;&#039; class you made in exercise 1 &amp;amp; 2 in [[Beginning classes]]. Make a folder &#039;&#039;classes&#039;&#039; in your &#039;&#039;unittest/src&#039;&#039; folder and put the &#039;&#039;MyMath&#039;&#039; class in a file &#039;&#039;MyMath.py&#039;&#039; in &#039;&#039;unittest/src/classes&#039;&#039;. Now make a unit test file &#039;&#039;MyMath_factorial_test.py&#039;&#039; in &#039;&#039;unittest/test&#039;&#039; that - surprise - tests your factorial method. Test it with at least these input: 12, 2, 1, 0, -1, 3.0, 3.4, &amp;quot;3&amp;quot;, &amp;quot;3.1.&amp;quot;, &amp;quot;ABC&amp;quot;. Parametrize at least the tests that should succeed. Bonus for parametrizing the exceptions.&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Intermediate_unit_test&amp;diff=302</id>
		<title>Intermediate unit test</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Intermediate_unit_test&amp;diff=302"/>
		<updated>2026-04-14T14:35:42Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Exercises for extra practice */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Beginning unit test]]&lt;br /&gt;
|Next: [[Runtime evaluation]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_09-Testing.ppt Testing]&amp;lt;br&amp;gt;&lt;br /&gt;
Online: [https://docs.pytest.org/ pytest documentation]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Unit test - start of reverse polish notation class]]&amp;lt;br&amp;gt;&lt;br /&gt;
Blog: [https://www.joelonsoftware.com/2000/04/30/top-five-wrong-reasons-you-dont-have-testers/ On testing], by the founder of StackExchange.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Unit test using pytest framework.&amp;lt;br&amp;gt;&lt;br /&gt;
Files, test data&amp;lt;br&amp;gt;&lt;br /&gt;
Setting up real projects&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
You should make a special folder for the exercises. I will refer to my special folder as &#039;&#039;unittest&#039;&#039; in these exercises. You will also see some &#039;&#039;__pycache__&#039;&#039; folders appear in places. This is Pythons cache for &amp;quot;compiled&amp;quot; programs. It is safe to ignore and also to delete, because it may become outdated.&lt;br /&gt;
# Follow the file structure of having a &#039;&#039;code&#039;&#039; (or &#039;&#039;src&#039;&#039;) folder for programs, a &#039;&#039;test&#039;&#039; folder for tests, and now a &#039;&#039;testdata&#039;&#039; folder for files containing test data. Now make unit tests and appropriate test data files for your &#039;&#039;&#039;fasta&#039;&#039;&#039; class from last week. In this exercise you just need to make unit test for the method &#039;&#039;&#039;load&#039;&#039;&#039;. You need to hand in both tests and test data.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add unit tests for the method &#039;&#039;&#039;save&#039;&#039;&#039; in your &#039;&#039;&#039;fasta&#039;&#039;&#039; class. Hand in same way as above.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add unit tests for the method &#039;&#039;&#039;delete&#039;&#039;&#039; in your &#039;&#039;&#039;fasta&#039;&#039;&#039; class. Hand in same way as above.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
I would not be surprised if you find errors in your &#039;&#039;&#039;fasta&#039;&#039;&#039; class based on these tests. I found flaws in my code.&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;br /&gt;
# Add unit tests for all methods in your &#039;&#039;&#039;fasta&#039;&#039;&#039; class. That will be a bit of work.&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=301</id>
		<title>Beginning unit test</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=301"/>
		<updated>2026-04-14T14:35:31Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Exercises for extra practice */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Intermediate classes]]&lt;br /&gt;
|Next: [[Intermediate unit test]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_09-Testing.ppt Testing]&amp;lt;br&amp;gt;&lt;br /&gt;
Online: [https://docs.pytest.org/ pytest documentation]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Example code - Unit test]]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Unit test - start of reverse polish notation class]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installation of pytest ===&lt;br /&gt;
If you are using an anaconda python installation pytest is included. You can test in your python has pytest.&lt;br /&gt;
 # On command line both should work or none&lt;br /&gt;
 python3 -c &amp;quot;import pytest&amp;quot;&lt;br /&gt;
 which pytest&lt;br /&gt;
 # It is pretty clear if you fail. Success can be more obscure.&lt;br /&gt;
 # Here is a fail test, so you can compare&lt;br /&gt;
 python3 -c &amp;quot;import yptest&amp;quot;&lt;br /&gt;
 which yptest&lt;br /&gt;
To install pytest, you need to be root/administrator.&lt;br /&gt;
 pip install -U pytest&lt;br /&gt;
 # or maybe (depending on your system)&lt;br /&gt;
 sudo pip install -U pytest&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Overview of test methods&amp;lt;br&amp;gt;&lt;br /&gt;
Unit test using pytest framework.&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
You should make a special folder for the exercises. I will refer to my special folder as &#039;&#039;unittest&#039;&#039; in these exercises. You will also see some &#039;&#039;__pycache__&#039;&#039; folders appear in places. This is Pythons cache for &amp;quot;compiled&amp;quot; programs. It is safe to ignore and also to delete, because it may become outdated.&amp;lt;br&amp;gt;&lt;br /&gt;
In some of these exercise you need to hand in not just a single file, but multiple files in a folder hierarchy. Zip the folder structure for your entire solution folder. Make sure it is clear to see what exercise your code/data is solving. And learn to zip :-)&lt;br /&gt;
# Use your &#039;&#039;&#039;normalize&#039;&#039;&#039; function from exercise 3 in [[Functions, namespace, memory management]]. If you did not do so already, change it to use exceptions instead of &#039;&#039;&#039;sys.exit()&#039;&#039;&#039;, when an error occurs. Now make simple unit tests for the following test cases: a list of positive numbers, a list of negative numbers, a list of integers, a list of mixed floats and integers, a single number in the list, empty list, a list with at least one non-number (string, list, set), a set containing numbers, and a dict where the keys are numbers. Get other ideas if you can. The &#039;&#039;&#039;normalize&#039;&#039;&#039; function and all test functions must be in one single file (&#039;&#039;normalize_test.py&#039;&#039; in &#039;&#039;unittest&#039;&#039;), which you can run &#039;&#039;pytest&#039;&#039; on.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Now remove the &#039;&#039;&#039;normalize&#039;&#039;&#039; function from &#039;&#039;normalize_test.py&#039;&#039; and put it in its own file &#039;&#039;normalize.py&#039;&#039;. Import it from the &#039;&#039;normalize_test.py&#039;&#039; like &#039;&#039;&#039;from normalize import normalize&#039;&#039;&#039;. The first &#039;&#039;normalize&#039;&#039; is the name of the .py file, the second &#039;&#039;normalize&#039;&#039; is the name of your normalize function. Just run &#039;&#039;pytest&#039;&#039; (no file name) in the folder to check it works. It is more normal to have test and function separated.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Above we removed test code from function code by creating two files. Next, put the files in their own folder in &#039;&#039;unittest&#039;&#039;. I would put my &#039;&#039;normalize.py&#039;&#039; in &#039;&#039;unittest/src&#039;&#039; and &#039;&#039;normalize_test.py&#039;&#039; in &#039;&#039;unittest/test&#039;&#039;. This way there is a very clear separation between function and test. The problem is making sure the test code loads the function code. Do it wrong a couple of times - it is very instructive.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# You hopefully remember the &#039;&#039;&#039;MyMath&#039;&#039;&#039; class you made in exercise 1 &amp;amp; 2 in [[Beginning classes]]. Make a folder &#039;&#039;classes&#039;&#039; in your &#039;&#039;unittest/src&#039;&#039; folder and put the &#039;&#039;MyMath&#039;&#039; class in a file &#039;&#039;MyMath.py&#039;&#039; in &#039;&#039;unittest/src/classes&#039;&#039;. Now make a unit test file &#039;&#039;MyMath_factorial_test.py&#039;&#039; in &#039;&#039;unittest/test&#039;&#039; that - surprise - tests your factorial method. Test it with at least these input: 12, 2, 1, 0, -1, 3.0, 3.4, &amp;quot;3&amp;quot;, &amp;quot;3.1.&amp;quot;, &amp;quot;ABC&amp;quot;. Parametrize at least the tests that should succeed. Bonus for parametrizing the exceptions.&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=300</id>
		<title>Beginning unit test</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=300"/>
		<updated>2026-04-14T14:32:23Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Exercises to be handed in */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Intermediate classes]]&lt;br /&gt;
|Next: [[Intermediate unit test]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_09-Testing.ppt Testing]&amp;lt;br&amp;gt;&lt;br /&gt;
Online: [https://docs.pytest.org/ pytest documentation]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Example code - Unit test]]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Unit test - start of reverse polish notation class]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installation of pytest ===&lt;br /&gt;
If you are using an anaconda python installation pytest is included. You can test in your python has pytest.&lt;br /&gt;
 # On command line both should work or none&lt;br /&gt;
 python3 -c &amp;quot;import pytest&amp;quot;&lt;br /&gt;
 which pytest&lt;br /&gt;
 # It is pretty clear if you fail. Success can be more obscure.&lt;br /&gt;
 # Here is a fail test, so you can compare&lt;br /&gt;
 python3 -c &amp;quot;import yptest&amp;quot;&lt;br /&gt;
 which yptest&lt;br /&gt;
To install pytest, you need to be root/administrator.&lt;br /&gt;
 pip install -U pytest&lt;br /&gt;
 # or maybe (depending on your system)&lt;br /&gt;
 sudo pip install -U pytest&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Overview of test methods&amp;lt;br&amp;gt;&lt;br /&gt;
Unit test using pytest framework.&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
You should make a special folder for the exercises. I will refer to my special folder as &#039;&#039;unittest&#039;&#039; in these exercises. You will also see some &#039;&#039;__pycache__&#039;&#039; folders appear in places. This is Pythons cache for &amp;quot;compiled&amp;quot; programs. It is safe to ignore and also to delete, because it may become outdated.&amp;lt;br&amp;gt;&lt;br /&gt;
In some of these exercise you need to hand in not just a single file, but multiple files in a folder hierarchy. Zip the folder structure for your entire solution folder. Make sure it is clear to see what exercise your code/data is solving. And learn to zip :-)&lt;br /&gt;
# Use your &#039;&#039;&#039;normalize&#039;&#039;&#039; function from exercise 3 in [[Functions, namespace, memory management]]. If you did not do so already, change it to use exceptions instead of &#039;&#039;&#039;sys.exit()&#039;&#039;&#039;, when an error occurs. Now make simple unit tests for the following test cases: a list of positive numbers, a list of negative numbers, a list of integers, a list of mixed floats and integers, a single number in the list, empty list, a list with at least one non-number (string, list, set), a set containing numbers, and a dict where the keys are numbers. Get other ideas if you can. The &#039;&#039;&#039;normalize&#039;&#039;&#039; function and all test functions must be in one single file (&#039;&#039;normalize_test.py&#039;&#039; in &#039;&#039;unittest&#039;&#039;), which you can run &#039;&#039;pytest&#039;&#039; on.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Now remove the &#039;&#039;&#039;normalize&#039;&#039;&#039; function from &#039;&#039;normalize_test.py&#039;&#039; and put it in its own file &#039;&#039;normalize.py&#039;&#039;. Import it from the &#039;&#039;normalize_test.py&#039;&#039; like &#039;&#039;&#039;from normalize import normalize&#039;&#039;&#039;. The first &#039;&#039;normalize&#039;&#039; is the name of the .py file, the second &#039;&#039;normalize&#039;&#039; is the name of your normalize function. Just run &#039;&#039;pytest&#039;&#039; (no file name) in the folder to check it works. It is more normal to have test and function separated.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Above we removed test code from function code by creating two files. Next, put the files in their own folder in &#039;&#039;unittest&#039;&#039;. I would put my &#039;&#039;normalize.py&#039;&#039; in &#039;&#039;unittest/src&#039;&#039; and &#039;&#039;normalize_test.py&#039;&#039; in &#039;&#039;unittest/test&#039;&#039;. This way there is a very clear separation between function and test. The problem is making sure the test code loads the function code. Do it wrong a couple of times - it is very instructive.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# You hopefully remember the &#039;&#039;&#039;MyMath&#039;&#039;&#039; class you made in exercise 1 &amp;amp; 2 in [[Beginning classes]]. Make a folder &#039;&#039;classes&#039;&#039; in your &#039;&#039;unittest/src&#039;&#039; folder and put the &#039;&#039;MyMath&#039;&#039; class in a file &#039;&#039;MyMath.py&#039;&#039; in &#039;&#039;unittest/src/classes&#039;&#039;. Now make a unit test file &#039;&#039;MyMath_factorial_test.py&#039;&#039; in &#039;&#039;unittest/test&#039;&#039; that - surprise - tests your factorial method. Test it with at least these input: 12, 2, 1, 0, -1, 3.0, 3.4, &amp;quot;3&amp;quot;, &amp;quot;3.1.&amp;quot;, &amp;quot;ABC&amp;quot;. Parametrize at least the tests that should succeed. Bonus for parametrizing the exceptions.&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;br /&gt;
# Add unit tests for all methods in your &#039;&#039;&#039;fasta&#039;&#039;&#039; class. That will be a bit of work.&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=299</id>
		<title>Beginning unit test</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=299"/>
		<updated>2026-04-14T14:32:02Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Exercises to be handed in */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Intermediate classes]]&lt;br /&gt;
|Next: [[Intermediate unit test]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_09-Testing.ppt Testing]&amp;lt;br&amp;gt;&lt;br /&gt;
Online: [https://docs.pytest.org/ pytest documentation]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Example code - Unit test]]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Unit test - start of reverse polish notation class]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installation of pytest ===&lt;br /&gt;
If you are using an anaconda python installation pytest is included. You can test in your python has pytest.&lt;br /&gt;
 # On command line both should work or none&lt;br /&gt;
 python3 -c &amp;quot;import pytest&amp;quot;&lt;br /&gt;
 which pytest&lt;br /&gt;
 # It is pretty clear if you fail. Success can be more obscure.&lt;br /&gt;
 # Here is a fail test, so you can compare&lt;br /&gt;
 python3 -c &amp;quot;import yptest&amp;quot;&lt;br /&gt;
 which yptest&lt;br /&gt;
To install pytest, you need to be root/administrator.&lt;br /&gt;
 pip install -U pytest&lt;br /&gt;
 # or maybe (depending on your system)&lt;br /&gt;
 sudo pip install -U pytest&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Overview of test methods&amp;lt;br&amp;gt;&lt;br /&gt;
Unit test using pytest framework.&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
You should make a special folder for the exercises. I will refer to my special folder as &#039;&#039;unittest&#039;&#039; in these exercises. You will also see some &#039;&#039;__pycache__&#039;&#039; folders appear in places. This is Pythons cache for &amp;quot;compiled&amp;quot; programs. It is safe to ignore and also to delete, because it may become outdated.&amp;lt;br&amp;gt;&lt;br /&gt;
In some of these exercise you need to hand in not just a single file, but multiple files in a folder hierarchy. Zip the folder structure for your entire solution folder. Make sure it is clear to see what exercise your code/data is solving. And learn to zip :-)&lt;br /&gt;
# Use your &#039;&#039;&#039;normalize&#039;&#039;&#039; function from exercise 3 in [[Functions, namespace, memory management]]. If you did not do so already, change it to use exceptions instead of &#039;&#039;&#039;sys.exit()&#039;&#039;&#039;, when an error occurs. Now make simple unit tests for the following test cases: a list of positive numbers, a list of negative numbers, a list of integers, a list of mixed floats and integers, a single number in the list, empty list, a list with at least one non-number (string, list, set), a set containing numbers, and a dict where the keys are numbers. Get other ideas if you can. The &#039;&#039;&#039;normalize&#039;&#039;&#039; function and all test functions must be in one single file (&#039;&#039;normalize_test.py&#039;&#039; in &#039;&#039;unittest&#039;&#039;), which you can run &#039;&#039;pytest&#039;&#039; on.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Now remove the &#039;&#039;&#039;normalize&#039;&#039;&#039; function from &#039;&#039;normalize_test.py&#039;&#039; and put it in its own file &#039;&#039;normalize.py&#039;&#039;. Import it from the &#039;&#039;normalize_test.py&#039;&#039; like &#039;&#039;&#039;from normalize import normalize&#039;&#039;&#039;. The first &#039;&#039;normalize&#039;&#039; is the name of the .py file, the second &#039;&#039;normalize&#039;&#039; is the name of your normalize function. Just run &#039;&#039;pytest&#039;&#039; (no file name) in the folder to check it works. It is more normal to have test and function separated.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Above we removed test code from function code by creating two files. Next, put the files in their own folder in &#039;&#039;unittest&#039;&#039;. I would put my &#039;&#039;normalize.py&#039;&#039; in &#039;&#039;unittest/src&#039;&#039; and &#039;&#039;normalize_test.py&#039;&#039; in &#039;&#039;unittest/test&#039;&#039;. This way there is a very clear separation between function and test. The problem is making sure the test code loads the function code. Do it wrong a couple of times - it is very instructive.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# You hopefully remember the &#039;&#039;&#039;MyMath&#039;&#039;&#039; class you made in exercise 1 &amp;amp; 2 in [[Beginning classes]]. Make a folder &#039;&#039;classes&#039;&#039; in your &#039;&#039;unittest/src&#039;&#039; folder and put the &#039;&#039;MyMath&#039;&#039; class in a file &#039;&#039;MyMath.py&#039;&#039; in &#039;unittest/src/classes&#039;&#039;. Now make a unit test file &#039;&#039;MyMath_factorial_test.py&#039;&#039; in &#039;&#039;unittest/test&#039;&#039; that - surprise - tests your factorial method. Test it with at least these input: 12, 2, 1, 0, -1, 3.0, 3.4, &amp;quot;3&amp;quot;, &amp;quot;3.1.&amp;quot;, &amp;quot;ABC&amp;quot;. Parametrize at least the tests that should succeed. Bonus for parametrizing the exceptions.&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;br /&gt;
# Add unit tests for all methods in your &#039;&#039;&#039;fasta&#039;&#039;&#039; class. That will be a bit of work.&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=298</id>
		<title>Beginning unit test</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=298"/>
		<updated>2026-04-14T14:26:39Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Exercises to be handed in */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Intermediate classes]]&lt;br /&gt;
|Next: [[Intermediate unit test]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_09-Testing.ppt Testing]&amp;lt;br&amp;gt;&lt;br /&gt;
Online: [https://docs.pytest.org/ pytest documentation]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Example code - Unit test]]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Unit test - start of reverse polish notation class]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installation of pytest ===&lt;br /&gt;
If you are using an anaconda python installation pytest is included. You can test in your python has pytest.&lt;br /&gt;
 # On command line both should work or none&lt;br /&gt;
 python3 -c &amp;quot;import pytest&amp;quot;&lt;br /&gt;
 which pytest&lt;br /&gt;
 # It is pretty clear if you fail. Success can be more obscure.&lt;br /&gt;
 # Here is a fail test, so you can compare&lt;br /&gt;
 python3 -c &amp;quot;import yptest&amp;quot;&lt;br /&gt;
 which yptest&lt;br /&gt;
To install pytest, you need to be root/administrator.&lt;br /&gt;
 pip install -U pytest&lt;br /&gt;
 # or maybe (depending on your system)&lt;br /&gt;
 sudo pip install -U pytest&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Overview of test methods&amp;lt;br&amp;gt;&lt;br /&gt;
Unit test using pytest framework.&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
You should make a special folder for the exercises. I will refer to my special folder as &#039;&#039;unittest&#039;&#039; in these exercises. You will also see some &#039;&#039;__pycache__&#039;&#039; folders appear in places. This is Pythons cache for &amp;quot;compiled&amp;quot; programs. It is safe to ignore and also to delete, because it may become outdated.&amp;lt;br&amp;gt;&lt;br /&gt;
In some of these exercise you need to hand in not just a single file, but multiple files in a folder hierarchy. Zip the folder structure for your entire solution folder. Make sure it is clear to see what exercise your code/data is solving. And learn to zip :-)&lt;br /&gt;
# Use your &#039;&#039;&#039;normalize&#039;&#039;&#039; function from exercise 3 in [[Functions, namespace, memory management]]. If you did not do so already, change it to use exceptions instead of &#039;&#039;&#039;sys.exit()&#039;&#039;&#039;, when an error occurs. Now make simple unit tests for the following test cases: a list of positive numbers, a list of negative numbers, a list of integers, a list of mixed floats and integers, a single number in the list, empty list, a list with at least one non-number (string, list, set), a set containing numbers, and a dict where the keys are numbers. Get other ideas if you can. The &#039;&#039;&#039;normalize&#039;&#039;&#039; function and all test functions must be in one single file (&#039;&#039;normalize_test.py&#039;&#039; in &#039;&#039;unittest&#039;&#039;), which you can run &#039;&#039;pytest&#039;&#039; on.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Now remove the &#039;&#039;&#039;normalize&#039;&#039;&#039; function from &#039;&#039;normalize_test.py&#039;&#039; and put it in its own file &#039;&#039;normalize.py&#039;&#039;. Import it from the &#039;&#039;normalize_test.py&#039;&#039; like &#039;&#039;&#039;from normalize import normalize&#039;&#039;&#039;. The first &#039;&#039;normalize&#039;&#039; is the name of the .py file, the second &#039;&#039;normalize&#039;&#039; is the name of your normalize function. Just run &#039;&#039;pytest&#039;&#039; (no file name) in the folder to check it works. It is more normal to have test and function separated.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Above we removed test code from function code by creating two files. Next, put the files in their own folder in &#039;&#039;unittest&#039;&#039;. I would put my &#039;&#039;normalize.py&#039;&#039; in &#039;&#039;unittest/src&#039;&#039; and &#039;&#039;normalize_test.py&#039;&#039; in &#039;&#039;unittest/test&#039;&#039;. This way there is a very clear separation between function and test. The problem is making sure the test code loads the function code. Do it wrong a couple of times - it is very instructive.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# You hopefully remember the &#039;&#039;&#039;MyMath&#039;&#039;&#039; class you made in exercise 1 &amp;amp; 2 in [[Beginning classes]]. Make a folder &#039;&#039;classes&#039; in your &#039;&#039;unittest/src&#039;&#039; folder and put the &#039;&#039;MyMath&#039;&#039; class in a file &#039;&#039;MyMath.py&#039;&#039; in &#039;unittest/src/classes&#039;&#039;. Now make a unit test file &#039;&#039;MyMath_factorial_test.py&#039;&#039; in &#039;&#039;unittest/test&#039;&#039; that - surprise - tests your factorial method.&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;br /&gt;
# Add unit tests for all methods in your &#039;&#039;&#039;fasta&#039;&#039;&#039; class. That will be a bit of work.&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Intermediate_unit_test&amp;diff=297</id>
		<title>Intermediate unit test</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Intermediate_unit_test&amp;diff=297"/>
		<updated>2026-04-14T14:16:24Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Exercises to be handed in */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Beginning unit test]]&lt;br /&gt;
|Next: [[Runtime evaluation]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_09-Testing.ppt Testing]&amp;lt;br&amp;gt;&lt;br /&gt;
Online: [https://docs.pytest.org/ pytest documentation]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Unit test - start of reverse polish notation class]]&amp;lt;br&amp;gt;&lt;br /&gt;
Blog: [https://www.joelonsoftware.com/2000/04/30/top-five-wrong-reasons-you-dont-have-testers/ On testing], by the founder of StackExchange.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Unit test using pytest framework.&amp;lt;br&amp;gt;&lt;br /&gt;
Files, test data&amp;lt;br&amp;gt;&lt;br /&gt;
Setting up real projects&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
You should make a special folder for the exercises. I will refer to my special folder as &#039;&#039;unittest&#039;&#039; in these exercises. You will also see some &#039;&#039;__pycache__&#039;&#039; folders appear in places. This is Pythons cache for &amp;quot;compiled&amp;quot; programs. It is safe to ignore and also to delete, because it may become outdated.&lt;br /&gt;
# Follow the file structure of having a &#039;&#039;code&#039;&#039; (or &#039;&#039;src&#039;&#039;) folder for programs, a &#039;&#039;test&#039;&#039; folder for tests, and now a &#039;&#039;testdata&#039;&#039; folder for files containing test data. Now make unit tests and appropriate test data files for your &#039;&#039;&#039;fasta&#039;&#039;&#039; class from last week. In this exercise you just need to make unit test for the method &#039;&#039;&#039;load&#039;&#039;&#039;. You need to hand in both tests and test data.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add unit tests for the method &#039;&#039;&#039;save&#039;&#039;&#039; in your &#039;&#039;&#039;fasta&#039;&#039;&#039; class. Hand in same way as above.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add unit tests for the method &#039;&#039;&#039;delete&#039;&#039;&#039; in your &#039;&#039;&#039;fasta&#039;&#039;&#039; class. Hand in same way as above.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
I would not be surprised if you find errors in your &#039;&#039;&#039;fasta&#039;&#039;&#039; class based on these tests. I found flaws in my code.&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=296</id>
		<title>Beginning unit test</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=296"/>
		<updated>2026-04-14T14:15:55Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Exercises to be handed in */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Intermediate classes]]&lt;br /&gt;
|Next: [[Intermediate unit test]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_09-Testing.ppt Testing]&amp;lt;br&amp;gt;&lt;br /&gt;
Online: [https://docs.pytest.org/ pytest documentation]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Example code - Unit test]]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Unit test - start of reverse polish notation class]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installation of pytest ===&lt;br /&gt;
If you are using an anaconda python installation pytest is included. You can test in your python has pytest.&lt;br /&gt;
 # On command line both should work or none&lt;br /&gt;
 python3 -c &amp;quot;import pytest&amp;quot;&lt;br /&gt;
 which pytest&lt;br /&gt;
 # It is pretty clear if you fail. Success can be more obscure.&lt;br /&gt;
 # Here is a fail test, so you can compare&lt;br /&gt;
 python3 -c &amp;quot;import yptest&amp;quot;&lt;br /&gt;
 which yptest&lt;br /&gt;
To install pytest, you need to be root/administrator.&lt;br /&gt;
 pip install -U pytest&lt;br /&gt;
 # or maybe (depending on your system)&lt;br /&gt;
 sudo pip install -U pytest&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Overview of test methods&amp;lt;br&amp;gt;&lt;br /&gt;
Unit test using pytest framework.&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
You should make a special folder for the exercises. I will refer to my special folder as &#039;&#039;unittest&#039;&#039; in these exercises. You will also see some &#039;&#039;__pycache__&#039;&#039; folders appear in places. This is Pythons cache for &amp;quot;compiled&amp;quot; programs. It is safe to ignore and also to delete, because it may become outdated.&amp;lt;br&amp;gt;&lt;br /&gt;
In some of these exercise you need to hand in not just a single file, but multiple files in a folder hierarchy. Zip the folder structure for your entire solution folder. Make sure it is clear to see what exercise your code/data is solving. And learn to zip :-)&lt;br /&gt;
# Use your &#039;&#039;&#039;normalize&#039;&#039;&#039; function from exercise 3 in [[Functions, namespace, memory management]]. If you did not do so already, change it to use exceptions instead of &#039;&#039;&#039;sys.exit()&#039;&#039;&#039;, when an error occurs. Now make simple unit tests for the following test cases: a list of positive numbers, a list of negative numbers, a list of integers, a list of mixed floats and integers, a single number in the list, empty list, a list with at least one non-number (string, list, set), a set containing numbers, and a dict where the keys are numbers. Get other ideas if you can. The &#039;&#039;&#039;normalize&#039;&#039;&#039; function and all test functions must be in one single file (&#039;&#039;normalize_test.py&#039;&#039; in &#039;&#039;unittest&#039;&#039;), which you can run &#039;&#039;pytest&#039;&#039; on.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Now remove the &#039;&#039;&#039;normalize&#039;&#039;&#039; function from &#039;&#039;normalize_test.py&#039;&#039; and put it in its own file &#039;&#039;normalize.py&#039;&#039;. Import it from the &#039;&#039;normalize_test.py&#039;&#039; like &#039;&#039;&#039;from normalize import normalize&#039;&#039;&#039;. The first &#039;&#039;normalize&#039;&#039; is the name of the .py file, the second &#039;&#039;normalize&#039;&#039; is the name of your normalize function. Just run &#039;&#039;pytest&#039;&#039; (no file name) in the folder to check it works. It is more normal to have test and function separated.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Above we removed test code from function code by creating two files. Next, put the files in their own folder in &#039;&#039;unittest&#039;&#039;. I would put my &#039;&#039;normalize.py&#039;&#039; in &#039;&#039;unittest/src&#039;&#039; and &#039;&#039;normalize_test.py&#039;&#039; in &#039;&#039;unittest/test&#039;&#039;. This way there is a very clear separation between function and test. The problem is making sure the test code loads the function code. Do it wrong a couple of times - it is very instructive.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;br /&gt;
# Add unit tests for all methods in your &#039;&#039;&#039;fasta&#039;&#039;&#039; class. That will be a bit of work.&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=295</id>
		<title>Beginning unit test</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=295"/>
		<updated>2026-04-13T10:06:00Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Required course material for the lesson */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Intermediate classes]]&lt;br /&gt;
|Next: [[Intermediate unit test]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_09-Testing.ppt Testing]&amp;lt;br&amp;gt;&lt;br /&gt;
Online: [https://docs.pytest.org/ pytest documentation]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Example code - Unit test]]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Unit test - start of reverse polish notation class]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installation of pytest ===&lt;br /&gt;
If you are using an anaconda python installation pytest is included. You can test in your python has pytest.&lt;br /&gt;
 # On command line both should work or none&lt;br /&gt;
 python3 -c &amp;quot;import pytest&amp;quot;&lt;br /&gt;
 which pytest&lt;br /&gt;
 # It is pretty clear if you fail. Success can be more obscure.&lt;br /&gt;
 # Here is a fail test, so you can compare&lt;br /&gt;
 python3 -c &amp;quot;import yptest&amp;quot;&lt;br /&gt;
 which yptest&lt;br /&gt;
To install pytest, you need to be root/administrator.&lt;br /&gt;
 pip install -U pytest&lt;br /&gt;
 # or maybe (depending on your system)&lt;br /&gt;
 sudo pip install -U pytest&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Overview of test methods&amp;lt;br&amp;gt;&lt;br /&gt;
Unit test using pytest framework.&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
You should make a special folder for the exercises. I will refer to my special folder as &#039;&#039;unittest&#039;&#039; in these exercises. You will also see some &#039;&#039;__pycache__&#039;&#039; folders appear in places. This is Pythons cache for &amp;quot;compiled&amp;quot; programs. It is safe to ignore and also to delete, because it may become outdated.&amp;lt;br&amp;gt;&lt;br /&gt;
In some of these exercise you need to hand in not just a single file, but multiple files in a folder hierarchy. Zip the folder structure for your entire solution folder. Make sure it is clear to see what exercise your code/data is solving. And learn to zip :-)&lt;br /&gt;
# Use your &#039;&#039;&#039;normalize&#039;&#039;&#039; function from exercise 3 in [[Functions, namespace, memory management]]. If you did not do so already, change it to use exceptions instead of &#039;&#039;&#039;sys.exit()&#039;&#039;&#039;, when an error occurs. Now make simple unit tests for the following test cases: a list of positive numbers, a list of negative numbers, a list of integers, a list of mixed floats and integers, a single number in the list, empty list, a list with at least one non-number (string, list, set), a set containing numbers, and a dict where the keys are numbers. Get other ideas if you can. The &#039;&#039;&#039;normalize&#039;&#039;&#039; function and all test functions must be in one single file (&#039;&#039;normalize_test.py&#039;&#039; in &#039;&#039;unittest&#039;&#039;), which you can run &#039;&#039;pytest&#039;&#039; on.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Now remove the &#039;&#039;&#039;normalize&#039;&#039;&#039; function from &#039;&#039;normalize_test.py&#039;&#039; and put it in its own file &#039;&#039;normalize.py&#039;&#039;. Import it from the &#039;&#039;normalize_test.py&#039;&#039; like &#039;&#039;&#039;from normalize import normalize&#039;&#039;&#039;. The first &#039;&#039;normalize&#039;&#039; is the name of the .py file, the second &#039;&#039;normalize&#039;&#039; is the name of your normalize function. Just run &#039;&#039;pytest&#039;&#039; (no file name) in the folder to check it works. It is more normal to have test and function separated.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Above we removed test code from function code by creating two files. Next, put the files in their own folder in &#039;&#039;unittest&#039;&#039;. I would put my &#039;&#039;normalize.py&#039;&#039; in &#039;&#039;unittest/src&#039;&#039; and &#039;&#039;normalize_test.py&#039;&#039; in &#039;&#039;unittest/test&#039;&#039;. This way there is a very clear separation between function and test. The problem is making sure the test code loads the function code. Do it wrong a couple of times - it is very instructive.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Follow the file structure of having a &#039;&#039;code&#039;&#039; (or &#039;&#039;src&#039;&#039;) folder for programs, a &#039;&#039;test&#039;&#039; folder for tests, and now a &#039;&#039;testdata&#039;&#039; folder for files containing test data. Now make unit tests and appropriate test data files for your &#039;&#039;&#039;fasta&#039;&#039;&#039; class from last week. In this exercise you just need to make unit test for the method &#039;&#039;&#039;load&#039;&#039;&#039;. You need to hand in both tests and test data.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add unit tests for the method &#039;&#039;&#039;save&#039;&#039;&#039; in your &#039;&#039;&#039;fasta&#039;&#039;&#039; class. Hand in same way as above.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add unit tests for the method &#039;&#039;&#039;delete&#039;&#039;&#039; in your &#039;&#039;&#039;fasta&#039;&#039;&#039; class. Hand in same way as above.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
I would not be surprised if you find errors in your &#039;&#039;&#039;fasta&#039;&#039;&#039; class based on these tests. I found flaws in my code.&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;br /&gt;
# Add unit tests for all methods in your &#039;&#039;&#039;fasta&#039;&#039;&#039; class. That will be a bit of work.&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=294</id>
		<title>Beginning unit test</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=294"/>
		<updated>2026-04-13T09:52:42Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Exercises to be handed in */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Intermediate classes]]&lt;br /&gt;
|Next: [[Intermediate unit test]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_09-Testing.ppt Testing]&amp;lt;br&amp;gt;&lt;br /&gt;
Online: [https://docs.pytest.org/ pytest documentation]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Example code - Unit test]]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Unit test - start of reverse polish notation class]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Overview of test methods&amp;lt;br&amp;gt;&lt;br /&gt;
Unit test using pytest framework.&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
You should make a special folder for the exercises. I will refer to my special folder as &#039;&#039;unittest&#039;&#039; in these exercises. You will also see some &#039;&#039;__pycache__&#039;&#039; folders appear in places. This is Pythons cache for &amp;quot;compiled&amp;quot; programs. It is safe to ignore and also to delete, because it may become outdated.&amp;lt;br&amp;gt;&lt;br /&gt;
In some of these exercise you need to hand in not just a single file, but multiple files in a folder hierarchy. Zip the folder structure for your entire solution folder. Make sure it is clear to see what exercise your code/data is solving. And learn to zip :-)&lt;br /&gt;
# Use your &#039;&#039;&#039;normalize&#039;&#039;&#039; function from exercise 3 in [[Functions, namespace, memory management]]. If you did not do so already, change it to use exceptions instead of &#039;&#039;&#039;sys.exit()&#039;&#039;&#039;, when an error occurs. Now make simple unit tests for the following test cases: a list of positive numbers, a list of negative numbers, a list of integers, a list of mixed floats and integers, a single number in the list, empty list, a list with at least one non-number (string, list, set), a set containing numbers, and a dict where the keys are numbers. Get other ideas if you can. The &#039;&#039;&#039;normalize&#039;&#039;&#039; function and all test functions must be in one single file (&#039;&#039;normalize_test.py&#039;&#039; in &#039;&#039;unittest&#039;&#039;), which you can run &#039;&#039;pytest&#039;&#039; on.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Now remove the &#039;&#039;&#039;normalize&#039;&#039;&#039; function from &#039;&#039;normalize_test.py&#039;&#039; and put it in its own file &#039;&#039;normalize.py&#039;&#039;. Import it from the &#039;&#039;normalize_test.py&#039;&#039; like &#039;&#039;&#039;from normalize import normalize&#039;&#039;&#039;. The first &#039;&#039;normalize&#039;&#039; is the name of the .py file, the second &#039;&#039;normalize&#039;&#039; is the name of your normalize function. Just run &#039;&#039;pytest&#039;&#039; (no file name) in the folder to check it works. It is more normal to have test and function separated.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Above we removed test code from function code by creating two files. Next, put the files in their own folder in &#039;&#039;unittest&#039;&#039;. I would put my &#039;&#039;normalize.py&#039;&#039; in &#039;&#039;unittest/src&#039;&#039; and &#039;&#039;normalize_test.py&#039;&#039; in &#039;&#039;unittest/test&#039;&#039;. This way there is a very clear separation between function and test. The problem is making sure the test code loads the function code. Do it wrong a couple of times - it is very instructive.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Follow the file structure of having a &#039;&#039;code&#039;&#039; (or &#039;&#039;src&#039;&#039;) folder for programs, a &#039;&#039;test&#039;&#039; folder for tests, and now a &#039;&#039;testdata&#039;&#039; folder for files containing test data. Now make unit tests and appropriate test data files for your &#039;&#039;&#039;fasta&#039;&#039;&#039; class from last week. In this exercise you just need to make unit test for the method &#039;&#039;&#039;load&#039;&#039;&#039;. You need to hand in both tests and test data.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add unit tests for the method &#039;&#039;&#039;save&#039;&#039;&#039; in your &#039;&#039;&#039;fasta&#039;&#039;&#039; class. Hand in same way as above.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add unit tests for the method &#039;&#039;&#039;delete&#039;&#039;&#039; in your &#039;&#039;&#039;fasta&#039;&#039;&#039; class. Hand in same way as above.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
I would not be surprised if you find errors in your &#039;&#039;&#039;fasta&#039;&#039;&#039; class based on these tests. I found flaws in my code.&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;br /&gt;
# Add unit tests for all methods in your &#039;&#039;&#039;fasta&#039;&#039;&#039; class. That will be a bit of work.&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=293</id>
		<title>Beginning unit test</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=293"/>
		<updated>2026-04-13T09:50:54Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Exercises to be handed in */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Intermediate classes]]&lt;br /&gt;
|Next: [[Intermediate unit test]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_09-Testing.ppt Testing]&amp;lt;br&amp;gt;&lt;br /&gt;
Online: [https://docs.pytest.org/ pytest documentation]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Example code - Unit test]]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Unit test - start of reverse polish notation class]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Overview of test methods&amp;lt;br&amp;gt;&lt;br /&gt;
Unit test using pytest framework.&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
You should make a special folder for the exercises. I will refer to my special folder as &#039;&#039;unittest&#039;&#039; in these exercises. You will also see some &#039;&#039;__pycache__&#039;&#039; folders appear in places. This is Pythons cache for &amp;quot;compiled&amp;quot; programs. It is safe to ignore and also to delete, because it may become outdated.&amp;lt;br&amp;gt;&lt;br /&gt;
In some of these exercise you need to hand in not just a single file, but multiple files in a folder hierarchy. Zip the folder structure for your entire solution folder. Make sure it is clear to see what exercise your code/data is solving. And learn to zip :-)&lt;br /&gt;
# Use your &#039;&#039;&#039;normalize&#039;&#039;&#039; function from exercise 3 in [[Functions, namespace, memory management]]. If you did not do so already, change it to use exceptions instead of &#039;&#039;&#039;sys.exit()&#039;&#039;&#039;, when an error occurs. Now make simple unit tests for the following test cases: a list of positive numbers, a list of negative numbers, a list of integers, a list of mixed floats and integers, a single number in the list, empty list, a list with at least one non-number (string, list, set), a set and a dict. Get other ideas if you can. The &#039;&#039;&#039;normalize&#039;&#039;&#039; function and all test functions must be in one single file (&#039;&#039;normalize_test.py&#039;&#039; in &#039;&#039;unittest&#039;&#039;), which you can run &#039;&#039;pytest&#039;&#039; on.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Now remove the &#039;&#039;&#039;normalize&#039;&#039;&#039; function from &#039;&#039;normalize_test.py&#039;&#039; and put it in its own file &#039;&#039;normalize.py&#039;&#039;. Import it from the &#039;&#039;normalize_test.py&#039;&#039; like &#039;&#039;&#039;from normalize import normalize&#039;&#039;&#039;. The first &#039;&#039;normalize&#039;&#039; is the name of the .py file, the second &#039;&#039;normalize&#039;&#039; is the name of your normalize function. Just run &#039;&#039;pytest&#039;&#039; (no file name) in the folder to check it works. It is more normal to have test and function separated.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Above we removed test code from function code by creating two files. Next, put the files in their own folder in &#039;&#039;unittest&#039;&#039;. I would put my &#039;&#039;normalize.py&#039;&#039; in &#039;&#039;unittest/src&#039;&#039; and &#039;&#039;normalize_test.py&#039;&#039; in &#039;&#039;unittest/test&#039;&#039;. This way there is a very clear separation between function and test. The problem is making sure the test code loads the function code. Do it wrong a couple of times - it is very instructive.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Follow the file structure of having a &#039;&#039;code&#039;&#039; (or &#039;&#039;src&#039;&#039;) folder for programs, a &#039;&#039;test&#039;&#039; folder for tests, and now a &#039;&#039;testdata&#039;&#039; folder for files containing test data. Now make unit tests and appropriate test data files for your &#039;&#039;&#039;fasta&#039;&#039;&#039; class from last week. In this exercise you just need to make unit test for the method &#039;&#039;&#039;load&#039;&#039;&#039;. You need to hand in both tests and test data.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add unit tests for the method &#039;&#039;&#039;save&#039;&#039;&#039; in your &#039;&#039;&#039;fasta&#039;&#039;&#039; class. Hand in same way as above.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add unit tests for the method &#039;&#039;&#039;delete&#039;&#039;&#039; in your &#039;&#039;&#039;fasta&#039;&#039;&#039; class. Hand in same way as above.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
I would not be surprised if you find errors in your &#039;&#039;&#039;fasta&#039;&#039;&#039; class based on these tests. I found flaws in my code.&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;br /&gt;
# Add unit tests for all methods in your &#039;&#039;&#039;fasta&#039;&#039;&#039; class. That will be a bit of work.&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=292</id>
		<title>Beginning unit test</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_unit_test&amp;diff=292"/>
		<updated>2026-04-13T09:40:22Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Exercises to be handed in */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Intermediate classes]]&lt;br /&gt;
|Next: [[Intermediate unit test]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_09-Testing.ppt Testing]&amp;lt;br&amp;gt;&lt;br /&gt;
Online: [https://docs.pytest.org/ pytest documentation]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Example code - Unit test]]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Unit test - start of reverse polish notation class]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Overview of test methods&amp;lt;br&amp;gt;&lt;br /&gt;
Unit test using pytest framework.&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
You should make a special folder for the exercises. I will refer to my special folder as &#039;&#039;unittest&#039;&#039; in these exercises. You will also see some &#039;&#039;__pycache__&#039;&#039; folders appear in places. This is Pythons cache for &amp;quot;compiled&amp;quot; programs. It is safe to ignore and also to delete, because it may become outdated.&amp;lt;br&amp;gt;&lt;br /&gt;
In some of these exercise you need to hand in not just a single file, but multiple files in a folder hierarchy. Zip the folder structure for your entire solution folder. Make sure it is clear to see what exercise your code/data is solving. And learn to zip :-)&lt;br /&gt;
# Use your factorial function from exercise 2 in [[Making Functions]]. If you did not do so already, change it to use exceptions instead of &#039;&#039;&#039;sys.exit()&#039;&#039;&#039;, when an error occurs. Now make simple unit tests for the following test cases: 12, 2, 1, 0, -1, 3.0, 3.4, &amp;quot;3&amp;quot;, &amp;quot;3.1.&amp;quot;, &amp;quot;ABC&amp;quot;. The factorial function and all test functions must be in one single file (&#039;&#039;factorial_test.py&#039;&#039; in &#039;&#039;unittest&#039;&#039;), which you can run &#039;&#039;pytest&#039;&#039; on.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Now remove the factorial function from &#039;&#039;factorial_test.py&#039;&#039; and put it in its own file &#039;&#039;factorial.py&#039;&#039;. Import it from the &#039;&#039;factorial_test.py&#039;&#039; like &#039;&#039;&#039;from factorial import factorial&#039;&#039;&#039;. The first factorial is the name of the .py file, the second factorial is the name of your factorial function. Just run &#039;&#039;pytest&#039;&#039; (no file name) in the folder to check it works. It is more normal to have test and function separated.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Above we removed test code from function code by creating two files. Next, put the files in their own folder in &#039;&#039;unittest&#039;&#039;. I would put my &#039;&#039;factorial.py&#039;&#039; in &#039;&#039;unittest/src&#039;&#039; and &#039;&#039;factorial_test.py&#039;&#039; in &#039;&#039;unittest/test&#039;&#039;. This way there is a very clear separation between function and test. The problem is making sure the test code loads the function code. Do it wrong a couple of times - it is very instructive.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Follow the file structure of having a &#039;&#039;code&#039;&#039; (or &#039;&#039;src&#039;&#039;) folder for programs, a &#039;&#039;test&#039;&#039; folder for tests, and now a &#039;&#039;testdata&#039;&#039; folder for files containing test data. Now make unit tests and appropriate test data files for your &#039;&#039;&#039;fasta&#039;&#039;&#039; class from last week. In this exercise you just need to make unit test for the method &#039;&#039;&#039;load&#039;&#039;&#039;. You need to hand in both tests and test data.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add unit tests for the method &#039;&#039;&#039;save&#039;&#039;&#039; in your &#039;&#039;&#039;fasta&#039;&#039;&#039; class. Hand in same way as above.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add unit tests for the method &#039;&#039;&#039;delete&#039;&#039;&#039; in your &#039;&#039;&#039;fasta&#039;&#039;&#039; class. Hand in same way as above.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
I would not be surprised if you find errors in your &#039;&#039;&#039;fasta&#039;&#039;&#039; class based on these tests. I found flaws in my code.&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;br /&gt;
# Add unit tests for all methods in your &#039;&#039;&#039;fasta&#039;&#039;&#039; class. That will be a bit of work.&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Intermediate_unit_test&amp;diff=291</id>
		<title>Intermediate unit test</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Intermediate_unit_test&amp;diff=291"/>
		<updated>2026-04-10T12:07:43Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Subjects covered */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Beginning unit test]]&lt;br /&gt;
|Next: [[Runtime evaluation]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_09-Testing.ppt Testing]&amp;lt;br&amp;gt;&lt;br /&gt;
Online: [https://docs.pytest.org/ pytest documentation]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Unit test - start of reverse polish notation class]]&amp;lt;br&amp;gt;&lt;br /&gt;
Blog: [https://www.joelonsoftware.com/2000/04/30/top-five-wrong-reasons-you-dont-have-testers/ On testing], by the founder of StackExchange.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Unit test using pytest framework.&amp;lt;br&amp;gt;&lt;br /&gt;
Files, test data&amp;lt;br&amp;gt;&lt;br /&gt;
Setting up real projects&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
You should make a special folder for the exercises. I will refer to my special folder as &#039;&#039;unittest&#039;&#039; in these exercises. You will also see some &#039;&#039;__pycache__&#039;&#039; folders appear in places. This is Pythons cache for &amp;quot;compiled&amp;quot; programs. It is safe to ignore and also to delete, because it may become outdated.&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Intermediate_unit_test&amp;diff=290</id>
		<title>Intermediate unit test</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Intermediate_unit_test&amp;diff=290"/>
		<updated>2026-04-10T12:05:47Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Exercises for extra practice */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Beginning unit test]]&lt;br /&gt;
|Next: [[Runtime evaluation]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_09-Testing.ppt Testing]&amp;lt;br&amp;gt;&lt;br /&gt;
Online: [https://docs.pytest.org/ pytest documentation]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Unit test - start of reverse polish notation class]]&amp;lt;br&amp;gt;&lt;br /&gt;
Blog: [https://www.joelonsoftware.com/2000/04/30/top-five-wrong-reasons-you-dont-have-testers/ On testing], by the founder of StackExchange.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Overview of test methods&amp;lt;br&amp;gt;&lt;br /&gt;
Unit test using pytest framework.&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
You should make a special folder for the exercises. I will refer to my special folder as &#039;&#039;unittest&#039;&#039; in these exercises. You will also see some &#039;&#039;__pycache__&#039;&#039; folders appear in places. This is Pythons cache for &amp;quot;compiled&amp;quot; programs. It is safe to ignore and also to delete, because it may become outdated.&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Intermediate_unit_test&amp;diff=289</id>
		<title>Intermediate unit test</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Intermediate_unit_test&amp;diff=289"/>
		<updated>2026-04-10T12:05:35Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Exercises to be handed in */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Beginning unit test]]&lt;br /&gt;
|Next: [[Runtime evaluation]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_09-Testing.ppt Testing]&amp;lt;br&amp;gt;&lt;br /&gt;
Online: [https://docs.pytest.org/ pytest documentation]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Unit test - start of reverse polish notation class]]&amp;lt;br&amp;gt;&lt;br /&gt;
Blog: [https://www.joelonsoftware.com/2000/04/30/top-five-wrong-reasons-you-dont-have-testers/ On testing], by the founder of StackExchange.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Overview of test methods&amp;lt;br&amp;gt;&lt;br /&gt;
Unit test using pytest framework.&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
You should make a special folder for the exercises. I will refer to my special folder as &#039;&#039;unittest&#039;&#039; in these exercises. You will also see some &#039;&#039;__pycache__&#039;&#039; folders appear in places. This is Pythons cache for &amp;quot;compiled&amp;quot; programs. It is safe to ignore and also to delete, because it may become outdated.&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;br /&gt;
# Add unit tests for all methods in your &#039;&#039;&#039;fasta&#039;&#039;&#039; class. That will be a bit of work.&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Intermediate_classes&amp;diff=288</id>
		<title>Intermediate classes</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Intermediate_classes&amp;diff=288"/>
		<updated>2026-03-23T10:06:12Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Exercises to be handed in */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Beginning classes]]&lt;br /&gt;
|Next: [[Beginning unit test]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_07-Classes.ppt Classes]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Example code - Inheritance issues]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Magic methods in classes&amp;lt;br&amp;gt;&lt;br /&gt;
Object Oriented Programming&amp;lt;br&amp;gt;&lt;br /&gt;
Polymorphism and inheritance&amp;lt;br&amp;gt;&lt;br /&gt;
Practical knowledge&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
The first four exercises will continue with the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class from last time.&lt;br /&gt;
# Use magic methods to add &#039;&#039;iteration&#039;&#039; and &#039;&#039;length&#039;&#039; evaluation (using &#039;&#039;&#039;__iter__&#039;&#039;&#039; and &#039;&#039;&#039;__len__&#039;&#039;&#039; magic methods) to the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class. Do this so you can write code like &amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;if len(MyFastaInstance) &amp;gt; 0:&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;for header, sequence in MyFastaInstance:&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;# Do something with header and sequence&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;print(header, sequence)&amp;lt;/div&amp;gt;The function &#039;&#039;&#039;len&#039;&#039;&#039; returns the number of sequences.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add the methods &#039;&#039;&#039;deletethis()&#039;&#039;&#039;, &#039;&#039;&#039;insertthis(header, sequence)&#039;&#039;&#039;, &#039;&#039;&#039;verifythis(alphabet)&#039;&#039;&#039; and &#039;&#039;&#039;discardthis(alphabet)&#039;&#039;&#039; to the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class. The methods should only work when &#039;&#039;iterating over an instance at the current item&#039;&#039;, i.e. they work when you are iterating over the fasta sequences on the &#039;&#039;current&#039;&#039; sequence and header, like this:&amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;for header, sequence in MyFastaInstance:&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;if not MyFastaInstance.verifythis(&amp;quot;DNA&amp;quot;):&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;MyFastaInstance.deletethis()&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;continue&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;# Do something with header and sequence&amp;lt;/div&amp;gt;As some may remember, it is normally impossible to successfully iterate straightforward through a list and delete and/or add elements to the list during the iteration. You have to make this possible. Hint: change the way your iteration works in the previous exercise. You need to take a position on this issue: When iterating over entries, how should you continue after inserting entries at your current position? Example: You are at element in position 5, you insert 2 elements at that position. This WILL mean the new elements are at position 5 and 6, and the one you &amp;quot;looked at&amp;quot; is now on position 7. Do you continue the iteration on position 5 or is the next position 8? My opinion is that you should not look at the new elements and you have already looked at the &amp;quot;old&amp;quot; element at 5, so the next one is at 8. You are free to make your own decision - just be clear about it. Realize if you insert something because you see a special element and you do not choose my way, then you will create an infinite loop, since you will see the special element again.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Let&#039;s do something natural. Make it possible to add one FastaInstance to another using the &#039;&#039;&#039;+=&#039;&#039;&#039; operator, like this:&amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;FastaInstance1 += FastaInstance2&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;The headers and sequences in Fastainstance2 should be added (list extension) to the headers and sequences in FastaInstance1. Use the magic method [https://zetcode.com/python/dunder-iadd/ &#039;&#039;&#039;__iadd__&#039;&#039;&#039;]. Try with the files &#039;&#039;dna7.fsa&#039;&#039; and &#039;&#039;protein.fsa&#039;&#039;. That will be a strange DNA and protein mix, but it is a great opportunity to use the &#039;&#039;&#039;discard&#039;&#039;&#039; method to get rid of one of the types.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Implement the &#039;&#039;addition&#039;&#039;, using [https://zetcode.com/python/dunder-add/ &#039;&#039;&#039;__add__&#039;&#039;&#039;]. Addition creates a new Fasta instance, but leaves the originals untouched.&amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;FastaInstance3 = FastaInstance1 + FastaInstance2&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;The resulting Fasta object must contain the headers and sequences from FastaInstance1 and FastaInstance2 in that order. Note that this works as an alternative constructor. Now that the Fasta class is done, save it in a file, so you can import it for the next exercises.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# You can consider a &#039;&#039;&#039;Fasta&#039;&#039;&#039; instance as a &#039;&#039;set&#039;&#039; of headers/sequences. The sequences are obviously uniquely identified by the identifier in the header, which is what will be used as key in the set operations. In the rest of the exercises we will explore inheritance by making a new class called &#039;&#039;&#039;FastaSet&#039;&#039;&#039;, which inherits from the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class.&amp;lt;br&amp;gt;A) The original &#039;&#039;&#039;__init__&#039;&#039;&#039;, &#039;&#039;&#039;save&#039;&#039;&#039;, &#039;&#039;&#039;load&#039;&#039;&#039;, &#039;&#039;&#039;insert&#039;&#039;&#039;, the iteration and the corresponding &#039;&#039;&#039;deletethis&#039;&#039;&#039;, &#039;&#039;&#039;insertthis&#039;&#039;&#039;, &#039;&#039;&#039;verifythis&#039;&#039;&#039; and &#039;&#039;&#039;discardthis&#039;&#039;&#039; methods are fine to keep in the new class (meaning do nothing about them).&amp;lt;br&amp;gt;B) To help in the new class create a new getter method &#039;&#039;&#039;identifiers&#039;&#039;&#039;, which returns a list of identifiers from the header lines.&amp;lt;br&amp;gt;C) Override the &#039;&#039;&#039;content&#039;&#039;&#039; method such that it takes a set or list of identifiers and returns only the headers/sequences that corresponds to the identifiers in the list. If you do not specify a list/set of identifiers, it still returns all.&amp;lt;br&amp;gt;D) Override the &#039;&#039;&#039;delete&#039;&#039;&#039; method in a similar way - it deletes the headers/sequences that corresponds to the input.&amp;lt;br&amp;gt;E) Override the &#039;&#039;&#039;verify&#039;&#039;&#039; method in a similar way to &#039;&#039;&#039;content&#039;&#039;&#039; - it verifies the headers/sequences that corresponds to the input.&amp;lt;br&amp;gt;F) Override the &#039;&#039;&#039;discard&#039;&#039;&#039; method in a similar way to &#039;&#039;&#039;content&#039;&#039;&#039; - it discards the headers/sequences that corresponds to the input.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# As the new FastaSet class is set orientated, implement the following set operations in the class:&amp;lt;br&amp;gt;A) union, operator is &#039;&#039;&#039;|&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__or__&#039;&#039;&#039;.&amp;lt;br&amp;gt;B) intersection, operator is &#039;&#039;&#039;&amp;amp;&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__and__&#039;&#039;&#039;.&amp;lt;br&amp;gt;C) difference, operator is &#039;&#039;&#039;-&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__sub__&#039;&#039;&#039;.&amp;lt;br&amp;gt;D) symmetric difference, operator is &#039;&#039;&#039;^&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__xor__&#039;&#039;&#039;.&amp;lt;br&amp;gt;These are quite similar to the addition in exercise 4 - the operators are used in the same way and a new Fasta object is returned. The identity of the sequence depends on the identifier in the corresponding header. This is an example of operator overloading - the normal arithmetic operator used on numbers are used on something completely different.&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;br /&gt;
# You continue to add the unique identifier control for all methods in Fasta and FastaSet, as mentioned last week.&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Intermediate_classes&amp;diff=287</id>
		<title>Intermediate classes</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Intermediate_classes&amp;diff=287"/>
		<updated>2026-03-23T10:05:41Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Exercises to be handed in */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Beginning classes]]&lt;br /&gt;
|Next: [[Beginning unit test]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_07-Classes.ppt Classes]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Example code - Inheritance issues]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Magic methods in classes&amp;lt;br&amp;gt;&lt;br /&gt;
Object Oriented Programming&amp;lt;br&amp;gt;&lt;br /&gt;
Polymorphism and inheritance&amp;lt;br&amp;gt;&lt;br /&gt;
Practical knowledge&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
The first four exercises will continue with the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class from last time.&lt;br /&gt;
# Use magic methods to add &#039;&#039;iteration&#039;&#039; and &#039;&#039;length&#039;&#039; evaluation (using &#039;&#039;&#039;__iter__&#039;&#039;&#039; and &#039;&#039;&#039;__len__&#039;&#039;&#039; magic methods) to the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class. Do this so you can write code like &amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;if len(MyFastaInstance) &amp;gt; 0:&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;for header, sequence in MyFastaInstance:&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;# Do something with header and sequence&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;print(header, sequence)&amp;lt;/div&amp;gt;The function &#039;&#039;&#039;len&#039;&#039;&#039; returns the number of sequences.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add the methods &#039;&#039;&#039;deletethis()&#039;&#039;&#039;, &#039;&#039;&#039;insertthis(header, sequence)&#039;&#039;&#039;, &#039;&#039;&#039;verifythis(alphabet)&#039;&#039;&#039; and &#039;&#039;&#039;discardthis(alphabet)&#039;&#039;&#039; to the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class. The methods should only work when &#039;&#039;iterating over an instance at the current item&#039;&#039;, i.e. they work when you are iterating over the fasta sequences on the &#039;&#039;current&#039;&#039; sequence and header, like this:&amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;for header, sequence in MyFastaInstance:&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;if not MyFastaInstance.verifythis(&amp;quot;DNA&amp;quot;):&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;MyFastaInstance.deletethis()&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;continue&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;# Do something with header and sequence&amp;lt;/div&amp;gt;As some may remember, it is normally impossible to successfully iterate straightforward through a list and delete and/or add elements to the list during the iteration. You have to make this possible. Hint: change the way your iteration works in the previous exercise. You need to take a position on this issue: When iterating over entries, how should you continue after inserting entries at your current position? Example: You are at element in position 5, you insert 2 elements at that position. This WILL mean the new elements are at position 5 and 6, and the one you &amp;quot;looked at&amp;quot; is now on position 7. Do you continue the iteration on position 5 or is the next position 8? My opinion is that you should not look at the new elements and you have already looked at the &amp;quot;old&amp;quot; element at 5, so the next one is at 8. You are free to make your own decision - just be clear about it. Just realize if you insert something because you see a special elements and you do not choose my way, then you will create an infinite loop, since you will see the special element again.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Let&#039;s do something natural. Make it possible to add one FastaInstance to another using the &#039;&#039;&#039;+=&#039;&#039;&#039; operator, like this:&amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;FastaInstance1 += FastaInstance2&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;The headers and sequences in Fastainstance2 should be added (list extension) to the headers and sequences in FastaInstance1. Use the magic method [https://zetcode.com/python/dunder-iadd/ &#039;&#039;&#039;__iadd__&#039;&#039;&#039;]. Try with the files &#039;&#039;dna7.fsa&#039;&#039; and &#039;&#039;protein.fsa&#039;&#039;. That will be a strange DNA and protein mix, but it is a great opportunity to use the &#039;&#039;&#039;discard&#039;&#039;&#039; method to get rid of one of the types.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Implement the &#039;&#039;addition&#039;&#039;, using [https://zetcode.com/python/dunder-add/ &#039;&#039;&#039;__add__&#039;&#039;&#039;]. Addition creates a new Fasta instance, but leaves the originals untouched.&amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;FastaInstance3 = FastaInstance1 + FastaInstance2&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;The resulting Fasta object must contain the headers and sequences from FastaInstance1 and FastaInstance2 in that order. Note that this works as an alternative constructor. Now that the Fasta class is done, save it in a file, so you can import it for the next exercises.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# You can consider a &#039;&#039;&#039;Fasta&#039;&#039;&#039; instance as a &#039;&#039;set&#039;&#039; of headers/sequences. The sequences are obviously uniquely identified by the identifier in the header, which is what will be used as key in the set operations. In the rest of the exercises we will explore inheritance by making a new class called &#039;&#039;&#039;FastaSet&#039;&#039;&#039;, which inherits from the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class.&amp;lt;br&amp;gt;A) The original &#039;&#039;&#039;__init__&#039;&#039;&#039;, &#039;&#039;&#039;save&#039;&#039;&#039;, &#039;&#039;&#039;load&#039;&#039;&#039;, &#039;&#039;&#039;insert&#039;&#039;&#039;, the iteration and the corresponding &#039;&#039;&#039;deletethis&#039;&#039;&#039;, &#039;&#039;&#039;insertthis&#039;&#039;&#039;, &#039;&#039;&#039;verifythis&#039;&#039;&#039; and &#039;&#039;&#039;discardthis&#039;&#039;&#039; methods are fine to keep in the new class (meaning do nothing about them).&amp;lt;br&amp;gt;B) To help in the new class create a new getter method &#039;&#039;&#039;identifiers&#039;&#039;&#039;, which returns a list of identifiers from the header lines.&amp;lt;br&amp;gt;C) Override the &#039;&#039;&#039;content&#039;&#039;&#039; method such that it takes a set or list of identifiers and returns only the headers/sequences that corresponds to the identifiers in the list. If you do not specify a list/set of identifiers, it still returns all.&amp;lt;br&amp;gt;D) Override the &#039;&#039;&#039;delete&#039;&#039;&#039; method in a similar way - it deletes the headers/sequences that corresponds to the input.&amp;lt;br&amp;gt;E) Override the &#039;&#039;&#039;verify&#039;&#039;&#039; method in a similar way to &#039;&#039;&#039;content&#039;&#039;&#039; - it verifies the headers/sequences that corresponds to the input.&amp;lt;br&amp;gt;F) Override the &#039;&#039;&#039;discard&#039;&#039;&#039; method in a similar way to &#039;&#039;&#039;content&#039;&#039;&#039; - it discards the headers/sequences that corresponds to the input.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# As the new FastaSet class is set orientated, implement the following set operations in the class:&amp;lt;br&amp;gt;A) union, operator is &#039;&#039;&#039;|&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__or__&#039;&#039;&#039;.&amp;lt;br&amp;gt;B) intersection, operator is &#039;&#039;&#039;&amp;amp;&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__and__&#039;&#039;&#039;.&amp;lt;br&amp;gt;C) difference, operator is &#039;&#039;&#039;-&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__sub__&#039;&#039;&#039;.&amp;lt;br&amp;gt;D) symmetric difference, operator is &#039;&#039;&#039;^&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__xor__&#039;&#039;&#039;.&amp;lt;br&amp;gt;These are quite similar to the addition in exercise 4 - the operators are used in the same way and a new Fasta object is returned. The identity of the sequence depends on the identifier in the corresponding header. This is an example of operator overloading - the normal arithmetic operator used on numbers are used on something completely different.&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;br /&gt;
# You continue to add the unique identifier control for all methods in Fasta and FastaSet, as mentioned last week.&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=286</id>
		<title>Example code - Inheritance issues</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=286"/>
		<updated>2026-03-19T19:22:14Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Take home messages */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The challenges in inheritance can not be demonstrated well in a powerpoint.&lt;br /&gt;
Thus, I made this page with examples. You can copy the code in the section and add it together and run it.&lt;br /&gt;
&lt;br /&gt;
First I create a slightly bigger CatClass.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class CatClass:&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Felis&amp;quot;&lt;br /&gt;
    species = &amp;quot;Catus&amp;quot;&lt;br /&gt;
    acts = {&#039;scratch&#039;: &amp;quot;purrs&amp;quot;,&lt;br /&gt;
            &#039;scare&#039;: &amp;quot;jumps high in the air&amp;quot;,&lt;br /&gt;
            &#039;feed&#039;: &amp;quot;is very excited&amp;quot; }&lt;br /&gt;
&lt;br /&gt;
    ### Instantiation&lt;br /&gt;
    def __init__(self, name, gender):&lt;br /&gt;
        self._name, self._gender = name, gender&lt;br /&gt;
&lt;br /&gt;
    ### Magic methods&lt;br /&gt;
    # Addition makes a kitten if male and female cat, alternative constructor&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Being biased and saying all kittens are male&lt;br /&gt;
        kitten = CatClass(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten     &lt;br /&gt;
        &lt;br /&gt;
    ### Class methods&lt;br /&gt;
    # Adding a cat action&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def add_action(cls, action, reaction):&lt;br /&gt;
       cls.acts[action] = reaction&lt;br /&gt;
    # Querying class for number of actions&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def count_action(cls):&lt;br /&gt;
        return len(cls.acts)&lt;br /&gt;
&lt;br /&gt;
    ### Property methods&lt;br /&gt;
    # name setter and getter&lt;br /&gt;
    @property&lt;br /&gt;
    def name(self):&lt;br /&gt;
        if not hasattr(self, &#039;_name&#039;):&lt;br /&gt;
            raise NameError(&amp;quot;Name of cat is not yet set&amp;quot;)&lt;br /&gt;
        return self._name&lt;br /&gt;
        &lt;br /&gt;
    @name.setter&lt;br /&gt;
    def name(self, value):&lt;br /&gt;
        if value == &#039;&#039;:&lt;br /&gt;
            raise ValueError(&amp;quot;Name can not be nothing&amp;quot;)&lt;br /&gt;
        self._name = value&lt;br /&gt;
&lt;br /&gt;
    ### Instance methods&lt;br /&gt;
    # The action method - using class variables&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
        elif self._gender == &#039;male&#039;:&lt;br /&gt;
            print(self._name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self._name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
### Main program                    &lt;br /&gt;
yourcat = CatClass(&#039;Missy&#039;, &#039;female&#039;)&lt;br /&gt;
&lt;br /&gt;
CatClass.add_action(&amp;quot;annoy&amp;quot;, &amp;quot;scratches your face&amp;quot;)&lt;br /&gt;
print(&amp;quot;Actions in CatClass:&amp;quot;, CatClass.count_action())&lt;br /&gt;
&lt;br /&gt;
mycat = CatClass(&amp;quot;Tom&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
kitten = mycat + yourcat&lt;br /&gt;
&lt;br /&gt;
print(f&amp;quot;Kitten: {kitten.name}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
yourcat.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This class looks fine, but it has a number of inheritance issues.&lt;br /&gt;
By creating a Tiger class that inherits from the CatClass, I will demonstrate. Also, see how simple it was to create a new class based on an old :-)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts = {&lt;br /&gt;
        &#039;scratch&#039;: &#039;roars&#039;,&lt;br /&gt;
        &#039;feed&#039;: &#039;demands more meat&#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.action(&amp;quot;scratch&amp;quot;)&lt;br /&gt;
tigger.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We want the Tiger to react differently than the Cat, at least for some actions. However, this code does not do it. The problem lies in the inherited &#039;&#039;&#039;action&#039;&#039;&#039; method.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
        elif self._gender == &#039;male&#039;:&lt;br /&gt;
            print(self._name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self._name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    # We are specifically using the actions in the CatClass for the behavior&lt;br /&gt;
    # We need to use the current class, as in cats uses CatClass actions and tigers uses Tiger actions.&lt;br /&gt;
&lt;br /&gt;
    # These are the problematic lines, they can be replaced in different ways&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
    # Through &#039;&#039;&#039;self&#039;&#039;&#039;, as self will search the instance namespace and then the class namespace for the variable&lt;br /&gt;
        if act in self.acts:&lt;br /&gt;
            print(self._name, self.acts[act])&lt;br /&gt;
    # By dynamically getting the class by type&lt;br /&gt;
        cls = type(self)&lt;br /&gt;
        if act in cls.acts:&lt;br /&gt;
            print(self._name, cls.acts[act])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This does not completely solve the problem. We would still like to be able to scare the tiger (inherit the cat action), but for now it looks bored when we try. This problem is caused by the complete replacement of the class variable acts in the Tiger class. The cat actions are deleted and replaced with tiger-only actions.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts = {&lt;br /&gt;
        &#039;scratch&#039;: &#039;roars&#039;,&lt;br /&gt;
        &#039;feed&#039;: &#039;demands more meat&#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
# Thats OK, we will just add the tiger actions later - we inherited the add_action from CatClass&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.add_action(&#039;scratch&#039;, &#039;roars&#039;)&lt;br /&gt;
tigger.add_action(&#039;feed&#039;, &#039;demands more meat&#039;)&lt;br /&gt;
# Testing&lt;br /&gt;
tigger.action(&#039;scare&#039;)&lt;br /&gt;
tigger.action(&#039;feed&#039;)&lt;br /&gt;
# All good, but what happened to our cat?&lt;br /&gt;
mycat.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The cat started roaring when scratched - that is a tiger action. Looking at the add_action class method, it is not specifying anywhere that the CatClass should be used so what is wrong? The problem is that the Tiger and the CatClass are &#039;&#039;sharing&#039;&#039; the class variables. The Tiger did not make new ones, so it is using the CatClass class variables, because CatClass is the parent class. Right now any changes in action made by the Tiger class is reflected in the CatClass and vice versa. The Tiger needs is own. Also did you notice that the Tiger&#039;s scientific name is Felis Catus, same as the cat - ridiculous.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Panthera&amp;quot;&lt;br /&gt;
    species = &amp;quot;Tigris&amp;quot;&lt;br /&gt;
    acts = CatClass.acts.copy()&lt;br /&gt;
    # Tiger class specials&lt;br /&gt;
    acts[&#039;scratch&#039;] = &#039;roars&#039;&lt;br /&gt;
    acts[&#039;feed&#039;} = &#039;demands more meat&#039;&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.action(&#039;scratch&#039;)&lt;br /&gt;
mycat.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Much better. Copy the mutable class variables from the base class and then change them so they fit.&lt;br /&gt;
&lt;br /&gt;
Life is good. Let&#039;s make some kittens.....&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
kitten1 = mycat + yourcat&lt;br /&gt;
print(kitten1.name)&lt;br /&gt;
&lt;br /&gt;
# Can we mate the cat and the tiger?&lt;br /&gt;
kitten2 = yourcat + tigger&lt;br /&gt;
kitten2.name = &amp;quot;Monstrous Mutant&amp;quot;&lt;br /&gt;
print(kitten2.name)&lt;br /&gt;
kitten2.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
That was unfortunate. We should not be able to breed a cat and a tiger, and if we did anyway, should the result be a cat (the kitten does a cat action)?&amp;lt;br&amp;gt;&lt;br /&gt;
The issue is in the &#039;&#039;__add__&#039;&#039; magic method. All that is required is that the two classes being &amp;quot;added&amp;quot; have a _gender instance variable.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Being biased and saying all kittens are male&lt;br /&gt;
        kitten = CatClass(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten&lt;br /&gt;
&lt;br /&gt;
    # Adding a class check - we must demand that we breed tigers with tigers and cats with cats&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        if type(self) != type(other):&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Still male kittens, making sure tigers begets tigers and cats begets cats&lt;br /&gt;
        kitten = type(self)(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten     &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are the two classes without any inheritance problems. I will leave it to you to do the testing. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class CatClass:&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Felis&amp;quot;&lt;br /&gt;
    species = &amp;quot;Catus&amp;quot;&lt;br /&gt;
    acts = {&#039;scratch&#039;: &amp;quot;purrs&amp;quot;,&lt;br /&gt;
            &#039;scare&#039;: &amp;quot;jumps high in the air&amp;quot;,&lt;br /&gt;
            &#039;feed&#039;: &amp;quot;is very excited&amp;quot; }&lt;br /&gt;
&lt;br /&gt;
    ### Instantiation&lt;br /&gt;
    def __init__(self, name, gender):&lt;br /&gt;
        self._name, self._gender = name, gender&lt;br /&gt;
&lt;br /&gt;
    ### Magic methods&lt;br /&gt;
    # Addition makes a kitten if male and female cat, alternative constructor&lt;br /&gt;
    # Adding a class check - we must demand that we breed tigers with tigers and cats with cats&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        if type(self) != type(other):&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Still male kittens, making sure tigers begets tigers and cats begets cats&lt;br /&gt;
        kitten = type(self)(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten&lt;br /&gt;
                &lt;br /&gt;
    ### Class methods&lt;br /&gt;
    # Adding a cat action&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def add_action(cls, action, reaction):&lt;br /&gt;
       cls.acts[action] = reaction&lt;br /&gt;
    # Querying class for number of actions&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def count_action(cls):&lt;br /&gt;
        return len(cls.acts)&lt;br /&gt;
&lt;br /&gt;
    ### Property methods&lt;br /&gt;
    # name setter and getter&lt;br /&gt;
    @property&lt;br /&gt;
    def name(self):&lt;br /&gt;
        if not hasattr(self, &#039;_name&#039;):&lt;br /&gt;
            raise NameError(&amp;quot;Name of cat is not yet set&amp;quot;)&lt;br /&gt;
        return self._name&lt;br /&gt;
        &lt;br /&gt;
    @name.setter&lt;br /&gt;
    def name(self, value):&lt;br /&gt;
        if value == &#039;&#039;:&lt;br /&gt;
            raise ValueError(&amp;quot;Name can not be nothing&amp;quot;)&lt;br /&gt;
        self._name = value&lt;br /&gt;
&lt;br /&gt;
    ### Instance methods&lt;br /&gt;
    # The action method - using class variables&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in self.acts:&lt;br /&gt;
            print(self._name, self.acts[act])&lt;br /&gt;
        elif self._gender == &#039;male&#039;:&lt;br /&gt;
            print(self._name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self._name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Panthera&amp;quot;&lt;br /&gt;
    species = &amp;quot;Tigris&amp;quot;&lt;br /&gt;
    acts = CatClass.acts.copy()&lt;br /&gt;
    # Tiger class specials&lt;br /&gt;
    acts[&#039;scratch&#039;] = &#039;roars&#039;&lt;br /&gt;
    acts[&#039;feed&#039;] = &#039;demands more meat&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
== Take home messages ==&lt;br /&gt;
* Even if you do not plan for your class to be inherited, make it so it can. That way it is less work later AND you remember how to do it.&lt;br /&gt;
* Don&#039;t hardcode class names in your class. Use &#039;&#039;type(self)&#039;&#039; to get the class. This goes when using class variables, constructing new instances and elsewhere. But not when copying the parent class&#039; class variables - there you have to name it :-)&lt;br /&gt;
* Make a copy of mutable class variables if you have any plan or possibility to modify them.&lt;br /&gt;
* In magic methods check that the &#039;&#039;other&#039;&#039; class is the same as &#039;&#039;self&#039;&#039;.&lt;br /&gt;
* Notice that what you learned here is slightly different from what was told in the beginning of the powerpoint.&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=285</id>
		<title>Example code - Inheritance issues</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=285"/>
		<updated>2026-03-19T18:54:04Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The challenges in inheritance can not be demonstrated well in a powerpoint.&lt;br /&gt;
Thus, I made this page with examples. You can copy the code in the section and add it together and run it.&lt;br /&gt;
&lt;br /&gt;
First I create a slightly bigger CatClass.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class CatClass:&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Felis&amp;quot;&lt;br /&gt;
    species = &amp;quot;Catus&amp;quot;&lt;br /&gt;
    acts = {&#039;scratch&#039;: &amp;quot;purrs&amp;quot;,&lt;br /&gt;
            &#039;scare&#039;: &amp;quot;jumps high in the air&amp;quot;,&lt;br /&gt;
            &#039;feed&#039;: &amp;quot;is very excited&amp;quot; }&lt;br /&gt;
&lt;br /&gt;
    ### Instantiation&lt;br /&gt;
    def __init__(self, name, gender):&lt;br /&gt;
        self._name, self._gender = name, gender&lt;br /&gt;
&lt;br /&gt;
    ### Magic methods&lt;br /&gt;
    # Addition makes a kitten if male and female cat, alternative constructor&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Being biased and saying all kittens are male&lt;br /&gt;
        kitten = CatClass(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten     &lt;br /&gt;
        &lt;br /&gt;
    ### Class methods&lt;br /&gt;
    # Adding a cat action&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def add_action(cls, action, reaction):&lt;br /&gt;
       cls.acts[action] = reaction&lt;br /&gt;
    # Querying class for number of actions&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def count_action(cls):&lt;br /&gt;
        return len(cls.acts)&lt;br /&gt;
&lt;br /&gt;
    ### Property methods&lt;br /&gt;
    # name setter and getter&lt;br /&gt;
    @property&lt;br /&gt;
    def name(self):&lt;br /&gt;
        if not hasattr(self, &#039;_name&#039;):&lt;br /&gt;
            raise NameError(&amp;quot;Name of cat is not yet set&amp;quot;)&lt;br /&gt;
        return self._name&lt;br /&gt;
        &lt;br /&gt;
    @name.setter&lt;br /&gt;
    def name(self, value):&lt;br /&gt;
        if value == &#039;&#039;:&lt;br /&gt;
            raise ValueError(&amp;quot;Name can not be nothing&amp;quot;)&lt;br /&gt;
        self._name = value&lt;br /&gt;
&lt;br /&gt;
    ### Instance methods&lt;br /&gt;
    # The action method - using class variables&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
        elif self._gender == &#039;male&#039;:&lt;br /&gt;
            print(self._name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self._name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
### Main program                    &lt;br /&gt;
yourcat = CatClass(&#039;Missy&#039;, &#039;female&#039;)&lt;br /&gt;
&lt;br /&gt;
CatClass.add_action(&amp;quot;annoy&amp;quot;, &amp;quot;scratches your face&amp;quot;)&lt;br /&gt;
print(&amp;quot;Actions in CatClass:&amp;quot;, CatClass.count_action())&lt;br /&gt;
&lt;br /&gt;
mycat = CatClass(&amp;quot;Tom&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
kitten = mycat + yourcat&lt;br /&gt;
&lt;br /&gt;
print(f&amp;quot;Kitten: {kitten.name}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
yourcat.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This class looks fine, but it has a number of inheritance issues.&lt;br /&gt;
By creating a Tiger class that inherits from the CatClass, I will demonstrate. Also, see how simple it was to create a new class based on an old :-)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts = {&lt;br /&gt;
        &#039;scratch&#039;: &#039;roars&#039;,&lt;br /&gt;
        &#039;feed&#039;: &#039;demands more meat&#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.action(&amp;quot;scratch&amp;quot;)&lt;br /&gt;
tigger.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We want the Tiger to react differently than the Cat, at least for some actions. However, this code does not do it. The problem lies in the inherited &#039;&#039;&#039;action&#039;&#039;&#039; method.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
        elif self._gender == &#039;male&#039;:&lt;br /&gt;
            print(self._name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self._name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    # We are specifically using the actions in the CatClass for the behavior&lt;br /&gt;
    # We need to use the current class, as in cats uses CatClass actions and tigers uses Tiger actions.&lt;br /&gt;
&lt;br /&gt;
    # These are the problematic lines, they can be replaced in different ways&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
    # Through &#039;&#039;&#039;self&#039;&#039;&#039;, as self will search the instance namespace and then the class namespace for the variable&lt;br /&gt;
        if act in self.acts:&lt;br /&gt;
            print(self._name, self.acts[act])&lt;br /&gt;
    # By dynamically getting the class by type&lt;br /&gt;
        cls = type(self)&lt;br /&gt;
        if act in cls.acts:&lt;br /&gt;
            print(self._name, cls.acts[act])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This does not completely solve the problem. We would still like to be able to scare the tiger (inherit the cat action), but for now it looks bored when we try. This problem is caused by the complete replacement of the class variable acts in the Tiger class. The cat actions are deleted and replaced with tiger-only actions.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts = {&lt;br /&gt;
        &#039;scratch&#039;: &#039;roars&#039;,&lt;br /&gt;
        &#039;feed&#039;: &#039;demands more meat&#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
# Thats OK, we will just add the tiger actions later - we inherited the add_action from CatClass&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.add_action(&#039;scratch&#039;, &#039;roars&#039;)&lt;br /&gt;
tigger.add_action(&#039;feed&#039;, &#039;demands more meat&#039;)&lt;br /&gt;
# Testing&lt;br /&gt;
tigger.action(&#039;scare&#039;)&lt;br /&gt;
tigger.action(&#039;feed&#039;)&lt;br /&gt;
# All good, but what happened to our cat?&lt;br /&gt;
mycat.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The cat started roaring when scratched - that is a tiger action. Looking at the add_action class method, it is not specifying anywhere that the CatClass should be used so what is wrong? The problem is that the Tiger and the CatClass are &#039;&#039;sharing&#039;&#039; the class variables. The Tiger did not make new ones, so it is using the CatClass class variables, because CatClass is the parent class. Right now any changes in action made by the Tiger class is reflected in the CatClass and vice versa. The Tiger needs is own. Also did you notice that the Tiger&#039;s scientific name is Felis Catus, same as the cat - ridiculous.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Panthera&amp;quot;&lt;br /&gt;
    species = &amp;quot;Tigris&amp;quot;&lt;br /&gt;
    acts = CatClass.acts.copy()&lt;br /&gt;
    # Tiger class specials&lt;br /&gt;
    acts[&#039;scratch&#039;] = &#039;roars&#039;&lt;br /&gt;
    acts[&#039;feed&#039;} = &#039;demands more meat&#039;&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.action(&#039;scratch&#039;)&lt;br /&gt;
mycat.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Much better. Copy the mutable class variables from the base class and then change them so they fit.&lt;br /&gt;
&lt;br /&gt;
Life is good. Let&#039;s make some kittens.....&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
kitten1 = mycat + yourcat&lt;br /&gt;
print(kitten1.name)&lt;br /&gt;
&lt;br /&gt;
# Can we mate the cat and the tiger?&lt;br /&gt;
kitten2 = yourcat + tigger&lt;br /&gt;
kitten2.name = &amp;quot;Monstrous Mutant&amp;quot;&lt;br /&gt;
print(kitten2.name)&lt;br /&gt;
kitten2.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
That was unfortunate. We should not be able to breed a cat and a tiger, and if we did anyway, should the result be a cat (the kitten does a cat action)?&amp;lt;br&amp;gt;&lt;br /&gt;
The issue is in the &#039;&#039;__add__&#039;&#039; magic method. All that is required is that the two classes being &amp;quot;added&amp;quot; have a _gender instance variable.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Being biased and saying all kittens are male&lt;br /&gt;
        kitten = CatClass(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten&lt;br /&gt;
&lt;br /&gt;
    # Adding a class check - we must demand that we breed tigers with tigers and cats with cats&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        if type(self) != type(other):&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Still male kittens, making sure tigers begets tigers and cats begets cats&lt;br /&gt;
        kitten = type(self)(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten     &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are the two classes without any inheritance problems. I will leave it to you to do the testing. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class CatClass:&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Felis&amp;quot;&lt;br /&gt;
    species = &amp;quot;Catus&amp;quot;&lt;br /&gt;
    acts = {&#039;scratch&#039;: &amp;quot;purrs&amp;quot;,&lt;br /&gt;
            &#039;scare&#039;: &amp;quot;jumps high in the air&amp;quot;,&lt;br /&gt;
            &#039;feed&#039;: &amp;quot;is very excited&amp;quot; }&lt;br /&gt;
&lt;br /&gt;
    ### Instantiation&lt;br /&gt;
    def __init__(self, name, gender):&lt;br /&gt;
        self._name, self._gender = name, gender&lt;br /&gt;
&lt;br /&gt;
    ### Magic methods&lt;br /&gt;
    # Addition makes a kitten if male and female cat, alternative constructor&lt;br /&gt;
    # Adding a class check - we must demand that we breed tigers with tigers and cats with cats&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        if type(self) != type(other):&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Still male kittens, making sure tigers begets tigers and cats begets cats&lt;br /&gt;
        kitten = type(self)(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten&lt;br /&gt;
                &lt;br /&gt;
    ### Class methods&lt;br /&gt;
    # Adding a cat action&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def add_action(cls, action, reaction):&lt;br /&gt;
       cls.acts[action] = reaction&lt;br /&gt;
    # Querying class for number of actions&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def count_action(cls):&lt;br /&gt;
        return len(cls.acts)&lt;br /&gt;
&lt;br /&gt;
    ### Property methods&lt;br /&gt;
    # name setter and getter&lt;br /&gt;
    @property&lt;br /&gt;
    def name(self):&lt;br /&gt;
        if not hasattr(self, &#039;_name&#039;):&lt;br /&gt;
            raise NameError(&amp;quot;Name of cat is not yet set&amp;quot;)&lt;br /&gt;
        return self._name&lt;br /&gt;
        &lt;br /&gt;
    @name.setter&lt;br /&gt;
    def name(self, value):&lt;br /&gt;
        if value == &#039;&#039;:&lt;br /&gt;
            raise ValueError(&amp;quot;Name can not be nothing&amp;quot;)&lt;br /&gt;
        self._name = value&lt;br /&gt;
&lt;br /&gt;
    ### Instance methods&lt;br /&gt;
    # The action method - using class variables&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in self.acts:&lt;br /&gt;
            print(self._name, self.acts[act])&lt;br /&gt;
        elif self._gender == &#039;male&#039;:&lt;br /&gt;
            print(self._name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self._name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Panthera&amp;quot;&lt;br /&gt;
    species = &amp;quot;Tigris&amp;quot;&lt;br /&gt;
    acts = CatClass.acts.copy()&lt;br /&gt;
    # Tiger class specials&lt;br /&gt;
    acts[&#039;scratch&#039;] = &#039;roars&#039;&lt;br /&gt;
    acts[&#039;feed&#039;] = &#039;demands more meat&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
== Take home messages ==&lt;br /&gt;
* Even if you do not plan for your class to be inherited, make it so it can. That way it is less work later AND you remember how to do it.&lt;br /&gt;
* Don&#039;t hardcode class names in your class. Use &#039;&#039;type(self)&#039;&#039; to get the class. This goes when using class variables, constructing new instances and elsewhere. But not when copying the parent class&#039; class variables - there you have to name it :-)&lt;br /&gt;
* Make a copy of mutable class variables if you have any plan or possibility to modify them.&lt;br /&gt;
* In magic methods check that the &#039;&#039;other&#039;&#039; class is the same as &#039;&#039;self&#039;&#039;.&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=284</id>
		<title>Example code - Inheritance issues</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=284"/>
		<updated>2026-03-19T18:52:06Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Take home messages */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The challenges in inheritance can not be demonstrated well in a powerpoint.&lt;br /&gt;
Thus, I made this page with examples. You can copy the code in the section and add it together and run it.&lt;br /&gt;
&lt;br /&gt;
First I create a slightly bigger CatClass.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class CatClass:&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Felis&amp;quot;&lt;br /&gt;
    species = &amp;quot;Catus&amp;quot;&lt;br /&gt;
    acts = {&#039;scratch&#039;: &amp;quot;purrs&amp;quot;,&lt;br /&gt;
            &#039;scare&#039;: &amp;quot;jumps high in the air&amp;quot;,&lt;br /&gt;
            &#039;feed&#039;: &amp;quot;is very excited&amp;quot; }&lt;br /&gt;
&lt;br /&gt;
    ### Instatiation&lt;br /&gt;
    def __init__(self, name, gender):&lt;br /&gt;
        self._name, self._gender = name, gender&lt;br /&gt;
&lt;br /&gt;
    ### Magic methods&lt;br /&gt;
    # Addition makes a kitten if male and female cat, alternative constructor&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Being biased and saying all kittens are male&lt;br /&gt;
        kitten = CatClass(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten     &lt;br /&gt;
        &lt;br /&gt;
    ### Class methods&lt;br /&gt;
    # Adding a cat action&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def add_action(cls, action, reaction):&lt;br /&gt;
       cls.acts[action] = reaction&lt;br /&gt;
    # Querying class for number of actions&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def count_action(cls):&lt;br /&gt;
        return len(cls.acts)&lt;br /&gt;
&lt;br /&gt;
    ### Property methods&lt;br /&gt;
    # name setter and getter&lt;br /&gt;
    @property&lt;br /&gt;
    def name(self):&lt;br /&gt;
        if not hasattr(self, &#039;_name&#039;):&lt;br /&gt;
            raise NameError(&amp;quot;Name of cat is not yet set&amp;quot;)&lt;br /&gt;
        return self._name&lt;br /&gt;
        &lt;br /&gt;
    @name.setter&lt;br /&gt;
    def name(self, value):&lt;br /&gt;
        if value == &#039;&#039;:&lt;br /&gt;
            raise ValueError(&amp;quot;Name can not be nothing&amp;quot;)&lt;br /&gt;
        self._name = value&lt;br /&gt;
&lt;br /&gt;
    ### Instance methods&lt;br /&gt;
    # The action method - using class variables&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
        elif self._gender == &#039;male&#039;:&lt;br /&gt;
            print(self._name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self._name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
### Main program                    &lt;br /&gt;
yourcat = CatClass(&#039;Missy&#039;, &#039;female&#039;)&lt;br /&gt;
&lt;br /&gt;
CatClass.add_action(&amp;quot;annoy&amp;quot;, &amp;quot;scratches your face&amp;quot;)&lt;br /&gt;
print(&amp;quot;Actions in CatClass:&amp;quot;, CatClass.count_action())&lt;br /&gt;
&lt;br /&gt;
mycat = CatClass(&amp;quot;Tom&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
kitten = mycat + yourcat&lt;br /&gt;
&lt;br /&gt;
print(f&amp;quot;Kitten: {kitten.name}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
yourcat.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This class looks fine, but it has a number of inheritance issues.&lt;br /&gt;
By creating a Tiger class that inherits from the CatClass, I will demonstrate. Also, see how simple it was to create a new class based on an old :-)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts = {&lt;br /&gt;
        &#039;scratch&#039;: &#039;roars&#039;,&lt;br /&gt;
        &#039;feed&#039;: &#039;demands more meat&#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.action(&amp;quot;scratch&amp;quot;)&lt;br /&gt;
tigger.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We want the Tiger to react differently than the Cat, at least for some actions. However, this code does not do it. The problem lies in the inherited &#039;&#039;&#039;action&#039;&#039;&#039; method.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
        elif self._gender == &#039;male&#039;:&lt;br /&gt;
            print(self._name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self._name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    # We are specifically using the actions in the CatClass for the behavior&lt;br /&gt;
    # We need to use the current class, as in cats uses CatClass actions and tigers uses Tiger actions.&lt;br /&gt;
&lt;br /&gt;
    # These are the problematic lines, they can be replaced in different ways&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
    # Through &#039;&#039;&#039;self&#039;&#039;&#039;, as self will search the instance namespace and then the class namespace for the variable&lt;br /&gt;
        if act in self.acts:&lt;br /&gt;
            print(self._name, self.acts[act])&lt;br /&gt;
    # By dynamically getting the class by type&lt;br /&gt;
        cls = type(self)&lt;br /&gt;
        if act in cls.acts:&lt;br /&gt;
            print(self._name, cls.acts[act])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This does not completely solve the problem. We would still like to be able to scare the tiger (inherit the cat action), but for now it looks bored when we try. This problem is caused by the complete replacement of the class variable acts in the Tiger class. The cat actions are deleted and replaced with tiger-only actions.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts = {&lt;br /&gt;
        &#039;scratch&#039;: &#039;roars&#039;,&lt;br /&gt;
        &#039;feed&#039;: &#039;demands more meat&#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
# Thats OK, we will just add the tiger actions later - we inherited the add_action from CatClass&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.add_action(&#039;scratch&#039;, &#039;roars&#039;)&lt;br /&gt;
tigger.add_action(&#039;feed&#039;, &#039;demands more meat&#039;)&lt;br /&gt;
# Testing&lt;br /&gt;
tigger.action(&#039;scare&#039;)&lt;br /&gt;
tigger.action(&#039;feed&#039;)&lt;br /&gt;
# All good, but what happened to our cat?&lt;br /&gt;
mycat.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The cat started roaring when scratched - that is a tiger action. Looking at the add_action class method, it is not specifying anywhere that the CatClass should be used so what is wrong? The problem is that the Tiger and the CatClass are &#039;&#039;sharing&#039;&#039; the class variables. The Tiger did not make new ones, so it is using the CatClass class variables, because CatClass is the parent class. Right now any changes in action made by the Tiger class is reflected in the CatClass and vice versa. The Tiger needs is own. Also did you notice that the Tiger&#039;s scientific name is Felis Catus, same as the cat - ridiculous.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Panthera&amp;quot;&lt;br /&gt;
    species = &amp;quot;Tigris&amp;quot;&lt;br /&gt;
    acts = CatClass.acts.copy()&lt;br /&gt;
    # Tiger class specials&lt;br /&gt;
    acts[&#039;scratch&#039;] = &#039;roars&#039;&lt;br /&gt;
    acts[&#039;feed&#039;} = &#039;demands more meat&#039;&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.action(&#039;scratch&#039;)&lt;br /&gt;
mycat.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Much better. Copy the mutable class variables from the base class and then change them so they fit.&lt;br /&gt;
&lt;br /&gt;
Life is good. Let&#039;s make some kittens.....&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
kitten1 = mycat + yourcat&lt;br /&gt;
print(kitten1.name)&lt;br /&gt;
&lt;br /&gt;
# Can we mate the cat and the tiger?&lt;br /&gt;
kitten2 = yourcat + tigger&lt;br /&gt;
kitten2.name = &amp;quot;Monstrous Mutant&amp;quot;&lt;br /&gt;
print(kitten2.name)&lt;br /&gt;
kitten2.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
That was unfortunate. We should not be able to breed a cat and a tiger, and if we did anyway, should the result be a cat (the kitten does a cat action)?&amp;lt;br&amp;gt;&lt;br /&gt;
The issue is in the &#039;&#039;__add__&#039;&#039; magic method. All that is required is that the two classes being &amp;quot;added&amp;quot; have a _gender instance variable.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Being biased and saying all kittens are male&lt;br /&gt;
        kitten = CatClass(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten&lt;br /&gt;
&lt;br /&gt;
    # Adding a class check - we must demand that we breed tigers with tigers and cats with cats&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        if type(self) != type(other):&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Still male kittens, making sure tigers begets tigers and cats begets cats&lt;br /&gt;
        kitten = type(self)(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten     &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are the two classes without any inheritance problems. I will leave it to you to do the testing. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class CatClass:&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Felis&amp;quot;&lt;br /&gt;
    species = &amp;quot;Catus&amp;quot;&lt;br /&gt;
    acts = {&#039;scratch&#039;: &amp;quot;purrs&amp;quot;,&lt;br /&gt;
            &#039;scare&#039;: &amp;quot;jumps high in the air&amp;quot;,&lt;br /&gt;
            &#039;feed&#039;: &amp;quot;is very excited&amp;quot; }&lt;br /&gt;
&lt;br /&gt;
    ### Instatiation&lt;br /&gt;
    def __init__(self, name, gender):&lt;br /&gt;
        self._name, self._gender = name, gender&lt;br /&gt;
&lt;br /&gt;
    ### Magic methods&lt;br /&gt;
    # Addition makes a kitten if male and female cat, alternative constructor&lt;br /&gt;
    # Adding a class check - we must demand that we breed tigers with tigers and cats with cats&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        if type(self) != type(other):&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Still male kittens, making sure tigers begets tigers and cats begets cats&lt;br /&gt;
        kitten = type(self)(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten&lt;br /&gt;
                &lt;br /&gt;
    ### Class methods&lt;br /&gt;
    # Adding a cat action&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def add_action(cls, action, reaction):&lt;br /&gt;
       cls.acts[action] = reaction&lt;br /&gt;
    # Querying class for number of actions&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def count_action(cls):&lt;br /&gt;
        return len(cls.acts)&lt;br /&gt;
&lt;br /&gt;
    ### Property methods&lt;br /&gt;
    # name setter and getter&lt;br /&gt;
    @property&lt;br /&gt;
    def name(self):&lt;br /&gt;
        if not hasattr(self, &#039;_name&#039;):&lt;br /&gt;
            raise NameError(&amp;quot;Name of cat is not yet set&amp;quot;)&lt;br /&gt;
        return self._name&lt;br /&gt;
        &lt;br /&gt;
    @name.setter&lt;br /&gt;
    def name(self, value):&lt;br /&gt;
        if value == &#039;&#039;:&lt;br /&gt;
            raise ValueError(&amp;quot;Name can not be nothing&amp;quot;)&lt;br /&gt;
        self._name = value&lt;br /&gt;
&lt;br /&gt;
    ### Instance methods&lt;br /&gt;
    # The action method - using class variables&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in self.acts:&lt;br /&gt;
            print(self._name, self.acts[act])&lt;br /&gt;
        elif self._gender == &#039;male&#039;:&lt;br /&gt;
            print(self._name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self._name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Panthera&amp;quot;&lt;br /&gt;
    species = &amp;quot;Tigris&amp;quot;&lt;br /&gt;
    acts = CatClass.acts.copy()&lt;br /&gt;
    # Tiger class specials&lt;br /&gt;
    acts[&#039;scratch&#039;] = &#039;roars&#039;&lt;br /&gt;
    acts[&#039;feed&#039;] = &#039;demands more meat&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
== Take home messages ==&lt;br /&gt;
* Even if you do not plan for your class to be inherited, make it so it can. That way it is less work later AND you remember how to do it.&lt;br /&gt;
* Don&#039;t hardcode class names in your class. Use &#039;&#039;type(self)&#039;&#039; to get the class. This goes when using class variables, constructing new instances and elsewhere. But not when copying the parent class&#039; class variables - there you have to name it :-)&lt;br /&gt;
* Make a copy of mutable class variables if you have any plan or possibility to modify them.&lt;br /&gt;
* In magic methods check that the &#039;&#039;other&#039;&#039; class is the same as &#039;&#039;self&#039;&#039;.&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=283</id>
		<title>Example code - Inheritance issues</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=283"/>
		<updated>2026-03-19T18:48:00Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Take home messages */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The challenges in inheritance can not be demonstrated well in a powerpoint.&lt;br /&gt;
Thus, I made this page with examples. You can copy the code in the section and add it together and run it.&lt;br /&gt;
&lt;br /&gt;
First I create a slightly bigger CatClass.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class CatClass:&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Felis&amp;quot;&lt;br /&gt;
    species = &amp;quot;Catus&amp;quot;&lt;br /&gt;
    acts = {&#039;scratch&#039;: &amp;quot;purrs&amp;quot;,&lt;br /&gt;
            &#039;scare&#039;: &amp;quot;jumps high in the air&amp;quot;,&lt;br /&gt;
            &#039;feed&#039;: &amp;quot;is very excited&amp;quot; }&lt;br /&gt;
&lt;br /&gt;
    ### Instatiation&lt;br /&gt;
    def __init__(self, name, gender):&lt;br /&gt;
        self._name, self._gender = name, gender&lt;br /&gt;
&lt;br /&gt;
    ### Magic methods&lt;br /&gt;
    # Addition makes a kitten if male and female cat, alternative constructor&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Being biased and saying all kittens are male&lt;br /&gt;
        kitten = CatClass(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten     &lt;br /&gt;
        &lt;br /&gt;
    ### Class methods&lt;br /&gt;
    # Adding a cat action&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def add_action(cls, action, reaction):&lt;br /&gt;
       cls.acts[action] = reaction&lt;br /&gt;
    # Querying class for number of actions&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def count_action(cls):&lt;br /&gt;
        return len(cls.acts)&lt;br /&gt;
&lt;br /&gt;
    ### Property methods&lt;br /&gt;
    # name setter and getter&lt;br /&gt;
    @property&lt;br /&gt;
    def name(self):&lt;br /&gt;
        if not hasattr(self, &#039;_name&#039;):&lt;br /&gt;
            raise NameError(&amp;quot;Name of cat is not yet set&amp;quot;)&lt;br /&gt;
        return self._name&lt;br /&gt;
        &lt;br /&gt;
    @name.setter&lt;br /&gt;
    def name(self, value):&lt;br /&gt;
        if value == &#039;&#039;:&lt;br /&gt;
            raise ValueError(&amp;quot;Name can not be nothing&amp;quot;)&lt;br /&gt;
        self._name = value&lt;br /&gt;
&lt;br /&gt;
    ### Instance methods&lt;br /&gt;
    # The action method - using class variables&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
        elif self._gender == &#039;male&#039;:&lt;br /&gt;
            print(self._name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self._name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
### Main program                    &lt;br /&gt;
yourcat = CatClass(&#039;Missy&#039;, &#039;female&#039;)&lt;br /&gt;
&lt;br /&gt;
CatClass.add_action(&amp;quot;annoy&amp;quot;, &amp;quot;scratches your face&amp;quot;)&lt;br /&gt;
print(&amp;quot;Actions in CatClass:&amp;quot;, CatClass.count_action())&lt;br /&gt;
&lt;br /&gt;
mycat = CatClass(&amp;quot;Tom&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
kitten = mycat + yourcat&lt;br /&gt;
&lt;br /&gt;
print(f&amp;quot;Kitten: {kitten.name}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
yourcat.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This class looks fine, but it has a number of inheritance issues.&lt;br /&gt;
By creating a Tiger class that inherits from the CatClass, I will demonstrate. Also, see how simple it was to create a new class based on an old :-)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts = {&lt;br /&gt;
        &#039;scratch&#039;: &#039;roars&#039;,&lt;br /&gt;
        &#039;feed&#039;: &#039;demands more meat&#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.action(&amp;quot;scratch&amp;quot;)&lt;br /&gt;
tigger.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We want the Tiger to react differently than the Cat, at least for some actions. However, this code does not do it. The problem lies in the inherited &#039;&#039;&#039;action&#039;&#039;&#039; method.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
        elif self._gender == &#039;male&#039;:&lt;br /&gt;
            print(self._name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self._name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    # We are specifically using the actions in the CatClass for the behavior&lt;br /&gt;
    # We need to use the current class, as in cats uses CatClass actions and tigers uses Tiger actions.&lt;br /&gt;
&lt;br /&gt;
    # These are the problematic lines, they can be replaced in different ways&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
    # Through &#039;&#039;&#039;self&#039;&#039;&#039;, as self will search the instance namespace and then the class namespace for the variable&lt;br /&gt;
        if act in self.acts:&lt;br /&gt;
            print(self._name, self.acts[act])&lt;br /&gt;
    # By dynamically getting the class by type&lt;br /&gt;
        cls = type(self)&lt;br /&gt;
        if act in cls.acts:&lt;br /&gt;
            print(self._name, cls.acts[act])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This does not completely solve the problem. We would still like to be able to scare the tiger (inherit the cat action), but for now it looks bored when we try. This problem is caused by the complete replacement of the class variable acts in the Tiger class. The cat actions are deleted and replaced with tiger-only actions.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts = {&lt;br /&gt;
        &#039;scratch&#039;: &#039;roars&#039;,&lt;br /&gt;
        &#039;feed&#039;: &#039;demands more meat&#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
# Thats OK, we will just add the tiger actions later - we inherited the add_action from CatClass&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.add_action(&#039;scratch&#039;, &#039;roars&#039;)&lt;br /&gt;
tigger.add_action(&#039;feed&#039;, &#039;demands more meat&#039;)&lt;br /&gt;
# Testing&lt;br /&gt;
tigger.action(&#039;scare&#039;)&lt;br /&gt;
tigger.action(&#039;feed&#039;)&lt;br /&gt;
# All good, but what happened to our cat?&lt;br /&gt;
mycat.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The cat started roaring when scratched - that is a tiger action. Looking at the add_action class method, it is not specifying anywhere that the CatClass should be used so what is wrong? The problem is that the Tiger and the CatClass are &#039;&#039;sharing&#039;&#039; the class variables. The Tiger did not make new ones, so it is using the CatClass class variables, because CatClass is the parent class. Right now any changes in action made by the Tiger class is reflected in the CatClass and vice versa. The Tiger needs is own. Also did you notice that the Tiger&#039;s scientific name is Felis Catus, same as the cat - ridiculous.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Panthera&amp;quot;&lt;br /&gt;
    species = &amp;quot;Tigris&amp;quot;&lt;br /&gt;
    acts = CatClass.acts.copy()&lt;br /&gt;
    # Tiger class specials&lt;br /&gt;
    acts[&#039;scratch&#039;] = &#039;roars&#039;&lt;br /&gt;
    acts[&#039;feed&#039;} = &#039;demands more meat&#039;&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.action(&#039;scratch&#039;)&lt;br /&gt;
mycat.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Much better. Copy the mutable class variables from the base class and then change them so they fit.&lt;br /&gt;
&lt;br /&gt;
Life is good. Let&#039;s make some kittens.....&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
kitten1 = mycat + yourcat&lt;br /&gt;
print(kitten1.name)&lt;br /&gt;
&lt;br /&gt;
# Can we mate the cat and the tiger?&lt;br /&gt;
kitten2 = yourcat + tigger&lt;br /&gt;
kitten2.name = &amp;quot;Monstrous Mutant&amp;quot;&lt;br /&gt;
print(kitten2.name)&lt;br /&gt;
kitten2.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
That was unfortunate. We should not be able to breed a cat and a tiger, and if we did anyway, should the result be a cat (the kitten does a cat action)?&amp;lt;br&amp;gt;&lt;br /&gt;
The issue is in the &#039;&#039;__add__&#039;&#039; magic method. All that is required is that the two classes being &amp;quot;added&amp;quot; have a _gender instance variable.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Being biased and saying all kittens are male&lt;br /&gt;
        kitten = CatClass(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten&lt;br /&gt;
&lt;br /&gt;
    # Adding a class check - we must demand that we breed tigers with tigers and cats with cats&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        if type(self) != type(other):&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Still male kittens, making sure tigers begets tigers and cats begets cats&lt;br /&gt;
        kitten = type(self)(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten     &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are the two classes without any inheritance problems. I will leave it to you to do the testing. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class CatClass:&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Felis&amp;quot;&lt;br /&gt;
    species = &amp;quot;Catus&amp;quot;&lt;br /&gt;
    acts = {&#039;scratch&#039;: &amp;quot;purrs&amp;quot;,&lt;br /&gt;
            &#039;scare&#039;: &amp;quot;jumps high in the air&amp;quot;,&lt;br /&gt;
            &#039;feed&#039;: &amp;quot;is very excited&amp;quot; }&lt;br /&gt;
&lt;br /&gt;
    ### Instatiation&lt;br /&gt;
    def __init__(self, name, gender):&lt;br /&gt;
        self._name, self._gender = name, gender&lt;br /&gt;
&lt;br /&gt;
    ### Magic methods&lt;br /&gt;
    # Addition makes a kitten if male and female cat, alternative constructor&lt;br /&gt;
    # Adding a class check - we must demand that we breed tigers with tigers and cats with cats&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        if type(self) != type(other):&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Still male kittens, making sure tigers begets tigers and cats begets cats&lt;br /&gt;
        kitten = type(self)(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten&lt;br /&gt;
                &lt;br /&gt;
    ### Class methods&lt;br /&gt;
    # Adding a cat action&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def add_action(cls, action, reaction):&lt;br /&gt;
       cls.acts[action] = reaction&lt;br /&gt;
    # Querying class for number of actions&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def count_action(cls):&lt;br /&gt;
        return len(cls.acts)&lt;br /&gt;
&lt;br /&gt;
    ### Property methods&lt;br /&gt;
    # name setter and getter&lt;br /&gt;
    @property&lt;br /&gt;
    def name(self):&lt;br /&gt;
        if not hasattr(self, &#039;_name&#039;):&lt;br /&gt;
            raise NameError(&amp;quot;Name of cat is not yet set&amp;quot;)&lt;br /&gt;
        return self._name&lt;br /&gt;
        &lt;br /&gt;
    @name.setter&lt;br /&gt;
    def name(self, value):&lt;br /&gt;
        if value == &#039;&#039;:&lt;br /&gt;
            raise ValueError(&amp;quot;Name can not be nothing&amp;quot;)&lt;br /&gt;
        self._name = value&lt;br /&gt;
&lt;br /&gt;
    ### Instance methods&lt;br /&gt;
    # The action method - using class variables&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in self.acts:&lt;br /&gt;
            print(self._name, self.acts[act])&lt;br /&gt;
        elif self._gender == &#039;male&#039;:&lt;br /&gt;
            print(self._name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self._name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Panthera&amp;quot;&lt;br /&gt;
    species = &amp;quot;Tigris&amp;quot;&lt;br /&gt;
    acts = CatClass.acts.copy()&lt;br /&gt;
    # Tiger class specials&lt;br /&gt;
    acts[&#039;scratch&#039;] = &#039;roars&#039;&lt;br /&gt;
    acts[&#039;feed&#039;] = &#039;demands more meat&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
== Take home messages ==&lt;br /&gt;
* Even if you do not plan for your class to be inherited, make it so it can. That way it is less work later AND you remember how to do it.&lt;br /&gt;
* Don&#039;t hardcode class names in your class. Use &#039;&#039;type(self)&#039;&#039; to get the class. This goes when using class variables, constructing new instances.&lt;br /&gt;
* Make a copy of mutable class variables if you have any plan or possibility to modify them.&lt;br /&gt;
* In magic methods check that the &#039;&#039;other&#039;&#039; class is the same as &#039;&#039;self&#039;&#039;.&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=282</id>
		<title>Example code - Inheritance issues</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=282"/>
		<updated>2026-03-19T18:44:30Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Take home messages */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The challenges in inheritance can not be demonstrated well in a powerpoint.&lt;br /&gt;
Thus, I made this page with examples. You can copy the code in the section and add it together and run it.&lt;br /&gt;
&lt;br /&gt;
First I create a slightly bigger CatClass.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class CatClass:&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Felis&amp;quot;&lt;br /&gt;
    species = &amp;quot;Catus&amp;quot;&lt;br /&gt;
    acts = {&#039;scratch&#039;: &amp;quot;purrs&amp;quot;,&lt;br /&gt;
            &#039;scare&#039;: &amp;quot;jumps high in the air&amp;quot;,&lt;br /&gt;
            &#039;feed&#039;: &amp;quot;is very excited&amp;quot; }&lt;br /&gt;
&lt;br /&gt;
    ### Instatiation&lt;br /&gt;
    def __init__(self, name, gender):&lt;br /&gt;
        self._name, self._gender = name, gender&lt;br /&gt;
&lt;br /&gt;
    ### Magic methods&lt;br /&gt;
    # Addition makes a kitten if male and female cat, alternative constructor&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Being biased and saying all kittens are male&lt;br /&gt;
        kitten = CatClass(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten     &lt;br /&gt;
        &lt;br /&gt;
    ### Class methods&lt;br /&gt;
    # Adding a cat action&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def add_action(cls, action, reaction):&lt;br /&gt;
       cls.acts[action] = reaction&lt;br /&gt;
    # Querying class for number of actions&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def count_action(cls):&lt;br /&gt;
        return len(cls.acts)&lt;br /&gt;
&lt;br /&gt;
    ### Property methods&lt;br /&gt;
    # name setter and getter&lt;br /&gt;
    @property&lt;br /&gt;
    def name(self):&lt;br /&gt;
        if not hasattr(self, &#039;_name&#039;):&lt;br /&gt;
            raise NameError(&amp;quot;Name of cat is not yet set&amp;quot;)&lt;br /&gt;
        return self._name&lt;br /&gt;
        &lt;br /&gt;
    @name.setter&lt;br /&gt;
    def name(self, value):&lt;br /&gt;
        if value == &#039;&#039;:&lt;br /&gt;
            raise ValueError(&amp;quot;Name can not be nothing&amp;quot;)&lt;br /&gt;
        self._name = value&lt;br /&gt;
&lt;br /&gt;
    ### Instance methods&lt;br /&gt;
    # The action method - using class variables&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
        elif self._gender == &#039;male&#039;:&lt;br /&gt;
            print(self._name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self._name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
### Main program                    &lt;br /&gt;
yourcat = CatClass(&#039;Missy&#039;, &#039;female&#039;)&lt;br /&gt;
&lt;br /&gt;
CatClass.add_action(&amp;quot;annoy&amp;quot;, &amp;quot;scratches your face&amp;quot;)&lt;br /&gt;
print(&amp;quot;Actions in CatClass:&amp;quot;, CatClass.count_action())&lt;br /&gt;
&lt;br /&gt;
mycat = CatClass(&amp;quot;Tom&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
kitten = mycat + yourcat&lt;br /&gt;
&lt;br /&gt;
print(f&amp;quot;Kitten: {kitten.name}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
yourcat.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This class looks fine, but it has a number of inheritance issues.&lt;br /&gt;
By creating a Tiger class that inherits from the CatClass, I will demonstrate. Also, see how simple it was to create a new class based on an old :-)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts = {&lt;br /&gt;
        &#039;scratch&#039;: &#039;roars&#039;,&lt;br /&gt;
        &#039;feed&#039;: &#039;demands more meat&#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.action(&amp;quot;scratch&amp;quot;)&lt;br /&gt;
tigger.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We want the Tiger to react differently than the Cat, at least for some actions. However, this code does not do it. The problem lies in the inherited &#039;&#039;&#039;action&#039;&#039;&#039; method.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
        elif self._gender == &#039;male&#039;:&lt;br /&gt;
            print(self._name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self._name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    # We are specifically using the actions in the CatClass for the behavior&lt;br /&gt;
    # We need to use the current class, as in cats uses CatClass actions and tigers uses Tiger actions.&lt;br /&gt;
&lt;br /&gt;
    # These are the problematic lines, they can be replaced in different ways&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
    # Through &#039;&#039;&#039;self&#039;&#039;&#039;, as self will search the instance namespace and then the class namespace for the variable&lt;br /&gt;
        if act in self.acts:&lt;br /&gt;
            print(self._name, self.acts[act])&lt;br /&gt;
    # By dynamically getting the class by type&lt;br /&gt;
        cls = type(self)&lt;br /&gt;
        if act in cls.acts:&lt;br /&gt;
            print(self._name, cls.acts[act])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This does not completely solve the problem. We would still like to be able to scare the tiger (inherit the cat action), but for now it looks bored when we try. This problem is caused by the complete replacement of the class variable acts in the Tiger class. The cat actions are deleted and replaced with tiger-only actions.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts = {&lt;br /&gt;
        &#039;scratch&#039;: &#039;roars&#039;,&lt;br /&gt;
        &#039;feed&#039;: &#039;demands more meat&#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
# Thats OK, we will just add the tiger actions later - we inherited the add_action from CatClass&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.add_action(&#039;scratch&#039;, &#039;roars&#039;)&lt;br /&gt;
tigger.add_action(&#039;feed&#039;, &#039;demands more meat&#039;)&lt;br /&gt;
# Testing&lt;br /&gt;
tigger.action(&#039;scare&#039;)&lt;br /&gt;
tigger.action(&#039;feed&#039;)&lt;br /&gt;
# All good, but what happened to our cat?&lt;br /&gt;
mycat.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The cat started roaring when scratched - that is a tiger action. Looking at the add_action class method, it is not specifying anywhere that the CatClass should be used so what is wrong? The problem is that the Tiger and the CatClass are &#039;&#039;sharing&#039;&#039; the class variables. The Tiger did not make new ones, so it is using the CatClass class variables, because CatClass is the parent class. Right now any changes in action made by the Tiger class is reflected in the CatClass and vice versa. The Tiger needs is own. Also did you notice that the Tiger&#039;s scientific name is Felis Catus, same as the cat - ridiculous.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Panthera&amp;quot;&lt;br /&gt;
    species = &amp;quot;Tigris&amp;quot;&lt;br /&gt;
    acts = CatClass.acts.copy()&lt;br /&gt;
    # Tiger class specials&lt;br /&gt;
    acts[&#039;scratch&#039;] = &#039;roars&#039;&lt;br /&gt;
    acts[&#039;feed&#039;} = &#039;demands more meat&#039;&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.action(&#039;scratch&#039;)&lt;br /&gt;
mycat.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Much better. Copy the mutable class variables from the base class and then change them so they fit.&lt;br /&gt;
&lt;br /&gt;
Life is good. Let&#039;s make some kittens.....&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
kitten1 = mycat + yourcat&lt;br /&gt;
print(kitten1.name)&lt;br /&gt;
&lt;br /&gt;
# Can we mate the cat and the tiger?&lt;br /&gt;
kitten2 = yourcat + tigger&lt;br /&gt;
kitten2.name = &amp;quot;Monstrous Mutant&amp;quot;&lt;br /&gt;
print(kitten2.name)&lt;br /&gt;
kitten2.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
That was unfortunate. We should not be able to breed a cat and a tiger, and if we did anyway, should the result be a cat (the kitten does a cat action)?&amp;lt;br&amp;gt;&lt;br /&gt;
The issue is in the &#039;&#039;__add__&#039;&#039; magic method. All that is required is that the two classes being &amp;quot;added&amp;quot; have a _gender instance variable.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Being biased and saying all kittens are male&lt;br /&gt;
        kitten = CatClass(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten&lt;br /&gt;
&lt;br /&gt;
    # Adding a class check - we must demand that we breed tigers with tigers and cats with cats&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        if type(self) != type(other):&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Still male kittens, making sure tigers begets tigers and cats begets cats&lt;br /&gt;
        kitten = type(self)(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten     &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are the two classes without any inheritance problems. I will leave it to you to do the testing. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class CatClass:&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Felis&amp;quot;&lt;br /&gt;
    species = &amp;quot;Catus&amp;quot;&lt;br /&gt;
    acts = {&#039;scratch&#039;: &amp;quot;purrs&amp;quot;,&lt;br /&gt;
            &#039;scare&#039;: &amp;quot;jumps high in the air&amp;quot;,&lt;br /&gt;
            &#039;feed&#039;: &amp;quot;is very excited&amp;quot; }&lt;br /&gt;
&lt;br /&gt;
    ### Instatiation&lt;br /&gt;
    def __init__(self, name, gender):&lt;br /&gt;
        self._name, self._gender = name, gender&lt;br /&gt;
&lt;br /&gt;
    ### Magic methods&lt;br /&gt;
    # Addition makes a kitten if male and female cat, alternative constructor&lt;br /&gt;
    # Adding a class check - we must demand that we breed tigers with tigers and cats with cats&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        if type(self) != type(other):&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Still male kittens, making sure tigers begets tigers and cats begets cats&lt;br /&gt;
        kitten = type(self)(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten&lt;br /&gt;
                &lt;br /&gt;
    ### Class methods&lt;br /&gt;
    # Adding a cat action&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def add_action(cls, action, reaction):&lt;br /&gt;
       cls.acts[action] = reaction&lt;br /&gt;
    # Querying class for number of actions&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def count_action(cls):&lt;br /&gt;
        return len(cls.acts)&lt;br /&gt;
&lt;br /&gt;
    ### Property methods&lt;br /&gt;
    # name setter and getter&lt;br /&gt;
    @property&lt;br /&gt;
    def name(self):&lt;br /&gt;
        if not hasattr(self, &#039;_name&#039;):&lt;br /&gt;
            raise NameError(&amp;quot;Name of cat is not yet set&amp;quot;)&lt;br /&gt;
        return self._name&lt;br /&gt;
        &lt;br /&gt;
    @name.setter&lt;br /&gt;
    def name(self, value):&lt;br /&gt;
        if value == &#039;&#039;:&lt;br /&gt;
            raise ValueError(&amp;quot;Name can not be nothing&amp;quot;)&lt;br /&gt;
        self._name = value&lt;br /&gt;
&lt;br /&gt;
    ### Instance methods&lt;br /&gt;
    # The action method - using class variables&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in self.acts:&lt;br /&gt;
            print(self._name, self.acts[act])&lt;br /&gt;
        elif self._gender == &#039;male&#039;:&lt;br /&gt;
            print(self._name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self._name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Panthera&amp;quot;&lt;br /&gt;
    species = &amp;quot;Tigris&amp;quot;&lt;br /&gt;
    acts = CatClass.acts.copy()&lt;br /&gt;
    # Tiger class specials&lt;br /&gt;
    acts[&#039;scratch&#039;] = &#039;roars&#039;&lt;br /&gt;
    acts[&#039;feed&#039;] = &#039;demands more meat&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
== Take home messages ==&lt;br /&gt;
* Even if you do not plan for your class to be inherited, make it so it can. That way it is less work later AND you remember how to do it.&lt;br /&gt;
* Don&#039;t hardcode class names in your class. Use &#039;&#039;type(self)&#039;&#039; to get the class.&lt;br /&gt;
* Make a copy of mutable class variables if you have any plan or possibility to modify them.&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=281</id>
		<title>Example code - Inheritance issues</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=281"/>
		<updated>2026-03-19T18:42:29Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The challenges in inheritance can not be demonstrated well in a powerpoint.&lt;br /&gt;
Thus, I made this page with examples. You can copy the code in the section and add it together and run it.&lt;br /&gt;
&lt;br /&gt;
First I create a slightly bigger CatClass.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class CatClass:&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Felis&amp;quot;&lt;br /&gt;
    species = &amp;quot;Catus&amp;quot;&lt;br /&gt;
    acts = {&#039;scratch&#039;: &amp;quot;purrs&amp;quot;,&lt;br /&gt;
            &#039;scare&#039;: &amp;quot;jumps high in the air&amp;quot;,&lt;br /&gt;
            &#039;feed&#039;: &amp;quot;is very excited&amp;quot; }&lt;br /&gt;
&lt;br /&gt;
    ### Instatiation&lt;br /&gt;
    def __init__(self, name, gender):&lt;br /&gt;
        self._name, self._gender = name, gender&lt;br /&gt;
&lt;br /&gt;
    ### Magic methods&lt;br /&gt;
    # Addition makes a kitten if male and female cat, alternative constructor&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Being biased and saying all kittens are male&lt;br /&gt;
        kitten = CatClass(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten     &lt;br /&gt;
        &lt;br /&gt;
    ### Class methods&lt;br /&gt;
    # Adding a cat action&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def add_action(cls, action, reaction):&lt;br /&gt;
       cls.acts[action] = reaction&lt;br /&gt;
    # Querying class for number of actions&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def count_action(cls):&lt;br /&gt;
        return len(cls.acts)&lt;br /&gt;
&lt;br /&gt;
    ### Property methods&lt;br /&gt;
    # name setter and getter&lt;br /&gt;
    @property&lt;br /&gt;
    def name(self):&lt;br /&gt;
        if not hasattr(self, &#039;_name&#039;):&lt;br /&gt;
            raise NameError(&amp;quot;Name of cat is not yet set&amp;quot;)&lt;br /&gt;
        return self._name&lt;br /&gt;
        &lt;br /&gt;
    @name.setter&lt;br /&gt;
    def name(self, value):&lt;br /&gt;
        if value == &#039;&#039;:&lt;br /&gt;
            raise ValueError(&amp;quot;Name can not be nothing&amp;quot;)&lt;br /&gt;
        self._name = value&lt;br /&gt;
&lt;br /&gt;
    ### Instance methods&lt;br /&gt;
    # The action method - using class variables&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
        elif self._gender == &#039;male&#039;:&lt;br /&gt;
            print(self._name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self._name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
### Main program                    &lt;br /&gt;
yourcat = CatClass(&#039;Missy&#039;, &#039;female&#039;)&lt;br /&gt;
&lt;br /&gt;
CatClass.add_action(&amp;quot;annoy&amp;quot;, &amp;quot;scratches your face&amp;quot;)&lt;br /&gt;
print(&amp;quot;Actions in CatClass:&amp;quot;, CatClass.count_action())&lt;br /&gt;
&lt;br /&gt;
mycat = CatClass(&amp;quot;Tom&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
kitten = mycat + yourcat&lt;br /&gt;
&lt;br /&gt;
print(f&amp;quot;Kitten: {kitten.name}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
yourcat.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This class looks fine, but it has a number of inheritance issues.&lt;br /&gt;
By creating a Tiger class that inherits from the CatClass, I will demonstrate. Also, see how simple it was to create a new class based on an old :-)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts = {&lt;br /&gt;
        &#039;scratch&#039;: &#039;roars&#039;,&lt;br /&gt;
        &#039;feed&#039;: &#039;demands more meat&#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.action(&amp;quot;scratch&amp;quot;)&lt;br /&gt;
tigger.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We want the Tiger to react differently than the Cat, at least for some actions. However, this code does not do it. The problem lies in the inherited &#039;&#039;&#039;action&#039;&#039;&#039; method.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
        elif self._gender == &#039;male&#039;:&lt;br /&gt;
            print(self._name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self._name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    # We are specifically using the actions in the CatClass for the behavior&lt;br /&gt;
    # We need to use the current class, as in cats uses CatClass actions and tigers uses Tiger actions.&lt;br /&gt;
&lt;br /&gt;
    # These are the problematic lines, they can be replaced in different ways&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
    # Through &#039;&#039;&#039;self&#039;&#039;&#039;, as self will search the instance namespace and then the class namespace for the variable&lt;br /&gt;
        if act in self.acts:&lt;br /&gt;
            print(self._name, self.acts[act])&lt;br /&gt;
    # By dynamically getting the class by type&lt;br /&gt;
        cls = type(self)&lt;br /&gt;
        if act in cls.acts:&lt;br /&gt;
            print(self._name, cls.acts[act])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This does not completely solve the problem. We would still like to be able to scare the tiger (inherit the cat action), but for now it looks bored when we try. This problem is caused by the complete replacement of the class variable acts in the Tiger class. The cat actions are deleted and replaced with tiger-only actions.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts = {&lt;br /&gt;
        &#039;scratch&#039;: &#039;roars&#039;,&lt;br /&gt;
        &#039;feed&#039;: &#039;demands more meat&#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
# Thats OK, we will just add the tiger actions later - we inherited the add_action from CatClass&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.add_action(&#039;scratch&#039;, &#039;roars&#039;)&lt;br /&gt;
tigger.add_action(&#039;feed&#039;, &#039;demands more meat&#039;)&lt;br /&gt;
# Testing&lt;br /&gt;
tigger.action(&#039;scare&#039;)&lt;br /&gt;
tigger.action(&#039;feed&#039;)&lt;br /&gt;
# All good, but what happened to our cat?&lt;br /&gt;
mycat.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The cat started roaring when scratched - that is a tiger action. Looking at the add_action class method, it is not specifying anywhere that the CatClass should be used so what is wrong? The problem is that the Tiger and the CatClass are &#039;&#039;sharing&#039;&#039; the class variables. The Tiger did not make new ones, so it is using the CatClass class variables, because CatClass is the parent class. Right now any changes in action made by the Tiger class is reflected in the CatClass and vice versa. The Tiger needs is own. Also did you notice that the Tiger&#039;s scientific name is Felis Catus, same as the cat - ridiculous.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Panthera&amp;quot;&lt;br /&gt;
    species = &amp;quot;Tigris&amp;quot;&lt;br /&gt;
    acts = CatClass.acts.copy()&lt;br /&gt;
    # Tiger class specials&lt;br /&gt;
    acts[&#039;scratch&#039;] = &#039;roars&#039;&lt;br /&gt;
    acts[&#039;feed&#039;} = &#039;demands more meat&#039;&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.action(&#039;scratch&#039;)&lt;br /&gt;
mycat.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Much better. Copy the mutable class variables from the base class and then change them so they fit.&lt;br /&gt;
&lt;br /&gt;
Life is good. Let&#039;s make some kittens.....&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
kitten1 = mycat + yourcat&lt;br /&gt;
print(kitten1.name)&lt;br /&gt;
&lt;br /&gt;
# Can we mate the cat and the tiger?&lt;br /&gt;
kitten2 = yourcat + tigger&lt;br /&gt;
kitten2.name = &amp;quot;Monstrous Mutant&amp;quot;&lt;br /&gt;
print(kitten2.name)&lt;br /&gt;
kitten2.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
That was unfortunate. We should not be able to breed a cat and a tiger, and if we did anyway, should the result be a cat (the kitten does a cat action)?&amp;lt;br&amp;gt;&lt;br /&gt;
The issue is in the &#039;&#039;__add__&#039;&#039; magic method. All that is required is that the two classes being &amp;quot;added&amp;quot; have a _gender instance variable.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Being biased and saying all kittens are male&lt;br /&gt;
        kitten = CatClass(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten&lt;br /&gt;
&lt;br /&gt;
    # Adding a class check - we must demand that we breed tigers with tigers and cats with cats&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        if type(self) != type(other):&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Still male kittens, making sure tigers begets tigers and cats begets cats&lt;br /&gt;
        kitten = type(self)(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten     &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are the two classes without any inheritance problems. I will leave it to you to do the testing. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class CatClass:&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Felis&amp;quot;&lt;br /&gt;
    species = &amp;quot;Catus&amp;quot;&lt;br /&gt;
    acts = {&#039;scratch&#039;: &amp;quot;purrs&amp;quot;,&lt;br /&gt;
            &#039;scare&#039;: &amp;quot;jumps high in the air&amp;quot;,&lt;br /&gt;
            &#039;feed&#039;: &amp;quot;is very excited&amp;quot; }&lt;br /&gt;
&lt;br /&gt;
    ### Instatiation&lt;br /&gt;
    def __init__(self, name, gender):&lt;br /&gt;
        self._name, self._gender = name, gender&lt;br /&gt;
&lt;br /&gt;
    ### Magic methods&lt;br /&gt;
    # Addition makes a kitten if male and female cat, alternative constructor&lt;br /&gt;
    # Adding a class check - we must demand that we breed tigers with tigers and cats with cats&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        if type(self) != type(other):&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Still male kittens, making sure tigers begets tigers and cats begets cats&lt;br /&gt;
        kitten = type(self)(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten&lt;br /&gt;
                &lt;br /&gt;
    ### Class methods&lt;br /&gt;
    # Adding a cat action&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def add_action(cls, action, reaction):&lt;br /&gt;
       cls.acts[action] = reaction&lt;br /&gt;
    # Querying class for number of actions&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def count_action(cls):&lt;br /&gt;
        return len(cls.acts)&lt;br /&gt;
&lt;br /&gt;
    ### Property methods&lt;br /&gt;
    # name setter and getter&lt;br /&gt;
    @property&lt;br /&gt;
    def name(self):&lt;br /&gt;
        if not hasattr(self, &#039;_name&#039;):&lt;br /&gt;
            raise NameError(&amp;quot;Name of cat is not yet set&amp;quot;)&lt;br /&gt;
        return self._name&lt;br /&gt;
        &lt;br /&gt;
    @name.setter&lt;br /&gt;
    def name(self, value):&lt;br /&gt;
        if value == &#039;&#039;:&lt;br /&gt;
            raise ValueError(&amp;quot;Name can not be nothing&amp;quot;)&lt;br /&gt;
        self._name = value&lt;br /&gt;
&lt;br /&gt;
    ### Instance methods&lt;br /&gt;
    # The action method - using class variables&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in self.acts:&lt;br /&gt;
            print(self._name, self.acts[act])&lt;br /&gt;
        elif self._gender == &#039;male&#039;:&lt;br /&gt;
            print(self._name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self._name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Panthera&amp;quot;&lt;br /&gt;
    species = &amp;quot;Tigris&amp;quot;&lt;br /&gt;
    acts = CatClass.acts.copy()&lt;br /&gt;
    # Tiger class specials&lt;br /&gt;
    acts[&#039;scratch&#039;] = &#039;roars&#039;&lt;br /&gt;
    acts[&#039;feed&#039;] = &#039;demands more meat&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
== Take home messages ==&lt;br /&gt;
* Even if you do not plan for your class to be inherited, make it so it can. That way it is less work later AND you remember how to do it.&lt;br /&gt;
* Don&#039;t hardcode class names in your class. Use &#039;&#039;type(self)&#039;&#039; to get the class.&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=280</id>
		<title>Example code - Inheritance issues</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=280"/>
		<updated>2026-03-19T18:42:10Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The challenges in inheritance can not be demonstrated well in a powerpoint.&lt;br /&gt;
Thus, I made this page with examples. You can copy the code in the section and add it together and run it.&lt;br /&gt;
&lt;br /&gt;
First I create a slightly bigger CatClass.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class CatClass:&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Felis&amp;quot;&lt;br /&gt;
    species = &amp;quot;Catus&amp;quot;&lt;br /&gt;
    acts = {&#039;scratch&#039;: &amp;quot;purrs&amp;quot;,&lt;br /&gt;
            &#039;scare&#039;: &amp;quot;jumps high in the air&amp;quot;,&lt;br /&gt;
            &#039;feed&#039;: &amp;quot;is very excited&amp;quot; }&lt;br /&gt;
&lt;br /&gt;
    ### Instatiation&lt;br /&gt;
    def __init__(self, name, gender):&lt;br /&gt;
        self._name, self._gender = name, gender&lt;br /&gt;
&lt;br /&gt;
    ### Magic methods&lt;br /&gt;
    # Addition makes a kitten if male and female cat, alternative constructor&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Being biased and saying all kittens are male&lt;br /&gt;
        kitten = CatClass(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten     &lt;br /&gt;
        &lt;br /&gt;
    ### Class methods&lt;br /&gt;
    # Adding a cat action&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def add_action(cls, action, reaction):&lt;br /&gt;
       cls.acts[action] = reaction&lt;br /&gt;
    # Querying class for number of actions&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def count_action(cls):&lt;br /&gt;
        return len(cls.acts)&lt;br /&gt;
&lt;br /&gt;
    ### Property methods&lt;br /&gt;
    # name setter and getter&lt;br /&gt;
    @property&lt;br /&gt;
    def name(self):&lt;br /&gt;
        if not hasattr(self, &#039;_name&#039;):&lt;br /&gt;
            raise NameError(&amp;quot;Name of cat is not yet set&amp;quot;)&lt;br /&gt;
        return self._name&lt;br /&gt;
        &lt;br /&gt;
    @name.setter&lt;br /&gt;
    def name(self, value):&lt;br /&gt;
        if value == &#039;&#039;:&lt;br /&gt;
            raise ValueError(&amp;quot;Name can not be nothing&amp;quot;)&lt;br /&gt;
        self._name = value&lt;br /&gt;
&lt;br /&gt;
    ### Instance methods&lt;br /&gt;
    # The action method - using class variables&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
        elif self._gender == &#039;male&#039;:&lt;br /&gt;
            print(self._name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self._name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
### Main program                    &lt;br /&gt;
yourcat = CatClass(&#039;Missy&#039;, &#039;female&#039;)&lt;br /&gt;
&lt;br /&gt;
CatClass.add_action(&amp;quot;annoy&amp;quot;, &amp;quot;scratches your face&amp;quot;)&lt;br /&gt;
print(&amp;quot;Actions in CatClass:&amp;quot;, CatClass.count_action())&lt;br /&gt;
&lt;br /&gt;
mycat = CatClass(&amp;quot;Tom&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
kitten = mycat + yourcat&lt;br /&gt;
&lt;br /&gt;
print(f&amp;quot;Kitten: {kitten.name}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
yourcat.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This class looks fine, but it has a number of inheritance issues.&lt;br /&gt;
By creating a Tiger class that inherits from the CatClass, I will demonstrate. Also, see how simple it was to create a new class based on an old :-)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts = {&lt;br /&gt;
        &#039;scratch&#039;: &#039;roars&#039;,&lt;br /&gt;
        &#039;feed&#039;: &#039;demands more meat&#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.action(&amp;quot;scratch&amp;quot;)&lt;br /&gt;
tigger.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We want the Tiger to react differently than the Cat, at least for some actions. However, this code does not do it. The problem lies in the inherited &#039;&#039;&#039;action&#039;&#039;&#039; method.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
        elif self._gender == &#039;male&#039;:&lt;br /&gt;
            print(self._name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self._name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    # We are specifically using the actions in the CatClass for the behavior&lt;br /&gt;
    # We need to use the current class, as in cats uses CatClass actions and tigers uses Tiger actions.&lt;br /&gt;
&lt;br /&gt;
    # These are the problematic lines, they can be replaced in different ways&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
    # Through &#039;&#039;&#039;self&#039;&#039;&#039;, as self will search the instance namespace and then the class namespace for the variable&lt;br /&gt;
        if act in self.acts:&lt;br /&gt;
            print(self._name, self.acts[act])&lt;br /&gt;
    # By dynamically getting the class by type&lt;br /&gt;
        cls = type(self)&lt;br /&gt;
        if act in cls.acts:&lt;br /&gt;
            print(self._name, cls.acts[act])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This does not completely solve the problem. We would still like to be able to scare the tiger (inherit the cat action), but for now it looks bored when we try. This problem is caused by the complete replacement of the class variable acts in the Tiger class. The cat actions are deleted and replaced with tiger-only actions.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts = {&lt;br /&gt;
        &#039;scratch&#039;: &#039;roars&#039;,&lt;br /&gt;
        &#039;feed&#039;: &#039;demands more meat&#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
# Thats OK, we will just add the tiger actions later - we inherited the add_action from CatClass&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.add_action(&#039;scratch&#039;, &#039;roars&#039;)&lt;br /&gt;
tigger.add_action(&#039;feed&#039;, &#039;demands more meat&#039;)&lt;br /&gt;
# Testing&lt;br /&gt;
tigger.action(&#039;scare&#039;)&lt;br /&gt;
tigger.action(&#039;feed&#039;)&lt;br /&gt;
# All good, but what happened to our cat?&lt;br /&gt;
mycat.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The cat started roaring when scratched - that is a tiger action. Looking at the add_action class method, it is not specifying anywhere that the CatClass should be used so what is wrong? The problem is that the Tiger and the CatClass are &#039;&#039;sharing&#039;&#039; the class variables. The Tiger did not make new ones, so it is using the CatClass class variables, because CatClass is the parent class. Right now any changes in action made by the Tiger class is reflected in the CatClass and vice versa. The Tiger needs is own. Also did you notice that the Tiger&#039;s scientific name is Felis Catus, same as the cat - ridiculous.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Panthera&amp;quot;&lt;br /&gt;
    species = &amp;quot;Tigris&amp;quot;&lt;br /&gt;
    acts = CatClass.acts.copy()&lt;br /&gt;
    # Tiger class specials&lt;br /&gt;
    acts[&#039;scratch&#039;] = &#039;roars&#039;&lt;br /&gt;
    acts[&#039;feed&#039;} = &#039;demands more meat&#039;&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.action(&#039;scratch&#039;)&lt;br /&gt;
mycat.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Much better. Copy the mutable class variables from the base class and then change them so they fit.&lt;br /&gt;
&lt;br /&gt;
Life is good. Let&#039;s make some kittens.....&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
kitten1 = mycat + yourcat&lt;br /&gt;
print(kitten1.name)&lt;br /&gt;
&lt;br /&gt;
# Can we mate the cat and the tiger?&lt;br /&gt;
kitten2 = yourcat + tigger&lt;br /&gt;
kitten2.name = &amp;quot;Monstrous Mutant&amp;quot;&lt;br /&gt;
print(kitten2.name)&lt;br /&gt;
kitten2.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
That was unfortunate. We should not be able to breed a cat and a tiger, and if we did anyway, should the result be a cat (the kitten does a cat action)?&amp;lt;br&amp;gt;&lt;br /&gt;
The issue is in the &#039;&#039;__add__&#039;&#039; magic method. All that is required is that the two classes being &amp;quot;added&amp;quot; have a _gender instance variable.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Being biased and saying all kittens are male&lt;br /&gt;
        kitten = CatClass(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten&lt;br /&gt;
&lt;br /&gt;
    # Adding a class check - we must demand that we breed tigers with tigers and cats with cats&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        if type(self) != type(other):&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Still male kittens, making sure tigers begets tigers and cats begets cats&lt;br /&gt;
        kitten = type(self)(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten     &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are the two classes without any inheritance problems. I will leave it to you to do the testing. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class CatClass:&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Felis&amp;quot;&lt;br /&gt;
    species = &amp;quot;Catus&amp;quot;&lt;br /&gt;
    acts = {&#039;scratch&#039;: &amp;quot;purrs&amp;quot;,&lt;br /&gt;
            &#039;scare&#039;: &amp;quot;jumps high in the air&amp;quot;,&lt;br /&gt;
            &#039;feed&#039;: &amp;quot;is very excited&amp;quot; }&lt;br /&gt;
&lt;br /&gt;
    ### Instatiation&lt;br /&gt;
    def __init__(self, name, gender):&lt;br /&gt;
        self._name, self._gender = name, gender&lt;br /&gt;
&lt;br /&gt;
    ### Magic methods&lt;br /&gt;
    # Addition makes a kitten if male and female cat, alternative constructor&lt;br /&gt;
    # Adding a class check - we must demand that we breed tigers with tigers and cats with cats&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        if type(self) != type(other):&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Still male kittens, making sure tigers begets tigers and cats begets cats&lt;br /&gt;
        kitten = type(self)(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten&lt;br /&gt;
                &lt;br /&gt;
    ### Class methods&lt;br /&gt;
    # Adding a cat action&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def add_action(cls, action, reaction):&lt;br /&gt;
       cls.acts[action] = reaction&lt;br /&gt;
    # Querying class for number of actions&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def count_action(cls):&lt;br /&gt;
        return len(cls.acts)&lt;br /&gt;
&lt;br /&gt;
    ### Property methods&lt;br /&gt;
    # name setter and getter&lt;br /&gt;
    @property&lt;br /&gt;
    def name(self):&lt;br /&gt;
        if not hasattr(self, &#039;_name&#039;):&lt;br /&gt;
            raise NameError(&amp;quot;Name of cat is not yet set&amp;quot;)&lt;br /&gt;
        return self._name&lt;br /&gt;
        &lt;br /&gt;
    @name.setter&lt;br /&gt;
    def name(self, value):&lt;br /&gt;
        if value == &#039;&#039;:&lt;br /&gt;
            raise ValueError(&amp;quot;Name can not be nothing&amp;quot;)&lt;br /&gt;
        self._name = value&lt;br /&gt;
&lt;br /&gt;
    ### Instance methods&lt;br /&gt;
    # The action method - using class variables&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in self.acts:&lt;br /&gt;
            print(self._name, self.acts[act])&lt;br /&gt;
        elif self._gender == &#039;male&#039;:&lt;br /&gt;
            print(self._name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self._name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Panthera&amp;quot;&lt;br /&gt;
    species = &amp;quot;Tigris&amp;quot;&lt;br /&gt;
    acts = CatClass.acts.copy()&lt;br /&gt;
    # Tiger class specials&lt;br /&gt;
    acts[&#039;scratch&#039;] = &#039;roars&#039;&lt;br /&gt;
    acts[&#039;feed&#039;] = &#039;demands more meat&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
== Take home messages&lt;br /&gt;
* Even if you do not plan for your class to be inherited, make it so it can. That way it is less work later AND you remember how to do it.&lt;br /&gt;
* Don&#039;t hardcode class names in your class. Use &#039;&#039;type(self)&#039;&#039; to get the class.&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=279</id>
		<title>Example code - Inheritance issues</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=279"/>
		<updated>2026-03-19T18:36:46Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The challenges in inheritance can not be demonstrated well in a powerpoint.&lt;br /&gt;
Thus, I made this page with examples. You can copy the code in the section and add it together and run it.&lt;br /&gt;
&lt;br /&gt;
First I create a slightly bigger CatClass.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class CatClass:&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Felis&amp;quot;&lt;br /&gt;
    species = &amp;quot;Catus&amp;quot;&lt;br /&gt;
    acts = {&#039;scratch&#039;: &amp;quot;purrs&amp;quot;,&lt;br /&gt;
            &#039;scare&#039;: &amp;quot;jumps high in the air&amp;quot;,&lt;br /&gt;
            &#039;feed&#039;: &amp;quot;is very excited&amp;quot; }&lt;br /&gt;
&lt;br /&gt;
    ### Instatiation&lt;br /&gt;
    def __init__(self, name, gender):&lt;br /&gt;
        self._name, self._gender = name, gender&lt;br /&gt;
&lt;br /&gt;
    ### Magic methods&lt;br /&gt;
    # Addition makes a kitten if male and female cat, alternative constructor&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Being biased and saying all kittens are male&lt;br /&gt;
        kitten = CatClass(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten     &lt;br /&gt;
        &lt;br /&gt;
    ### Class methods&lt;br /&gt;
    # Adding a cat action&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def add_action(cls, action, reaction):&lt;br /&gt;
       cls.acts[action] = reaction&lt;br /&gt;
    # Querying class for number of actions&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def count_action(cls):&lt;br /&gt;
        return len(cls.acts)&lt;br /&gt;
&lt;br /&gt;
    ### Property methods&lt;br /&gt;
    # name setter and getter&lt;br /&gt;
    @property&lt;br /&gt;
    def name(self):&lt;br /&gt;
        if not hasattr(self, &#039;_name&#039;):&lt;br /&gt;
            raise NameError(&amp;quot;Name of cat is not yet set&amp;quot;)&lt;br /&gt;
        return self._name&lt;br /&gt;
        &lt;br /&gt;
    @name.setter&lt;br /&gt;
    def name(self, value):&lt;br /&gt;
        if value == &#039;&#039;:&lt;br /&gt;
            raise ValueError(&amp;quot;Name can not be nothing&amp;quot;)&lt;br /&gt;
        self._name = value&lt;br /&gt;
&lt;br /&gt;
    ### Instance methods&lt;br /&gt;
    # The action method - using class variables&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
        elif self._gender == &#039;male&#039;:&lt;br /&gt;
            print(self._name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self._name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
### Main program                    &lt;br /&gt;
yourcat = CatClass(&#039;Missy&#039;, &#039;female&#039;)&lt;br /&gt;
&lt;br /&gt;
CatClass.add_action(&amp;quot;annoy&amp;quot;, &amp;quot;scratches your face&amp;quot;)&lt;br /&gt;
print(&amp;quot;Actions in CatClass:&amp;quot;, CatClass.count_action())&lt;br /&gt;
&lt;br /&gt;
mycat = CatClass(&amp;quot;Tom&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
kitten = mycat + yourcat&lt;br /&gt;
&lt;br /&gt;
print(f&amp;quot;Kitten: {kitten.name}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
yourcat.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This class looks fine, but it has a number of inheritance issues.&lt;br /&gt;
By creating a Tiger class that inherits from the CatClass, I will demonstrate. Also, see how simple it was to create a new class based on an old :-)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts = {&lt;br /&gt;
        &#039;scratch&#039;: &#039;roars&#039;,&lt;br /&gt;
        &#039;feed&#039;: &#039;demands more meat&#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.action(&amp;quot;scratch&amp;quot;)&lt;br /&gt;
tigger.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We want the Tiger to react differently than the Cat, at least for some actions. However, this code does not do it. The problem lies in the inherited &#039;&#039;&#039;action&#039;&#039;&#039; method.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
        elif self._gender == &#039;male&#039;:&lt;br /&gt;
            print(self._name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self._name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    # We are specifically using the actions in the CatClass for the behavior&lt;br /&gt;
    # We need to use the current class, as in cats uses CatClass actions and tigers uses Tiger actions.&lt;br /&gt;
&lt;br /&gt;
    # These are the problematic lines, they can be replaced in different ways&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
    # Through &#039;&#039;&#039;self&#039;&#039;&#039;, as self will search the instance namespace and then the class namespace for the variable&lt;br /&gt;
        if act in self.acts:&lt;br /&gt;
            print(self._name, self.acts[act])&lt;br /&gt;
    # By dynamically getting the class by type&lt;br /&gt;
        cls = type(self)&lt;br /&gt;
        if act in cls.acts:&lt;br /&gt;
            print(self._name, cls.acts[act])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This does not completely solve the problem. We would still like to be able to scare the tiger (inherit the cat action), but for now it looks bored when we try. This problem is caused by the complete replacement of the class variable acts in the Tiger class. The cat actions are deleted and replaced with tiger-only actions.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts = {&lt;br /&gt;
        &#039;scratch&#039;: &#039;roars&#039;,&lt;br /&gt;
        &#039;feed&#039;: &#039;demands more meat&#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
# Thats OK, we will just add the tiger actions later - we inherited the add_action from CatClass&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.add_action(&#039;scratch&#039;, &#039;roars&#039;)&lt;br /&gt;
tigger.add_action(&#039;feed&#039;, &#039;demands more meat&#039;)&lt;br /&gt;
# Testing&lt;br /&gt;
tigger.action(&#039;scare&#039;)&lt;br /&gt;
tigger.action(&#039;feed&#039;)&lt;br /&gt;
# All good, but what happened to our cat?&lt;br /&gt;
mycat.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The cat started roaring when scratched - that is a tiger action. Looking at the add_action class method, it is not specifying anywhere that the CatClass should be used so what is wrong? The problem is that the Tiger and the CatClass are &#039;&#039;sharing&#039;&#039; the class variables. The Tiger did not make new ones, so it is using the CatClass class variables, because CatClass is the parent class. Right now any changes in action made by the Tiger class is reflected in the CatClass and vice versa. The Tiger needs is own. Also did you notice that the Tiger&#039;s scientific name is Felis Catus, same as the cat - ridiculous.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Panthera&amp;quot;&lt;br /&gt;
    species = &amp;quot;Tigris&amp;quot;&lt;br /&gt;
    acts = CatClass.acts.copy()&lt;br /&gt;
    # Tiger class specials&lt;br /&gt;
    acts[&#039;scratch&#039;] = &#039;roars&#039;&lt;br /&gt;
    acts[&#039;feed&#039;} = &#039;demands more meat&#039;&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.action(&#039;scratch&#039;)&lt;br /&gt;
mycat.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Much better. Copy the mutable class variables from the base class and then change them so they fit.&lt;br /&gt;
&lt;br /&gt;
Life is good. Let&#039;s make some kittens.....&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
kitten1 = mycat + yourcat&lt;br /&gt;
print(kitten1.name)&lt;br /&gt;
&lt;br /&gt;
# Can we mate the cat and the tiger?&lt;br /&gt;
kitten2 = yourcat + tigger&lt;br /&gt;
kitten2.name = &amp;quot;Monstrous Mutant&amp;quot;&lt;br /&gt;
print(kitten2.name)&lt;br /&gt;
kitten2.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
That was unfortunate. We should not be able to breed a cat and a tiger, and if we did anyway, should the result be a cat (the kitten does a cat action)?&amp;lt;br&amp;gt;&lt;br /&gt;
The issue is in the &#039;&#039;__add__&#039;&#039; magic method. All the is required is that the two classes being &amp;quot;added&amp;quot; have a _gender instance variable.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Being biased and saying all kittens are male&lt;br /&gt;
        kitten = CatClass(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten&lt;br /&gt;
&lt;br /&gt;
    # Adding a class check - we must demand that we breed tigers with tigers and cats with cats&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        if type(self) != type(other):&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Still male kittens, making sure tigers begets tigers and cats begets cats&lt;br /&gt;
        kitten = type(self)(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten     &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here are the two classes without any inheritance problems. I will leave it to you to do the testing. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class CatClass:&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Felis&amp;quot;&lt;br /&gt;
    species = &amp;quot;Catus&amp;quot;&lt;br /&gt;
    acts = {&#039;scratch&#039;: &amp;quot;purrs&amp;quot;,&lt;br /&gt;
            &#039;scare&#039;: &amp;quot;jumps high in the air&amp;quot;,&lt;br /&gt;
            &#039;feed&#039;: &amp;quot;is very excited&amp;quot; }&lt;br /&gt;
&lt;br /&gt;
    ### Instatiation&lt;br /&gt;
    def __init__(self, name, gender):&lt;br /&gt;
        self._name, self._gender = name, gender&lt;br /&gt;
&lt;br /&gt;
    ### Magic methods&lt;br /&gt;
    # Addition makes a kitten if male and female cat, alternative constructor&lt;br /&gt;
    # Adding a class check - we must demand that we breed tigers with tigers and cats with cats&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        if type(self) != type(other):&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Still male kittens, making sure tigers begets tigers and cats begets cats&lt;br /&gt;
        kitten = type(self)(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten&lt;br /&gt;
                &lt;br /&gt;
    ### Class methods&lt;br /&gt;
    # Adding a cat action&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def add_action(cls, action, reaction):&lt;br /&gt;
       cls.acts[action] = reaction&lt;br /&gt;
    # Querying class for number of actions&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def count_action(cls):&lt;br /&gt;
        return len(cls.acts)&lt;br /&gt;
&lt;br /&gt;
    ### Property methods&lt;br /&gt;
    # name setter and getter&lt;br /&gt;
    @property&lt;br /&gt;
    def name(self):&lt;br /&gt;
        if not hasattr(self, &#039;_name&#039;):&lt;br /&gt;
            raise NameError(&amp;quot;Name of cat is not yet set&amp;quot;)&lt;br /&gt;
        return self._name&lt;br /&gt;
        &lt;br /&gt;
    @name.setter&lt;br /&gt;
    def name(self, value):&lt;br /&gt;
        if value == &#039;&#039;:&lt;br /&gt;
            raise ValueError(&amp;quot;Name can not be nothing&amp;quot;)&lt;br /&gt;
        self._name = value&lt;br /&gt;
&lt;br /&gt;
    ### Instance methods&lt;br /&gt;
    # The action method - using class variables&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in self.acts:&lt;br /&gt;
            print(self._name, self.acts[act])&lt;br /&gt;
        elif self._gender == &#039;male&#039;:&lt;br /&gt;
            print(self._name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self._name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Panthera&amp;quot;&lt;br /&gt;
    species = &amp;quot;Tigris&amp;quot;&lt;br /&gt;
    acts = CatClass.acts.copy()&lt;br /&gt;
    # Tiger class specials&lt;br /&gt;
    acts[&#039;scratch&#039;] = &#039;roars&#039;&lt;br /&gt;
    acts[&#039;feed&#039;] = &#039;demands more meat&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=278</id>
		<title>Example code - Inheritance issues</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=278"/>
		<updated>2026-03-19T18:19:06Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The challenges in inheritance can not be demonstrated well in a powerpoint.&lt;br /&gt;
Thus, I made this page with examples. You can copy the code in the section and add it together and run it.&lt;br /&gt;
&lt;br /&gt;
First I create a slightly bigger CatClass.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class CatClass:&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Felis&amp;quot;&lt;br /&gt;
    species = &amp;quot;Catus&amp;quot;&lt;br /&gt;
    acts = {&#039;scratch&#039;: &amp;quot;purrs&amp;quot;,&lt;br /&gt;
            &#039;scare&#039;: &amp;quot;jumps high in the air&amp;quot;,&lt;br /&gt;
            &#039;feed&#039;: &amp;quot;is very excited&amp;quot; }&lt;br /&gt;
&lt;br /&gt;
    ### Instatiation&lt;br /&gt;
    def __init__(self, name, gender):&lt;br /&gt;
        self._name, self._gender = name, gender&lt;br /&gt;
&lt;br /&gt;
    ### Magic methods&lt;br /&gt;
    # Addition makes a kitten if male and female cat, alternative constructor&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Being biased and saying all kittens are male&lt;br /&gt;
        kitten = CatClass(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten     &lt;br /&gt;
        &lt;br /&gt;
    ### Class methods&lt;br /&gt;
    # Adding a cat action&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def add_action(cls, action, reaction):&lt;br /&gt;
       cls.acts[action] = reaction&lt;br /&gt;
    # Querying class for number of actions&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def count_action(cls):&lt;br /&gt;
        return len(cls.acts)&lt;br /&gt;
&lt;br /&gt;
    ### Property methods&lt;br /&gt;
    # name setter and getter&lt;br /&gt;
    @property&lt;br /&gt;
    def name(self):&lt;br /&gt;
        if not hasattr(self, &#039;_name&#039;):&lt;br /&gt;
            raise NameError(&amp;quot;Name of cat is not yet set&amp;quot;)&lt;br /&gt;
        return self._name&lt;br /&gt;
        &lt;br /&gt;
    @name.setter&lt;br /&gt;
    def name(self, value):&lt;br /&gt;
        if value == &#039;&#039;:&lt;br /&gt;
            raise ValueError(&amp;quot;Name can not be nothing&amp;quot;)&lt;br /&gt;
        self._name = value&lt;br /&gt;
&lt;br /&gt;
    ### Instance methods&lt;br /&gt;
    # The action method - using class variables&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
        elif self._gender == &#039;male&#039;:&lt;br /&gt;
            print(self._name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self._name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
### Main program                    &lt;br /&gt;
yourcat = CatClass(&#039;Missy&#039;, &#039;female&#039;)&lt;br /&gt;
&lt;br /&gt;
CatClass.add_action(&amp;quot;annoy&amp;quot;, &amp;quot;scratches your face&amp;quot;)&lt;br /&gt;
print(&amp;quot;Actions in CatClass:&amp;quot;, CatClass.count_action())&lt;br /&gt;
&lt;br /&gt;
mycat = CatClass(&amp;quot;Tom&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
kitten = mycat + yourcat&lt;br /&gt;
&lt;br /&gt;
print(f&amp;quot;Kitten: {kitten.name}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
yourcat.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This class looks fine, but it has a number of inheritance issues.&lt;br /&gt;
By creating a Tiger class that inherits from the CatClass, I will demonstrate. Also, see how simple it was to create a new class based on an old :-)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts = {&lt;br /&gt;
        &#039;scratch&#039;: &#039;roars&#039;,&lt;br /&gt;
        &#039;feed&#039;: &#039;demands more meat&#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.action(&amp;quot;scratch&amp;quot;)&lt;br /&gt;
tigger.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We want the Tiger to react differently than the Cat, at least for some actions. However, this code does not do it. The problem lies in the inherited &#039;&#039;&#039;action&#039;&#039;&#039; method.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
        elif self._gender == &#039;male&#039;:&lt;br /&gt;
            print(self._name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self._name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    # We are specifically using the actions in the CatClass for the behavior&lt;br /&gt;
    # We need to use the current class, as in cats uses CatClass actions and tigers uses Tiger actions.&lt;br /&gt;
&lt;br /&gt;
    # These are the problematic lines, they can be replaced in different ways&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
    # Through &#039;&#039;&#039;self&#039;&#039;&#039;, as self will search the instance namespace and then the class namespace for the variable&lt;br /&gt;
        if act in self.acts:&lt;br /&gt;
            print(self._name, self.acts[act])&lt;br /&gt;
    # By dynamically getting the class by type&lt;br /&gt;
        cls = type(self)&lt;br /&gt;
        if act in cls.acts:&lt;br /&gt;
            print(self._name, cls.acts[act])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This does not completely solve the problem. We would still like to be able to scare the tiger (inherit the cat action), but for now it looks bored when we try. This problem is caused by the complete replacement of the class variable acts in the Tiger class. The cat actions are deleted and replaced with tiger-only actions.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts = {&lt;br /&gt;
        &#039;scratch&#039;: &#039;roars&#039;,&lt;br /&gt;
        &#039;feed&#039;: &#039;demands more meat&#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
# Thats OK, we will just add the tiger actions later - we inherited the add_action from CatClass&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.add_action(&#039;scratch&#039;, &#039;roars&#039;)&lt;br /&gt;
tigger.add_action(&#039;feed&#039;, &#039;demands more meat&#039;)&lt;br /&gt;
# Testing&lt;br /&gt;
tigger.action(&#039;scare&#039;)&lt;br /&gt;
tigger.action(&#039;feed&#039;)&lt;br /&gt;
# All good, but what happened to our cat?&lt;br /&gt;
mycat.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The cat started roaring when scratched - that is a tiger action. Looking at the add_action class method, it is not specifying anywhere that the CatClass should be used so what is wrong? The problem is that the Tiger and the CatClass are &#039;&#039;sharing&#039;&#039; the class variables. The Tiger did not make new ones, so it is using the CatClass class variables, because CatClass is the parent class. Right now any changes in action made by the Tiger class is reflected in the CatClass and vice versa. The Tiger needs is own. Also did you notice that the Tiger&#039;s scientific name is Felis Catus, same as the cat - ridiculous.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Panthera&amp;quot;&lt;br /&gt;
    species = &amp;quot;Tigris&amp;quot;&lt;br /&gt;
    acts = CatClass.acts.copy()&lt;br /&gt;
    # Tiger class specials&lt;br /&gt;
    acts[&#039;scratch&#039;] = &#039;roars&#039;&lt;br /&gt;
    acts[&#039;feed&#039;} = &#039;demands more meat&#039;&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.action(&#039;scratch&#039;)&lt;br /&gt;
mycat.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Much better. Copy the mutable class variables from the base class and then change them so they fit.&lt;br /&gt;
&lt;br /&gt;
Life is good. Let&#039;s make some kittens.....&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
kitten1 = mycat + yourcat&lt;br /&gt;
print(kitten1.name)&lt;br /&gt;
&lt;br /&gt;
# Can we mate the cat and the tiger?&lt;br /&gt;
kitten2 = yourcat + tigger&lt;br /&gt;
kitten2.name = &amp;quot;Monstrous Mutant&amp;quot;&lt;br /&gt;
print(kitten2.name)&lt;br /&gt;
kitten2.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
That was unfortunate. We should not be able to breed a cat and a tiger, and if we did anyway, should the result be a cat (the kitten does a cat action)?&amp;lt;br&amp;gt;&lt;br /&gt;
The issue is in the &#039;&#039;__add__&#039;&#039; magic method. All the is required is that the two classes being &amp;quot;added&amp;quot; have a _gender instance variable.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Being biased and saying all kittens are male&lt;br /&gt;
        kitten = CatClass(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten&lt;br /&gt;
&lt;br /&gt;
    # Adding a class check - we must demand that we breed tigers with tigers and cats with cats&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        if type(self) != type(other):&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Still male kittens, making sure tigers begets tigers and cats begets cats&lt;br /&gt;
        kitten = type(self)(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten     &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=277</id>
		<title>Example code - Inheritance issues</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=277"/>
		<updated>2026-03-19T17:48:08Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The challenges in inheritance can not be demonstrated well in a powerpoint.&lt;br /&gt;
Thus, I made this page with examples. You can copy the code in the section and add it together and run it.&lt;br /&gt;
&lt;br /&gt;
First I create a slightly bigger CatClass.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class CatClass:&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Felis&amp;quot;&lt;br /&gt;
    species = &amp;quot;Catus&amp;quot;&lt;br /&gt;
    acts = {&#039;scratch&#039;: &amp;quot;purrs&amp;quot;,&lt;br /&gt;
            &#039;scare&#039;: &amp;quot;jumps high in the air&amp;quot;,&lt;br /&gt;
            &#039;feed&#039;: &amp;quot;is very excited&amp;quot; }&lt;br /&gt;
&lt;br /&gt;
    ### Instatiation&lt;br /&gt;
    def __init__(self, name, gender):&lt;br /&gt;
        self._name, self._gender = name, gender&lt;br /&gt;
&lt;br /&gt;
    ### Magic methods&lt;br /&gt;
    # Addition makes a kitten if male and female cat, alternative constructor&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Being biased and saying all kittens are male&lt;br /&gt;
        kitten = CatClass(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten     &lt;br /&gt;
        &lt;br /&gt;
    ### Class methods&lt;br /&gt;
    # Adding a cat action&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def add_action(cls, action, reaction):&lt;br /&gt;
       cls.acts[action] = reaction&lt;br /&gt;
    # Querying class for number of actions&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def count_action(cls):&lt;br /&gt;
        return len(cls.acts)&lt;br /&gt;
&lt;br /&gt;
    ### Property methods&lt;br /&gt;
    # name setter and getter&lt;br /&gt;
    @property&lt;br /&gt;
    def name(self):&lt;br /&gt;
        if not hasattr(self, &#039;_name&#039;):&lt;br /&gt;
            raise NameError(&amp;quot;Name of cat is not yet set&amp;quot;)&lt;br /&gt;
        return self._name&lt;br /&gt;
        &lt;br /&gt;
    @name.setter&lt;br /&gt;
    def name(self, value):&lt;br /&gt;
        if value == &#039;&#039;:&lt;br /&gt;
            raise ValueError(&amp;quot;Name can not be nothing&amp;quot;)&lt;br /&gt;
        self._name = value&lt;br /&gt;
&lt;br /&gt;
    ### Instance methods&lt;br /&gt;
    # The action method - using class variables&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
        elif self._gender == &#039;male&#039;:&lt;br /&gt;
            print(self._name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self._name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
### Main program                    &lt;br /&gt;
yourcat = CatClass(&#039;Missy&#039;, &#039;female&#039;)&lt;br /&gt;
&lt;br /&gt;
CatClass.add_action(&amp;quot;annoy&amp;quot;, &amp;quot;scratches your face&amp;quot;)&lt;br /&gt;
print(&amp;quot;Actions in CatClass:&amp;quot;, CatClass.count_action())&lt;br /&gt;
&lt;br /&gt;
mycat = CatClass(&amp;quot;Tom&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
kitten = mycat + yourcat&lt;br /&gt;
&lt;br /&gt;
print(f&amp;quot;Kitten: {kitten.name}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
yourcat.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This class looks fine, but it has a number of inheritance issues.&lt;br /&gt;
By creating a Tiger class that inherits from the CatClass, I will demonstrate. Also, see how simple it was to create a new class based on an old :-)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts = {&lt;br /&gt;
        &#039;scratch&#039;: &#039;roars&#039;,&lt;br /&gt;
        &#039;feed&#039;: &#039;demands more meat&#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.action(&amp;quot;scratch&amp;quot;)&lt;br /&gt;
tigger.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We want the Tiger to react differently than the Cat, at least for some actions. However, this code does not do it. The problem lies in the inherited &#039;&#039;&#039;action&#039;&#039;&#039; method.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
        elif self._gender == &#039;male&#039;:&lt;br /&gt;
            print(self._name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self._name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    # We are specifically using the actions in the CatClass for the behavior&lt;br /&gt;
    # We need to use the current class, as in cats uses CatClass actions and tigers uses Tiger actions.&lt;br /&gt;
&lt;br /&gt;
    # These are the problematic lines, they can be replaced in different ways&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
    # Through &#039;&#039;&#039;self&#039;&#039;&#039;, as self will search the instance namespace and then the class namespace for the variable&lt;br /&gt;
        if act in self.acts:&lt;br /&gt;
            print(self._name, self.acts[act])&lt;br /&gt;
    # By dynamically getting the class by type&lt;br /&gt;
        cls = type(self)&lt;br /&gt;
        if act in cls.acts:&lt;br /&gt;
            print(self._name, cls.acts[act])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This does not completely solve the problem. We would still like to be able to scare the tiger (inherit the cat action), but for now it looks bored when we try. This problem is caused by the complete replacement of the class variable acts in the Tiger class. The cat actions are deleted and replaced with tiger-only actions.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts = {&lt;br /&gt;
        &#039;scratch&#039;: &#039;roars&#039;,&lt;br /&gt;
        &#039;feed&#039;: &#039;demands more meat&#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
# Thats OK, we will just add the tiger actions later - we inherited the add_action from CatClass&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.add_action(&#039;scratch&#039;, &#039;roars&#039;)&lt;br /&gt;
tigger.add_action(&#039;feed&#039;, &#039;demands more meat&#039;)&lt;br /&gt;
# Testing&lt;br /&gt;
tigger.action(&#039;scare&#039;)&lt;br /&gt;
tigger.action(&#039;feed&#039;)&lt;br /&gt;
# All good, but what happened to our cat?&lt;br /&gt;
mycat.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The cat started roaring when scratched - that is a tiger action. Looking at the add_action class method, it is not specifying anywhere that the CatClass should be used so what is wrong? The problem is that the Tiger and the CatClass are &#039;&#039;sharing&#039;&#039; the class variables. The Tiger did not make new ones, so it is using the CatClass class variables, because CatClass is the parent class. Right now any changes in action made by the Tiger class is reflected in the CatClass and vice versa. The Tiger needs is own. Also did you notice that the Tiger&#039;s scientific name is Felis Catus, same as the cat - ridiculous.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Panthera&amp;quot;&lt;br /&gt;
    species = &amp;quot;Tigris&amp;quot;&lt;br /&gt;
    acts = CatClass.acts.copy()&lt;br /&gt;
    # Tiger class specials&lt;br /&gt;
    acts[&#039;scratch&#039;] = &#039;roars&#039;&lt;br /&gt;
    acts[&#039;feed&#039;} = &#039;demands more meat&#039;&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.action(&#039;scratch&#039;)&lt;br /&gt;
mycat.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Much better. Copy the mutable class variables from the base class and then change them so they fit.&lt;br /&gt;
&lt;br /&gt;
Life is good. Let&#039;s make some kittens.....&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
kitten1 = mycat + yourcat&lt;br /&gt;
print(kitten1.name)&lt;br /&gt;
&lt;br /&gt;
# Can we mate the cat and the tiger?&lt;br /&gt;
kitten2 = yourcat + tigger&lt;br /&gt;
kitten2.name = &amp;quot;Monstrous Mutant&amp;quot;&lt;br /&gt;
print(kitten2.name)&lt;br /&gt;
kitten2.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
That was unfortunate. We should not be able to breed a cat and a tiger, and if we did anyway, should the result be a cat (the kitten does a cat action)?&amp;lt;br&amp;gt;&lt;br /&gt;
The issue is in the &#039;&#039;__add__&#039;&#039; magic method. All the is required is that the two classes being &amp;quot;added&amp;quot; have a _gender instance variable.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Being biased and saying all kittens are male&lt;br /&gt;
        kitten = CatClass(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten&lt;br /&gt;
&lt;br /&gt;
    # Adding a class check - we must demand that we breed tigers with tigers and cats with cats&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        if type(self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Being biased and saying all kittens are male&lt;br /&gt;
        kitten = CatClass(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten     &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=276</id>
		<title>Example code - Inheritance issues</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=276"/>
		<updated>2026-03-19T17:30:57Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The challenges in inheritance can not be demonstrated well in a powerpoint.&lt;br /&gt;
Thus, I made this page with examples. You can copy the code in the section and add it together and run it.&lt;br /&gt;
&lt;br /&gt;
First I create a slightly bigger CatClass.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class CatClass:&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Felis&amp;quot;&lt;br /&gt;
    species = &amp;quot;Catus&amp;quot;&lt;br /&gt;
    acts = {&#039;scratch&#039;: &amp;quot;purrs&amp;quot;,&lt;br /&gt;
            &#039;scare&#039;: &amp;quot;jumps high in the air&amp;quot;,&lt;br /&gt;
            &#039;feed&#039;: &amp;quot;is very excited&amp;quot; }&lt;br /&gt;
&lt;br /&gt;
    ### Instatiation&lt;br /&gt;
    def __init__(self, name, gender):&lt;br /&gt;
        self._name, self._gender = name, gender&lt;br /&gt;
&lt;br /&gt;
    ### Magic methods&lt;br /&gt;
    # Addition makes a kitten if male and female cat, alternative constructor&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self._gender == other._gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Being biased and saying all kittens are male&lt;br /&gt;
        kitten = CatClass(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten     &lt;br /&gt;
        &lt;br /&gt;
    ### Class methods&lt;br /&gt;
    # Adding a cat action&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def add_action(cls, action, reaction):&lt;br /&gt;
       cls.acts[action] = reaction&lt;br /&gt;
    # Querying class for number of actions&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def count_action(cls):&lt;br /&gt;
        return len(cls.acts)&lt;br /&gt;
&lt;br /&gt;
    ### Property methods&lt;br /&gt;
    # name setter and getter&lt;br /&gt;
    @property&lt;br /&gt;
    def name(self):&lt;br /&gt;
        if not hasattr(self, &#039;_name&#039;):&lt;br /&gt;
            raise NameError(&amp;quot;Name of cat is not yet set&amp;quot;)&lt;br /&gt;
        return self._name&lt;br /&gt;
        &lt;br /&gt;
    @name.setter&lt;br /&gt;
    def name(self, value):&lt;br /&gt;
        if value == &#039;&#039;:&lt;br /&gt;
            raise ValueError(&amp;quot;Name can not be nothing&amp;quot;)&lt;br /&gt;
        self._name = value&lt;br /&gt;
&lt;br /&gt;
    ### Instance methods&lt;br /&gt;
    # The action method - using class variables&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
        elif self._gender == &#039;male&#039;:&lt;br /&gt;
            print(self._name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self._name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
### Main program                    &lt;br /&gt;
yourcat = CatClass(&#039;Missy&#039;, &#039;female&#039;)&lt;br /&gt;
&lt;br /&gt;
CatClass.add_action(&amp;quot;annoy&amp;quot;, &amp;quot;scratches your face&amp;quot;)&lt;br /&gt;
print(&amp;quot;Actions in CatClass:&amp;quot;, CatClass.count_action())&lt;br /&gt;
&lt;br /&gt;
mycat = CatClass(&amp;quot;Tom&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
kitten = mycat + yourcat&lt;br /&gt;
&lt;br /&gt;
print(f&amp;quot;Kitten: {kitten.name}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
yourcat.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This class looks fine, but it has a number of inheritance issues.&lt;br /&gt;
By creating a Tiger class that inherits from the CatClass, I will demonstrate. Also, see how simple it was to create a new class based on an old :-)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts = {&lt;br /&gt;
        &#039;scratch&#039;: &#039;roars&#039;,&lt;br /&gt;
        &#039;feed&#039;: &#039;demands more meat&#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.action(&amp;quot;scratch&amp;quot;)&lt;br /&gt;
tigger.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We want the Tiger to react differently than the Cat, at least for some actions. However, this code does not do it. The problem lies in the inherited &#039;&#039;&#039;action&#039;&#039;&#039; method.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
        elif self._gender == &#039;male&#039;:&lt;br /&gt;
            print(self._name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self._name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    # We are specifically using the actions in the CatClass for the behavior&lt;br /&gt;
    # We need to use the current class, as in cats uses CatClass actions and tigers uses Tiger actions.&lt;br /&gt;
&lt;br /&gt;
    # These are the problematic lines, they can be replaced in different ways&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self._name, CatClass.acts[act])&lt;br /&gt;
    # Through &#039;&#039;&#039;self&#039;&#039;&#039;, as self will search the instance namespace and then the class namespace for the variable&lt;br /&gt;
        if act in self.acts:&lt;br /&gt;
            print(self._name, self.acts[act])&lt;br /&gt;
    # By dynamically getting the class by type&lt;br /&gt;
        cls = type(self)&lt;br /&gt;
        if act in cls.acts:&lt;br /&gt;
            print(self._name, cls.acts[act])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This does not completely solve the problem. We would still like to be able to scare the tiger (inherit the cat action), but for now it looks bored when we try. This problem is caused by the complete replacement of the class variable acts in the Tiger class. The cat actions are deleted and replaced with tiger-only actions.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts = {&lt;br /&gt;
        &#039;scratch&#039;: &#039;roars&#039;,&lt;br /&gt;
        &#039;feed&#039;: &#039;demands more meat&#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
# Thats OK, we will just add the tiger actions later - we inherited the add_action from CatClass&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.add_action(&#039;scratch&#039;, &#039;roars&#039;)&lt;br /&gt;
tigger.add_action(&#039;feed&#039;, &#039;demands more meat&#039;)&lt;br /&gt;
# Testing&lt;br /&gt;
tigger.action(&#039;scare&#039;)&lt;br /&gt;
tigger.action(&#039;feed&#039;)&lt;br /&gt;
# All good, but what happened to our cat?&lt;br /&gt;
mycat.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The cat started roaring when scratched - that is a tiger action. Looking at the add_action class method, it is not specifying anywhere that the CatClass should be used so what is wrong? The problem is that the Tiger and the CatClass are &#039;&#039;sharing&#039;&#039; the class variables. The Tiger did not make new ones, so it is using the CatClass class variables, because CatClass is the parent class. Right now any changes in action made by the Tiger class is reflected in the CatClass and vice versa. The Tiger needs is own. Also did you notice that the Tiger&#039;s scientific name is Felis Catus, same as the cat - ridiculous.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Panthera&amp;quot;&lt;br /&gt;
    species = &amp;quot;Tigris&amp;quot;&lt;br /&gt;
    acts = CatClass.acts.copy()&lt;br /&gt;
    # Tiger class specials&lt;br /&gt;
    acts[&#039;scratch&#039;] = &#039;roars&#039;&lt;br /&gt;
    acts[&#039;feed&#039;} = &#039;demands more meat&#039;&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.action(&#039;scratch&#039;)&lt;br /&gt;
mycat.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Much better. Copy the mutable class variables from the base class and then change them so they fit.&lt;br /&gt;
&lt;br /&gt;
Life is good. Let&#039;s make some kittens.....&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
kitten1 = mycat + yourcat&lt;br /&gt;
print(kitten1.name)&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=275</id>
		<title>Example code - Inheritance issues</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=275"/>
		<updated>2026-03-19T17:05:24Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The challenges in inheritance can not be demonstrated well in a powerpoint.&lt;br /&gt;
Thus, I made this page with examples. You can copy the code in the section and add it together and run it.&lt;br /&gt;
&lt;br /&gt;
First I create a slightly bigger CatClass.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class CatClass:&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Felis&amp;quot;&lt;br /&gt;
    species = &amp;quot;Catus&amp;quot;&lt;br /&gt;
    acts = {&#039;scratch&#039;: &amp;quot;purrs&amp;quot;,&lt;br /&gt;
            &#039;scare&#039;: &amp;quot;jumps high in the air&amp;quot;,&lt;br /&gt;
            &#039;feed&#039;: &amp;quot;is very excited&amp;quot; }&lt;br /&gt;
&lt;br /&gt;
    ### Instatiation&lt;br /&gt;
    def __init__(self, name, gender):&lt;br /&gt;
        self.name, self.gender = name, gender&lt;br /&gt;
&lt;br /&gt;
    ### Magic methods&lt;br /&gt;
    # Addition makes a kitten if male and female cat, alternative constructor&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self.gender == other.gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Being biased and saying all kittens are male&lt;br /&gt;
        kitten = CatClass(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten     &lt;br /&gt;
        &lt;br /&gt;
    ### Class methods&lt;br /&gt;
    # Adding a cat action&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def add_action(cls, action, reaction):&lt;br /&gt;
       cls.acts[action] = reaction&lt;br /&gt;
    # Querying class for number of actions&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def count_action(cls):&lt;br /&gt;
        return len(cls.acts)&lt;br /&gt;
&lt;br /&gt;
    ### Property methods&lt;br /&gt;
    # age setter and getter&lt;br /&gt;
    @property&lt;br /&gt;
    def age(self):&lt;br /&gt;
        if not hasattr(self, &#039;_age&#039;):&lt;br /&gt;
            raise NameError(&amp;quot;Age of cat is not yet set&amp;quot;)&lt;br /&gt;
        return self._age&lt;br /&gt;
        &lt;br /&gt;
    @age.setter&lt;br /&gt;
    def age(self, value):&lt;br /&gt;
        if value &amp;lt; 0:&lt;br /&gt;
            raise ValueError(&amp;quot;Age can not be negative&amp;quot;)&lt;br /&gt;
        self._age = value&lt;br /&gt;
&lt;br /&gt;
    ### Instance methods&lt;br /&gt;
    # The action method - using class variables&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self.name, CatClass.acts[act])&lt;br /&gt;
        elif self.gender == &#039;male&#039;:&lt;br /&gt;
            print(self.name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self.name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
### Main program                    &lt;br /&gt;
yourcat = CatClass(&#039;Missy&#039;, &#039;female&#039;)&lt;br /&gt;
yourcat.age = 5&lt;br /&gt;
print(f&amp;quot;The age of your cat is {yourcat.age}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
CatClass.add_action(&amp;quot;annoy&amp;quot;, &amp;quot;scratches your face&amp;quot;)&lt;br /&gt;
print(&amp;quot;Actions in CatClass:&amp;quot;, CatClass.count_action())&lt;br /&gt;
&lt;br /&gt;
mycat = CatClass(&amp;quot;Tom&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
kitten = mycat + yourcat&lt;br /&gt;
&lt;br /&gt;
print(f&amp;quot;Kitten: {kitten.name}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
yourcat.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This class looks fine, but it has a number of inheritance issues.&lt;br /&gt;
By creating a Tiger class that inherits from the CatClass, I will demonstrate. Also, see how simple it was to create a new class based on an old :-)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts = {&lt;br /&gt;
        &#039;scratch&#039;: &#039;roars&#039;,&lt;br /&gt;
        &#039;feed&#039;: &#039;demands more meat&#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.action(&amp;quot;scratch&amp;quot;)&lt;br /&gt;
tigger.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We want the Tiger to react differently than the Cat, at least for some actions. However, this code does not do it. The problem lies in the inherited &#039;&#039;&#039;action&#039;&#039;&#039; method.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self.name, CatClass.acts[act])&lt;br /&gt;
        elif self.gender == &#039;male&#039;:&lt;br /&gt;
            print(self.name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self.name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    # We are specifically using the actions in the CatClass for the behavior&lt;br /&gt;
    # We need to use the current class, as in cats uses CatClass actions and tigers uses Tiger actions.&lt;br /&gt;
&lt;br /&gt;
    # These are the problematic lines, they can be replaced in different ways&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self.name, CatClass.acts[act])&lt;br /&gt;
    # Through &#039;&#039;&#039;self&#039;&#039;&#039;, as self will search the instance namespace and then the class namespace for the variable&lt;br /&gt;
        if act in self.acts:&lt;br /&gt;
            print(self.name, self.acts[act])&lt;br /&gt;
    # By dynamically getting the class by type&lt;br /&gt;
        cls = type(self)&lt;br /&gt;
        if act in cls.acts:&lt;br /&gt;
            print(self.name, cls.acts[act])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This does not completely solve the problem. We would still like to be able to scare the tiger (inherit the cat action), but for now it looks bored when we try. This problem is caused by the complete replacement of the class variable acts in the Tiger class. The cat actions are deleted and replaced with tiger-only actions.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts = {&lt;br /&gt;
        &#039;scratch&#039;: &#039;roars&#039;,&lt;br /&gt;
        &#039;feed&#039;: &#039;demands more meat&#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
# Thats OK, we will just add the tiger actions later - we inherited the add_action from CatClass&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.add_action(&#039;scratch&#039;, &#039;roars&#039;)&lt;br /&gt;
tigger.add_action(&#039;feed&#039;, &#039;demands more meat&#039;)&lt;br /&gt;
# Testing&lt;br /&gt;
tigger.action(&#039;scare&#039;)&lt;br /&gt;
tigger.action(&#039;feed&#039;)&lt;br /&gt;
# All good, but what happened to our cat?&lt;br /&gt;
mycat.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The cat started roaring when scratched - that is a tiger action. Looking at the add_action class method, it is not specifying anywhere that the CatClass should be used so what is wrong? The problem is that the Tiger and the CatClass are &#039;&#039;sharing&#039;&#039; the class variables. The Tiger did not make new ones, so it is using the CatClass class variables, because CatClass is the parent class. Right now any changes in action made by the Tiger class is reflected in the CatClass and vice versa. The Tiger needs is own. Also did you notice that the Tiger&#039;s scientific name is Felis Catus, same as the cat - ridiculous.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Panthera&amp;quot;&lt;br /&gt;
    species = &amp;quot;Tigris&amp;quot;&lt;br /&gt;
    acts = CatClass.acts.copy()&lt;br /&gt;
    # Tiger class specials&lt;br /&gt;
    acts[&#039;scratch&#039;] = &#039;roars&#039;&lt;br /&gt;
    acts[&#039;feed&#039;} = &#039;demands more meat&#039;&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.action(&#039;scratch&#039;)&lt;br /&gt;
mycat.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Much better. Copy the mutable class variables from the base class and then change them so they fit.&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=274</id>
		<title>Example code - Inheritance issues</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=274"/>
		<updated>2026-03-19T16:49:52Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The challenges in inheritance can not be demonstrated well in a powerpoint.&lt;br /&gt;
Thus, I made this page with examples. You can copy the code in the section and add it together and run it.&lt;br /&gt;
&lt;br /&gt;
First I create a slightly bigger CatClass.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class CatClass:&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Felis&amp;quot;&lt;br /&gt;
    species = &amp;quot;Catus&amp;quot;&lt;br /&gt;
    acts = {&#039;scratch&#039;: &amp;quot;purrs&amp;quot;,&lt;br /&gt;
            &#039;scare&#039;: &amp;quot;jumps high in the air&amp;quot;,&lt;br /&gt;
            &#039;feed&#039;: &amp;quot;is very excited&amp;quot; }&lt;br /&gt;
&lt;br /&gt;
    ### Instatiation&lt;br /&gt;
    def __init__(self, name, gender):&lt;br /&gt;
        self.name, self.gender = name, gender&lt;br /&gt;
&lt;br /&gt;
    ### Magic methods&lt;br /&gt;
    # Addition makes a kitten if male and female cat, alternative constructor&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self.gender == other.gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Being biased and saying all kittens are male&lt;br /&gt;
        kitten = CatClass(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten     &lt;br /&gt;
        &lt;br /&gt;
    ### Class methods&lt;br /&gt;
    # Adding a cat action&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def add_action(cls, action, reaction):&lt;br /&gt;
       cls.acts[action] = reaction&lt;br /&gt;
    # Querying class for number of actions&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def count_action(cls):&lt;br /&gt;
        return len(cls.acts)&lt;br /&gt;
&lt;br /&gt;
    ### Property methods&lt;br /&gt;
    # age setter and getter&lt;br /&gt;
    @property&lt;br /&gt;
    def age(self):&lt;br /&gt;
        if not hasattr(self, &#039;_age&#039;):&lt;br /&gt;
            raise NameError(&amp;quot;Age of cat is not yet set&amp;quot;)&lt;br /&gt;
        return self._age&lt;br /&gt;
        &lt;br /&gt;
    @age.setter&lt;br /&gt;
    def age(self, value):&lt;br /&gt;
        if value &amp;lt; 0:&lt;br /&gt;
            raise ValueError(&amp;quot;Age can not be negative&amp;quot;)&lt;br /&gt;
        self._age = value&lt;br /&gt;
&lt;br /&gt;
    ### Instance methods&lt;br /&gt;
    # The action method - using class variables&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self.name, CatClass.acts[act])&lt;br /&gt;
        elif self.gender == &#039;male&#039;:&lt;br /&gt;
            print(self.name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self.name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
### Main program                    &lt;br /&gt;
yourcat = CatClass(&#039;Missy&#039;, &#039;female&#039;)&lt;br /&gt;
yourcat.age = 5&lt;br /&gt;
print(f&amp;quot;The age of your cat is {yourcat.age}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
CatClass.add_action(&amp;quot;annoy&amp;quot;, &amp;quot;scratches your face&amp;quot;)&lt;br /&gt;
print(&amp;quot;Actions in CatClass:&amp;quot;, CatClass.count_action())&lt;br /&gt;
&lt;br /&gt;
mycat = CatClass(&amp;quot;Tom&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
kitten = mycat + yourcat&lt;br /&gt;
&lt;br /&gt;
print(f&amp;quot;Kitten: {kitten.name}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
yourcat.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This class looks fine, but it has a number of inheritance issues.&lt;br /&gt;
By creating a Tiger class that inherits from the CatClass, I will demonstrate. Also, see how simple it was to create a new class based on an old :-)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts = {&lt;br /&gt;
        &#039;scratch&#039;: &#039;roars&#039;,&lt;br /&gt;
        &#039;feed&#039;: &#039;demands more meat&#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.action(&amp;quot;scratch&amp;quot;)&lt;br /&gt;
tigger.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We want the Tiger to react differently than the Cat, at least for some actions. However, this code does not do it. The problem lies in the inherited &#039;&#039;&#039;action&#039;&#039;&#039; method.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self.name, CatClass.acts[act])&lt;br /&gt;
        elif self.gender == &#039;male&#039;:&lt;br /&gt;
            print(self.name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self.name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    # We are specifically using the actions in the CatClass for the behavior&lt;br /&gt;
    # We need to use the current class, as in cats uses CatClass actions and tigers uses Tiger actions.&lt;br /&gt;
&lt;br /&gt;
    # These are the problematic lines, they can be replaced in different ways&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self.name, CatClass.acts[act])&lt;br /&gt;
    # Through &#039;&#039;&#039;self&#039;&#039;&#039;, as self will search the instance namespace and then the class namespace for the variable&lt;br /&gt;
        if act in self.acts:&lt;br /&gt;
            print(self.name, self.acts[act])&lt;br /&gt;
    # By dynamically getting the class by type&lt;br /&gt;
        cls = type(self)&lt;br /&gt;
        if act in cls.acts:&lt;br /&gt;
            print(self.name, cls.acts[act])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This does not completely solve the problem. We would still like to be able to scare the tiger (inherit the cat action), but for now it looks bored when we try. This problem is caused by the complete replacement of the class variable acts in the Tiger class. The cat actions are deleted and replaced with tiger-only actions.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts = {&lt;br /&gt;
        &#039;scratch&#039;: &#039;roars&#039;,&lt;br /&gt;
        &#039;feed&#039;: &#039;demands more meat&#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
# Thats OK, we will just add the tiger actions later - we inherited the add_action from CatClass&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.add_action(&#039;scratch&#039;, &#039;roars&#039;)&lt;br /&gt;
tigger.add_action(&#039;feed&#039;, &#039;demands more meat&#039;)&lt;br /&gt;
# Testing&lt;br /&gt;
tigger.action(&#039;scare&#039;)&lt;br /&gt;
tigger.action(&#039;feed&#039;)&lt;br /&gt;
# All good, but what happened to our cat?&lt;br /&gt;
mycat.action(&#039;scratch&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The cat started roaring when scratched - that is a tiger action. Looking at the add_action class method, it is not specifying anywhere that the CatClass should be used so what is wrong?&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=273</id>
		<title>Example code - Inheritance issues</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=273"/>
		<updated>2026-03-19T16:37:13Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The challenges in inheritance can not be demonstrated well in a powerpoint.&lt;br /&gt;
Thus, I made this page with examples. You can copy the code in the section and add it together and run it.&lt;br /&gt;
&lt;br /&gt;
First I create a slightly bigger CatClass.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class CatClass:&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Felis&amp;quot;&lt;br /&gt;
    species = &amp;quot;Catus&amp;quot;&lt;br /&gt;
    acts = {&#039;scratch&#039;: &amp;quot;purrs&amp;quot;,&lt;br /&gt;
            &#039;scare&#039;: &amp;quot;jumps high in the air&amp;quot;,&lt;br /&gt;
            &#039;feed&#039;: &amp;quot;is very excited&amp;quot; }&lt;br /&gt;
&lt;br /&gt;
    ### Instatiation&lt;br /&gt;
    def __init__(self, name, gender):&lt;br /&gt;
        self.name, self.gender = name, gender&lt;br /&gt;
&lt;br /&gt;
    ### Magic methods&lt;br /&gt;
    # Addition makes a kitten if male and female cat, alternative constructor&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self.gender == other.gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Being biased and saying all kittens are male&lt;br /&gt;
        kitten = CatClass(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten     &lt;br /&gt;
        &lt;br /&gt;
    ### Class methods&lt;br /&gt;
    # Adding a cat action&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def add_action(cls, action, reaction):&lt;br /&gt;
       cls.acts[action] = reaction&lt;br /&gt;
    # Querying class for number of actions&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def count_action(cls):&lt;br /&gt;
        return len(cls.acts)&lt;br /&gt;
&lt;br /&gt;
    ### Property methods&lt;br /&gt;
    # age setter and getter&lt;br /&gt;
    @property&lt;br /&gt;
    def age(self):&lt;br /&gt;
        if not hasattr(self, &#039;_age&#039;):&lt;br /&gt;
            raise NameError(&amp;quot;Age of cat is not yet set&amp;quot;)&lt;br /&gt;
        return self._age&lt;br /&gt;
        &lt;br /&gt;
    @age.setter&lt;br /&gt;
    def age(self, value):&lt;br /&gt;
        if value &amp;lt; 0:&lt;br /&gt;
            raise ValueError(&amp;quot;Age can not be negative&amp;quot;)&lt;br /&gt;
        self._age = value&lt;br /&gt;
&lt;br /&gt;
    ### Instance methods&lt;br /&gt;
    # The action method - using class variables&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self.name, CatClass.acts[act])&lt;br /&gt;
        elif self.gender == &#039;male&#039;:&lt;br /&gt;
            print(self.name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self.name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
### Main program                    &lt;br /&gt;
yourcat = CatClass(&#039;Missy&#039;, &#039;female&#039;)&lt;br /&gt;
yourcat.age = 5&lt;br /&gt;
print(f&amp;quot;The age of your cat is {yourcat.age}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
CatClass.add_action(&amp;quot;annoy&amp;quot;, &amp;quot;scratches your face&amp;quot;)&lt;br /&gt;
print(&amp;quot;Actions in CatClass:&amp;quot;, CatClass.count_action())&lt;br /&gt;
&lt;br /&gt;
mycat = CatClass(&amp;quot;Tom&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
kitten = mycat + yourcat&lt;br /&gt;
&lt;br /&gt;
print(f&amp;quot;Kitten: {kitten.name}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
yourcat.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This class looks fine, but it has a number of inheritance issues.&lt;br /&gt;
By creating a Tiger class that inherits from the CatClass, I will demonstrate. Also, see how simple it was to create a new class based on an old :-)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts = {&lt;br /&gt;
        &#039;scratch&#039;: &#039;roars&#039;,&lt;br /&gt;
        &#039;feed&#039;: &#039;demands more meat&#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.action(&amp;quot;scratch&amp;quot;)&lt;br /&gt;
tigger.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We want the Tiger to react differently than the Cat, at least for some actions. However, this code does not do it. The problem lies in the inherited &#039;&#039;&#039;action&#039;&#039;&#039; method.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self.name, CatClass.acts[act])&lt;br /&gt;
        elif self.gender == &#039;male&#039;:&lt;br /&gt;
            print(self.name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self.name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    # We are specifically using the actions in the CatClass for the behavior&lt;br /&gt;
    # We need to use the current class, as in cats uses CatClass actions and tigers uses Tiger actions.&lt;br /&gt;
&lt;br /&gt;
    # These are the problematic lines, they can be replaced in different ways&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self.name, CatClass.acts[act])&lt;br /&gt;
    # Through &#039;&#039;&#039;self&#039;&#039;&#039;, as self will search the instance namespace and then the class namespace for the variable&lt;br /&gt;
        if act in self.acts:&lt;br /&gt;
            print(self.name, self.acts[act])&lt;br /&gt;
    # By dynamically getting the class by type&lt;br /&gt;
        cls = type(self)&lt;br /&gt;
        if act in cls.acts:&lt;br /&gt;
            print(self.name, cls.acts[act])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This does not completely solve the problem. We would still like to be able to scare the tiger (inherit the cat action), but for now it looks bored when we try. This problem is caused by the complete replacement of the class variable acts in the Tiger class. The cat actions are deleted and replaced with tiger-only actions.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts = {&lt;br /&gt;
        &#039;scratch&#039;: &#039;roars&#039;,&lt;br /&gt;
        &#039;feed&#039;: &#039;demands more meat&#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
# By changing instead of replacing we might get somewhere good.&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts[&#039;scratch&#039;] = &#039;roars&#039;&lt;br /&gt;
    acts[&#039;feed&#039;] = &#039;demands more meat&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=272</id>
		<title>Example code - Inheritance issues</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=272"/>
		<updated>2026-03-19T16:26:33Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The challenges in inheritance can not be demonstrated well in a powerpoint.&lt;br /&gt;
Thus, I made this page with examples. You can copy the code in the section and add it together and run it.&lt;br /&gt;
&lt;br /&gt;
First I create a slightly bigger CatClass.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class CatClass:&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Felis&amp;quot;&lt;br /&gt;
    species = &amp;quot;Catus&amp;quot;&lt;br /&gt;
    acts = {&#039;scratch&#039;: &amp;quot;purrs&amp;quot;,&lt;br /&gt;
            &#039;scare&#039;: &amp;quot;jumps high in the air&amp;quot;,&lt;br /&gt;
            &#039;feed&#039;: &amp;quot;is very excited&amp;quot; }&lt;br /&gt;
&lt;br /&gt;
    ### Instatiation&lt;br /&gt;
    def __init__(self, name, gender):&lt;br /&gt;
        self.name, self.gender = name, gender&lt;br /&gt;
&lt;br /&gt;
    ### Magic methods&lt;br /&gt;
    # Addition makes a kitten if male and female cat, alternative constructor&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self.gender == other.gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Being biased and saying all kittens are male&lt;br /&gt;
        kitten = CatClass(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten     &lt;br /&gt;
        &lt;br /&gt;
    ### Class methods&lt;br /&gt;
    # Adding a cat action&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def add_action(cls, action, reaction):&lt;br /&gt;
       cls.acts[action] = reaction&lt;br /&gt;
    # Querying class for number of actions&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def count_action(cls):&lt;br /&gt;
        return len(cls.acts)&lt;br /&gt;
&lt;br /&gt;
    ### Property methods&lt;br /&gt;
    # age setter and getter&lt;br /&gt;
    @property&lt;br /&gt;
    def age(self):&lt;br /&gt;
        if not hasattr(self, &#039;_age&#039;):&lt;br /&gt;
            raise NameError(&amp;quot;Age of cat is not yet set&amp;quot;)&lt;br /&gt;
        return self._age&lt;br /&gt;
        &lt;br /&gt;
    @age.setter&lt;br /&gt;
    def age(self, value):&lt;br /&gt;
        if value &amp;lt; 0:&lt;br /&gt;
            raise ValueError(&amp;quot;Age can not be negative&amp;quot;)&lt;br /&gt;
        self._age = value&lt;br /&gt;
&lt;br /&gt;
    ### Instance methods&lt;br /&gt;
    # The action method - using class variables&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self.name, CatClass.acts[act])&lt;br /&gt;
        elif self.gender == &#039;male&#039;:&lt;br /&gt;
            print(self.name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self.name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
### Main program                    &lt;br /&gt;
yourcat = CatClass(&#039;Missy&#039;, &#039;female&#039;)&lt;br /&gt;
yourcat.age = 5&lt;br /&gt;
print(f&amp;quot;The age of your cat is {yourcat.age}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
CatClass.add_action(&amp;quot;annoy&amp;quot;, &amp;quot;scratches your face&amp;quot;)&lt;br /&gt;
print(&amp;quot;Actions in CatClass:&amp;quot;, CatClass.count_action())&lt;br /&gt;
&lt;br /&gt;
mycat = CatClass(&amp;quot;Tom&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
kitten = mycat + yourcat&lt;br /&gt;
&lt;br /&gt;
print(f&amp;quot;Kitten: {kitten.name}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
yourcat.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This class looks fine, but it has a number of inheritance issues.&lt;br /&gt;
By creating a Tiger class that inherits from the CatClass, I will demonstrate. Also, see how simple it was to create a new class based on an old :-)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts = {&lt;br /&gt;
        &#039;scratch&#039;: &#039;roars&#039;,&lt;br /&gt;
        &#039;feed&#039;: &#039;demands more meat&#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.action(&amp;quot;scratch&amp;quot;)&lt;br /&gt;
tigger.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We want the Tiger to react differently than the Cat, at least for some actions. However, this code does not do it. The problem lies in the inherited &#039;&#039;&#039;action&#039;&#039;&#039; method.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self.name, CatClass.acts[act])&lt;br /&gt;
        elif self.gender == &#039;male&#039;:&lt;br /&gt;
            print(self.name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self.name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    # We are specifically using the actions in the CatClass for the behavior&lt;br /&gt;
    # We need to use the current class, as in cat uses CatClass actions and tigers uses Tiger actions.&lt;br /&gt;
&lt;br /&gt;
    # These are the problematic lines, they can be replaced in different ways&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self.name, CatClass.acts[act])&lt;br /&gt;
    # Through &#039;&#039;&#039;self&#039;&#039;&#039;, as self will search for the instance namespace and then the class namespace for the variable&lt;br /&gt;
        if act in self.acts:&lt;br /&gt;
            print(self.name, self.acts[act])&lt;br /&gt;
    # Dynamically getting the class by type&lt;br /&gt;
        cls = type(self)&lt;br /&gt;
        if act in cls.acts:&lt;br /&gt;
            print(self.name, cls.acts[act])&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=271</id>
		<title>Example code - Inheritance issues</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Example_code_-_Inheritance_issues&amp;diff=271"/>
		<updated>2026-03-19T16:07:22Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: Created page with &amp;quot;The challenges in inheritance can not be demonstrated well in a powerpoint. Thus, I made this page with examples. You can copy the code in the section and add it together and run it.  First I create a slightly bigger CatClass. &amp;lt;pre&amp;gt; class CatClass:     ### Class variables     genus = &amp;quot;Felis&amp;quot;     species = &amp;quot;Catus&amp;quot;     acts = {&amp;#039;scratch&amp;#039;: &amp;quot;purrs&amp;quot;,             &amp;#039;scare&amp;#039;: &amp;quot;jumps high in the air&amp;quot;,             &amp;#039;feed&amp;#039;: &amp;quot;is very excited&amp;quot; }      ### Instatiation     def __init__(sel...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The challenges in inheritance can not be demonstrated well in a powerpoint.&lt;br /&gt;
Thus, I made this page with examples. You can copy the code in the section and add it together and run it.&lt;br /&gt;
&lt;br /&gt;
First I create a slightly bigger CatClass.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class CatClass:&lt;br /&gt;
    ### Class variables&lt;br /&gt;
    genus = &amp;quot;Felis&amp;quot;&lt;br /&gt;
    species = &amp;quot;Catus&amp;quot;&lt;br /&gt;
    acts = {&#039;scratch&#039;: &amp;quot;purrs&amp;quot;,&lt;br /&gt;
            &#039;scare&#039;: &amp;quot;jumps high in the air&amp;quot;,&lt;br /&gt;
            &#039;feed&#039;: &amp;quot;is very excited&amp;quot; }&lt;br /&gt;
&lt;br /&gt;
    ### Instatiation&lt;br /&gt;
    def __init__(self, name, gender):&lt;br /&gt;
        self.name, self.gender = name, gender&lt;br /&gt;
&lt;br /&gt;
    ### Magic methods&lt;br /&gt;
    # Addition makes a kitten if male and female cat, alternative constructor&lt;br /&gt;
    def __add__(self, other):&lt;br /&gt;
        # Taken a short cut and just demanding the genders to be different to breed&lt;br /&gt;
        if self.gender == other.gender:&lt;br /&gt;
            return NotImplemented&lt;br /&gt;
        # Being biased and saying all kittens are male&lt;br /&gt;
        kitten = CatClass(&#039;Unnamed kitten&#039;, &#039;male&#039;)&lt;br /&gt;
        return kitten     &lt;br /&gt;
        &lt;br /&gt;
    ### Class methods&lt;br /&gt;
    # Adding a cat action&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def add_action(cls, action, reaction):&lt;br /&gt;
       cls.acts[action] = reaction&lt;br /&gt;
    # Querying class for number of actions&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def count_action(cls):&lt;br /&gt;
        return len(cls.acts)&lt;br /&gt;
&lt;br /&gt;
    ### Property methods&lt;br /&gt;
    # age setter and getter&lt;br /&gt;
    @property&lt;br /&gt;
    def age(self):&lt;br /&gt;
        if not hasattr(self, &#039;_age&#039;):&lt;br /&gt;
            raise NameError(&amp;quot;Age of cat is not yet set&amp;quot;)&lt;br /&gt;
        return self._age&lt;br /&gt;
        &lt;br /&gt;
    @age.setter&lt;br /&gt;
    def age(self, value):&lt;br /&gt;
        if value &amp;lt; 0:&lt;br /&gt;
            raise ValueError(&amp;quot;Age can not be negative&amp;quot;)&lt;br /&gt;
        self._age = value&lt;br /&gt;
&lt;br /&gt;
    ### Instance methods&lt;br /&gt;
    # The action method - using class variables&lt;br /&gt;
    def action(self, act):&lt;br /&gt;
        if act in CatClass.acts:&lt;br /&gt;
            print(self.name, CatClass.acts[act])&lt;br /&gt;
        elif self.gender == &#039;male&#039;:&lt;br /&gt;
            print(self.name, &amp;quot;looks bored&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(self.name, &amp;quot;yawns&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
### Main program                    &lt;br /&gt;
yourcat = CatClass(&#039;Missy&#039;, &#039;female&#039;)&lt;br /&gt;
yourcat.age = 5&lt;br /&gt;
print(f&amp;quot;The age of your cat is {yourcat.age}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
CatClass.add_action(&amp;quot;annoy&amp;quot;, &amp;quot;scratches your face&amp;quot;)&lt;br /&gt;
print(&amp;quot;Actions in CatClass:&amp;quot;, CatClass.count_action())&lt;br /&gt;
&lt;br /&gt;
mycat = CatClass(&amp;quot;Tom&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
kitten = mycat + yourcat&lt;br /&gt;
&lt;br /&gt;
print(f&amp;quot;Kitten: {kitten.name}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
yourcat.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This class looks fine, but it has a number of inheritance issues.&lt;br /&gt;
By creating a Tiger class that inherits from the CatClass, I will demonstrate.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Tiger(CatClass):&lt;br /&gt;
    acts = {&lt;br /&gt;
        &#039;scratch&#039;: &#039;roars&#039;,&lt;br /&gt;
        &#039;feed&#039;: &#039;demands more meat&#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
tigger = Tiger(&amp;quot;Shere Khan&amp;quot;, &amp;quot;male&amp;quot;)&lt;br /&gt;
tigger.action(&amp;quot;scratch&amp;quot;)&lt;br /&gt;
tigger.action(&#039;scare&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Intermediate_classes&amp;diff=270</id>
		<title>Intermediate classes</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Intermediate_classes&amp;diff=270"/>
		<updated>2026-03-19T16:00:12Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Required course material for the lesson */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Beginning classes]]&lt;br /&gt;
|Next: [[Beginning unit test]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_07-Classes.ppt Classes]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Example code - Inheritance issues]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Magic methods in classes&amp;lt;br&amp;gt;&lt;br /&gt;
Object Oriented Programming&amp;lt;br&amp;gt;&lt;br /&gt;
Polymorphism and inheritance&amp;lt;br&amp;gt;&lt;br /&gt;
Practical knowledge&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
The first four exercises will continue with the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class from last time.&lt;br /&gt;
# Use magic methods to add &#039;&#039;iteration&#039;&#039; and &#039;&#039;length&#039;&#039; evaluation (using &#039;&#039;&#039;__iter__&#039;&#039;&#039; and &#039;&#039;&#039;__len__&#039;&#039;&#039; magic methods) to the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class. Do this so you can write code like &amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;if len(MyFastaInstance) &amp;gt; 0:&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;for header, sequence in MyFastaInstance:&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;# Do something with header and sequence&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;print(header, sequence)&amp;lt;/div&amp;gt;The function &#039;&#039;&#039;len&#039;&#039;&#039; returns the number of sequences.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add the methods &#039;&#039;&#039;deletethis()&#039;&#039;&#039;, &#039;&#039;&#039;insertthis(header, sequence)&#039;&#039;&#039;, &#039;&#039;&#039;verifythis(alphabet)&#039;&#039;&#039; and &#039;&#039;&#039;discardthis(alphabet)&#039;&#039;&#039; to the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class. The methods should only work when &#039;&#039;iterating over an instance at the current item&#039;&#039;, i.e. they work when you are iterating over the fasta sequences on the &#039;&#039;current&#039;&#039; sequence and header, like this:&amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;for header, sequence in MyFastaInstance:&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;if not MyFastaInstance.verifythis(&amp;quot;DNA&amp;quot;):&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;MyFastaInstance.deletethis()&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;continue&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;# Do something with header and sequence&amp;lt;/div&amp;gt;As some may remember, it is normally impossible to successfully iterate straightforward through a list and delete and/or add elements to the list during the iteration. You have to make this possible. Hint: change the way your iteration works in the previous exercise. You need to take a position on this issue: When iterating over entries, how should you continue after inserting entries at your current position? Example: You are at element in position 5, you insert 2 elements at that position. This WILL mean the new elements are at position 5 and 6, and the one you &amp;quot;looked at&amp;quot; is now on position 7. Do you continue the iteration on position 5 or is the next position 8? My opinion is that you should not look at the new elements and you have already looked at the &amp;quot;old&amp;quot; element ant 5, so the next one is at 8. You are free to make your own decision - just be clear about it.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Let&#039;s do something natural. Make it possible to add one FastaInstance to another using the &#039;&#039;&#039;+=&#039;&#039;&#039; operator, like this:&amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;FastaInstance1 += FastaInstance2&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;The headers and sequences in Fastainstance2 should be added (list extension) to the headers and sequences in FastaInstance1. Use the magic method [https://zetcode.com/python/dunder-iadd/ &#039;&#039;&#039;__iadd__&#039;&#039;&#039;]. Try with the files &#039;&#039;dna7.fsa&#039;&#039; and &#039;&#039;protein.fsa&#039;&#039;. That will be a strange DNA and protein mix, but it is a great opportunity to use the &#039;&#039;&#039;discard&#039;&#039;&#039; method to get rid of one of the types.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Implement the &#039;&#039;addition&#039;&#039;, using [https://zetcode.com/python/dunder-add/ &#039;&#039;&#039;__add__&#039;&#039;&#039;]. Addition creates a new Fasta instance, but leaves the originals untouched.&amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;FastaInstance3 = FastaInstance1 + FastaInstance2&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;The resulting Fasta object must contain the headers and sequences from FastaInstance1 and FastaInstance2 in that order. Note that this works as an alternative constructor. Now that the Fasta class is done, save it in a file, so you can import it for the next exercises.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# You can consider a &#039;&#039;&#039;Fasta&#039;&#039;&#039; instance as a &#039;&#039;set&#039;&#039; of headers/sequences. The sequences are obviously uniquely identified by the identifier in the header, which is what will be used as key in the set operations. In the rest of the exercises we will explore inheritance by making a new class called &#039;&#039;&#039;FastaSet&#039;&#039;&#039;, which inherits from the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class.&amp;lt;br&amp;gt;A) The original &#039;&#039;&#039;__init__&#039;&#039;&#039;, &#039;&#039;&#039;save&#039;&#039;&#039;, &#039;&#039;&#039;load&#039;&#039;&#039;, &#039;&#039;&#039;insert&#039;&#039;&#039;, the iteration and the corresponding &#039;&#039;&#039;deletethis&#039;&#039;&#039;, &#039;&#039;&#039;insertthis&#039;&#039;&#039;, &#039;&#039;&#039;verifythis&#039;&#039;&#039; and &#039;&#039;&#039;discardthis&#039;&#039;&#039; methods are fine to keep in the new class (meaning do nothing about them).&amp;lt;br&amp;gt;B) To help in the new class create a new getter method &#039;&#039;&#039;identifiers&#039;&#039;&#039;, which returns a list of identifiers from the header lines.&amp;lt;br&amp;gt;C) Override the &#039;&#039;&#039;content&#039;&#039;&#039; method such that it takes a set or list of identifiers and returns only the headers/sequences that corresponds to the identifiers in the list. If you do not specify a list/set of identifiers, it still returns all.&amp;lt;br&amp;gt;D) Override the &#039;&#039;&#039;delete&#039;&#039;&#039; method in a similar way - it deletes the headers/sequences that corresponds to the input.&amp;lt;br&amp;gt;E) Override the &#039;&#039;&#039;verify&#039;&#039;&#039; method in a similar way to &#039;&#039;&#039;content&#039;&#039;&#039; - it verifies the headers/sequences that corresponds to the input.&amp;lt;br&amp;gt;F) Override the &#039;&#039;&#039;discard&#039;&#039;&#039; method in a similar way to &#039;&#039;&#039;content&#039;&#039;&#039; - it discards the headers/sequences that corresponds to the input.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# As the new FastaSet class is set orientated, implement the following set operations in the class:&amp;lt;br&amp;gt;A) union, operator is &#039;&#039;&#039;|&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__or__&#039;&#039;&#039;.&amp;lt;br&amp;gt;B) intersection, operator is &#039;&#039;&#039;&amp;amp;&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__and__&#039;&#039;&#039;.&amp;lt;br&amp;gt;C) difference, operator is &#039;&#039;&#039;-&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__sub__&#039;&#039;&#039;.&amp;lt;br&amp;gt;D) symmetric difference, operator is &#039;&#039;&#039;^&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__xor__&#039;&#039;&#039;.&amp;lt;br&amp;gt;These are quite similar to the addition in exercise 4 - the operators are used in the same way and a new Fasta object is returned. The identity of the sequence depends on the identifier in the corresponding header. This is an example of operator overloading - the normal arithmetic operator used on numbers are used on something completely different.&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;br /&gt;
# You continue to add the unique identifier control for all methods in Fasta and FastaSet, as mentioned last week.&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Intermediate_classes&amp;diff=269</id>
		<title>Intermediate classes</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Intermediate_classes&amp;diff=269"/>
		<updated>2026-03-18T22:06:42Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Exercises to be handed in */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Beginning classes]]&lt;br /&gt;
|Next: [[Beginning unit test]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_07-Classes.ppt Classes]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Example code - Classes]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Magic methods in classes&amp;lt;br&amp;gt;&lt;br /&gt;
Object Oriented Programming&amp;lt;br&amp;gt;&lt;br /&gt;
Polymorphism and inheritance&amp;lt;br&amp;gt;&lt;br /&gt;
Practical knowledge&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
The first four exercises will continue with the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class from last time.&lt;br /&gt;
# Use magic methods to add &#039;&#039;iteration&#039;&#039; and &#039;&#039;length&#039;&#039; evaluation (using &#039;&#039;&#039;__iter__&#039;&#039;&#039; and &#039;&#039;&#039;__len__&#039;&#039;&#039; magic methods) to the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class. Do this so you can write code like &amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;if len(MyFastaInstance) &amp;gt; 0:&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;for header, sequence in MyFastaInstance:&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;# Do something with header and sequence&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;print(header, sequence)&amp;lt;/div&amp;gt;The function &#039;&#039;&#039;len&#039;&#039;&#039; returns the number of sequences.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add the methods &#039;&#039;&#039;deletethis()&#039;&#039;&#039;, &#039;&#039;&#039;insertthis(header, sequence)&#039;&#039;&#039;, &#039;&#039;&#039;verifythis(alphabet)&#039;&#039;&#039; and &#039;&#039;&#039;discardthis(alphabet)&#039;&#039;&#039; to the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class. The methods should only work when &#039;&#039;iterating over an instance at the current item&#039;&#039;, i.e. they work when you are iterating over the fasta sequences on the &#039;&#039;current&#039;&#039; sequence and header, like this:&amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;for header, sequence in MyFastaInstance:&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;if not MyFastaInstance.verifythis(&amp;quot;DNA&amp;quot;):&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;MyFastaInstance.deletethis()&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;continue&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;# Do something with header and sequence&amp;lt;/div&amp;gt;As some may remember, it is normally impossible to successfully iterate straightforward through a list and delete and/or add elements to the list during the iteration. You have to make this possible. Hint: change the way your iteration works in the previous exercise. You need to take a position on this issue: When iterating over entries, how should you continue after inserting entries at your current position? Example: You are at element in position 5, you insert 2 elements at that position. This WILL mean the new elements are at position 5 and 6, and the one you &amp;quot;looked at&amp;quot; is now on position 7. Do you continue the iteration on position 5 or is the next position 8? My opinion is that you should not look at the new elements and you have already looked at the &amp;quot;old&amp;quot; element ant 5, so the next one is at 8. You are free to make your own decision - just be clear about it.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Let&#039;s do something natural. Make it possible to add one FastaInstance to another using the &#039;&#039;&#039;+=&#039;&#039;&#039; operator, like this:&amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;FastaInstance1 += FastaInstance2&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;The headers and sequences in Fastainstance2 should be added (list extension) to the headers and sequences in FastaInstance1. Use the magic method [https://zetcode.com/python/dunder-iadd/ &#039;&#039;&#039;__iadd__&#039;&#039;&#039;]. Try with the files &#039;&#039;dna7.fsa&#039;&#039; and &#039;&#039;protein.fsa&#039;&#039;. That will be a strange DNA and protein mix, but it is a great opportunity to use the &#039;&#039;&#039;discard&#039;&#039;&#039; method to get rid of one of the types.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Implement the &#039;&#039;addition&#039;&#039;, using [https://zetcode.com/python/dunder-add/ &#039;&#039;&#039;__add__&#039;&#039;&#039;]. Addition creates a new Fasta instance, but leaves the originals untouched.&amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;FastaInstance3 = FastaInstance1 + FastaInstance2&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;The resulting Fasta object must contain the headers and sequences from FastaInstance1 and FastaInstance2 in that order. Note that this works as an alternative constructor. Now that the Fasta class is done, save it in a file, so you can import it for the next exercises.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# You can consider a &#039;&#039;&#039;Fasta&#039;&#039;&#039; instance as a &#039;&#039;set&#039;&#039; of headers/sequences. The sequences are obviously uniquely identified by the identifier in the header, which is what will be used as key in the set operations. In the rest of the exercises we will explore inheritance by making a new class called &#039;&#039;&#039;FastaSet&#039;&#039;&#039;, which inherits from the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class.&amp;lt;br&amp;gt;A) The original &#039;&#039;&#039;__init__&#039;&#039;&#039;, &#039;&#039;&#039;save&#039;&#039;&#039;, &#039;&#039;&#039;load&#039;&#039;&#039;, &#039;&#039;&#039;insert&#039;&#039;&#039;, the iteration and the corresponding &#039;&#039;&#039;deletethis&#039;&#039;&#039;, &#039;&#039;&#039;insertthis&#039;&#039;&#039;, &#039;&#039;&#039;verifythis&#039;&#039;&#039; and &#039;&#039;&#039;discardthis&#039;&#039;&#039; methods are fine to keep in the new class (meaning do nothing about them).&amp;lt;br&amp;gt;B) To help in the new class create a new getter method &#039;&#039;&#039;identifiers&#039;&#039;&#039;, which returns a list of identifiers from the header lines.&amp;lt;br&amp;gt;C) Override the &#039;&#039;&#039;content&#039;&#039;&#039; method such that it takes a set or list of identifiers and returns only the headers/sequences that corresponds to the identifiers in the list. If you do not specify a list/set of identifiers, it still returns all.&amp;lt;br&amp;gt;D) Override the &#039;&#039;&#039;delete&#039;&#039;&#039; method in a similar way - it deletes the headers/sequences that corresponds to the input.&amp;lt;br&amp;gt;E) Override the &#039;&#039;&#039;verify&#039;&#039;&#039; method in a similar way to &#039;&#039;&#039;content&#039;&#039;&#039; - it verifies the headers/sequences that corresponds to the input.&amp;lt;br&amp;gt;F) Override the &#039;&#039;&#039;discard&#039;&#039;&#039; method in a similar way to &#039;&#039;&#039;content&#039;&#039;&#039; - it discards the headers/sequences that corresponds to the input.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# As the new FastaSet class is set orientated, implement the following set operations in the class:&amp;lt;br&amp;gt;A) union, operator is &#039;&#039;&#039;|&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__or__&#039;&#039;&#039;.&amp;lt;br&amp;gt;B) intersection, operator is &#039;&#039;&#039;&amp;amp;&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__and__&#039;&#039;&#039;.&amp;lt;br&amp;gt;C) difference, operator is &#039;&#039;&#039;-&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__sub__&#039;&#039;&#039;.&amp;lt;br&amp;gt;D) symmetric difference, operator is &#039;&#039;&#039;^&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__xor__&#039;&#039;&#039;.&amp;lt;br&amp;gt;These are quite similar to the addition in exercise 4 - the operators are used in the same way and a new Fasta object is returned. The identity of the sequence depends on the identifier in the corresponding header. This is an example of operator overloading - the normal arithmetic operator used on numbers are used on something completely different.&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;br /&gt;
# You continue to add the unique identifier control for all methods in Fasta and FastaSet, as mentioned last week.&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Collection_of_files&amp;diff=268</id>
		<title>Collection of files</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Collection_of_files&amp;diff=268"/>
		<updated>2026-03-18T16:49:27Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Files used in various exercises */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
Last updated: February 2, 2023&lt;br /&gt;
== Files used in various exercises ==&lt;br /&gt;
To download the files to your system, just press the Shift key while you left click on the blue link. Follow the instructions.&amp;lt;br&amp;gt;&lt;br /&gt;
You can play around with these files as much as you like. If you change or destroy them, just download them again.&amp;lt;br&amp;gt;&lt;br /&gt;
Put the files in your course folder on your computer.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
The files have been zipped together in one convenient download for you.&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/22118_files.zip 22118_files.zip]&amp;lt;br&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
=== Individual files ===&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/ex1.acc ex1.acc]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/ex1.dat ex1.dat]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/orphans.sp orphans.sp]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/scores.txt scores.txt]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/negative_list.txt negative_list.txt]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/translation.txt translation.txt]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/dna7.fsa dna7.fsa]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/employee-data.csv employee-data.csv]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/mat1.dat mat1.dat]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/mat2.dat mat2.dat]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/dna-array.dat dna-array.dat]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/dna-array-norm.dat dna-array-norm.dat]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/lineartransform.dat lineartransform.dat]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/dnanoise.fsa dnanoise.fsa]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/protein.fsa protein.fsa]&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/data1.gb data1.gb]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/data2.gb data2.gb]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/data3.gb data3.gb]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/data4.gb data4.gb]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/ex5.acc ex5.acc]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/test1.dat test1.dat]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/test2.dat test2.dat]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/test3.dat test3.dat]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/matrix.dat matrix.dat]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/pandas_exercise.zip pandas_exercise.zip]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/gene_combined.txt gene_combined.txt]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/Bioreactor_results.csv Bioreactor_results.csv]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/pathogen_abundance.tab pathogen_abundance.tab]&amp;lt;br&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Intermediate_classes&amp;diff=267</id>
		<title>Intermediate classes</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Intermediate_classes&amp;diff=267"/>
		<updated>2026-03-18T16:47:37Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Exercises to be handed in */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Beginning classes]]&lt;br /&gt;
|Next: [[Beginning unit test]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_07-Classes.ppt Classes]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Example code - Classes]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Magic methods in classes&amp;lt;br&amp;gt;&lt;br /&gt;
Object Oriented Programming&amp;lt;br&amp;gt;&lt;br /&gt;
Polymorphism and inheritance&amp;lt;br&amp;gt;&lt;br /&gt;
Practical knowledge&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
The first four exercises will continue with the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class from last time.&lt;br /&gt;
# Use magic methods to add &#039;&#039;iteration&#039;&#039; and &#039;&#039;length&#039;&#039; evaluation (using &#039;&#039;&#039;__iter__&#039;&#039;&#039; and &#039;&#039;&#039;__len__&#039;&#039;&#039; magic methods) to the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class. Do this so you can write code like &amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;if len(MyFastaInstance) &amp;gt; 0:&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;for header, sequence in MyFastaInstance:&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;# Do something with header and sequence&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;print(header, sequence)&amp;lt;/div&amp;gt;The function &#039;&#039;&#039;len&#039;&#039;&#039; returns the number of sequences.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add the methods &#039;&#039;&#039;deletethis()&#039;&#039;&#039;, &#039;&#039;&#039;insertthis(header, sequence)&#039;&#039;&#039;, &#039;&#039;&#039;verifythis(alphabet)&#039;&#039;&#039; and &#039;&#039;&#039;discardthis(alphabet)&#039;&#039;&#039; to the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class. The methods should only work when &#039;&#039;iterating over an instance at the current item&#039;&#039;, i.e. they work when you are iterating over the fasta sequences on the &#039;&#039;current&#039;&#039; sequence and header, like this:&amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;for header, sequence in MyFastaInstance:&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;if not MyFastaInstance.verifythis(&amp;quot;DNA&amp;quot;):&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;MyFastaInstance.deletethis()&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;continue&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;# Do something with header and sequence&amp;lt;/div&amp;gt;As some may remember, it is normally impossible to successfully iterate straightforward through a list and delete and/or add elements to the list during the iteration. You have to make this possible. Hint: change the way your iteration works in the previous exercise. You need to take a position on this issue: When iterating over entries, how should you continue after inserting entries at your current position? Example: You are at element in position 5, you insert 2 elements at that position. This WILL mean the new elements are at position 5 and 6, and the one you &amp;quot;looked at&amp;quot; is now on position 7. Do you continue the iteration on position 5 or is the next position 8? My opinion is that you should not look at the new elements and you have already looked at the &amp;quot;old&amp;quot; element ant 5, so the next one is at 8. You are free to make your own decision - just be clear about it.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Let&#039;s do something natural. Make it possible to add one FastaInstance to another using the &#039;&#039;&#039;+=&#039;&#039;&#039; operator, like this:&amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;FastaInstance1 += FastaInstance2&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;The headers and sequences in Fastainstance2 should be added (list extension) to the headers and sequences in FastaInstance1. Use the magic method [https://zetcode.com/python/dunder-iadd/ &#039;&#039;&#039;__iadd__&#039;&#039;&#039;]. Try with the files &#039;&#039;dna7.fsa&#039;&#039; and &#039;&#039;protein.fsa&#039;&#039;. That will be a strange DNA and protein mix, but it is a great opportunity to use the &#039;&#039;&#039;discard&#039;&#039;&#039; method to get rid of one of the types.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Implement the &#039;&#039;addition&#039;&#039;, using [https://zetcode.com/python/dunder-add/ &#039;&#039;&#039;__add__&#039;&#039;&#039;]. Addition creates a new Fasta instance, but leaves the originals untouched.&amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;FastaInstance3 = FastaInstance1 + FastaInstance2&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;The resulting Fasta object must contain the headers and sequences from FastaInstance1 and FastaInstance2 in that order. Note that this works as an alternative constructor. Now that the Fasta class is done, save it in a file, so you can import it for the next exercises.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# You can consider a &#039;&#039;&#039;Fasta&#039;&#039;&#039; instance as a &#039;&#039;set&#039;&#039; of headers/sequences. The sequences are obviously uniquely identified by the identifier in the header, which is what will be used as key in the set operations. In the rest of the exercises we will explore inheritance by making a new class called &#039;&#039;&#039;FastaSet&#039;&#039;&#039;, which inherits from the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class.&amp;lt;br&amp;gt;A) The original &#039;&#039;&#039;__init__&#039;&#039;&#039;, &#039;&#039;&#039;save&#039;&#039;&#039;, &#039;&#039;&#039;load&#039;&#039;&#039;, &#039;&#039;&#039;insert&#039;&#039;&#039;, the iteration and the corresponding &#039;&#039;&#039;deletethis&#039;&#039;&#039;, &#039;&#039;&#039;insertthis&#039;&#039;&#039;, &#039;&#039;&#039;verifythis&#039;&#039;&#039; and &#039;&#039;&#039;discardthis&#039;&#039;&#039; methods are fine to keep in the new class (meaning do nothing about them).&amp;lt;br&amp;gt;B) To help in the new class create a new getter method &#039;&#039;&#039;identifiers&#039;&#039;&#039;, which returns a list of identifiers from the header lines.&amp;lt;br&amp;gt;C) Override the &#039;&#039;&#039;content&#039;&#039;&#039; method such that it takes a set or list of identifiers and returns only the headers/sequences that corresponds to the identifiers in the list. If you do not specify a list/set of identifiers, it still returns all.&amp;lt;br&amp;gt;D) Override the &#039;&#039;&#039;delete&#039;&#039;&#039; method in a similar way - it deletes the headers/sequences that corresponds to the input.&amp;lt;br&amp;gt;E) Override the &#039;&#039;&#039;verify&#039;&#039;&#039; method in a similar way to &#039;&#039;&#039;content&#039;&#039;&#039; - it verifies the headers/sequences that corresponds to the input.&amp;lt;br&amp;gt;F) Override the &#039;&#039;&#039;discard&#039;&#039;&#039; method in a similar way to &#039;&#039;&#039;content&#039;&#039;&#039; - it discards the headers/sequences that corresponds to the input.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# As the new FastaSet class is set orientated, implement the following set operations in the class:&amp;lt;br&amp;gt;A) union, operator is &#039;&#039;&#039;|&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__or__&#039;&#039;&#039;.&amp;lt;br&amp;gt;B) intersection, operator is &#039;&#039;&#039;&amp;amp;&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__and__&#039;&#039;&#039;.&amp;lt;br&amp;gt;C) difference, operator is &#039;&#039;&#039;-&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__sub__&#039;&#039;&#039;.&amp;lt;br&amp;gt;D) symmetric difference, operator is &#039;&#039;&#039;^&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__xor__&#039;&#039;&#039;.&amp;lt;br&amp;gt;These are quite similar to the addition in exercise 4 - the operators are used in the same way and a new Fasta object is returned. The identity of the sequence depends on the identifier in the corresponding header. This is an example of operator overloading.&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;br /&gt;
# You continue to add the unique identifier control for all methods in Fasta and FastaSet, as mentioned last week.&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Collection_of_files&amp;diff=266</id>
		<title>Collection of files</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Collection_of_files&amp;diff=266"/>
		<updated>2026-03-18T16:25:44Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Individual files */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
Last updated: February 2, 2023&lt;br /&gt;
== Files used in various exercises ==&lt;br /&gt;
To download the files to your system, just press the Shift key while you left click on the blue link. Follow the instructions.&amp;lt;br&amp;gt;&lt;br /&gt;
You can play around with these files as much as you like. If you change or destroy them, just download them again.&amp;lt;br&amp;gt;&lt;br /&gt;
Put the files in your course folder on your computer.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
The files have been zipped together in one convenient download for you.&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/22118_files.zip 22118_files.zip]&amp;lt;br&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
=== Individual files ===&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/ex1.acc ex1.acc]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/ex1.dat ex1.dat]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/orphans.sp orphans.sp]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/scores.txt scores.txt]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/negative_list.txt negative_list.txt]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/translation.txt translation.txt]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/dna7.fsa dna7.fsa]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/employee-data.csv employee-data.csv]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/mat1.dat mat1.dat]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/mat2.dat mat2.dat]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/dna-array.dat dna-array.dat]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/dna-array-norm.dat dna-array-norm.dat]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/lineartransform.dat lineartransform.dat]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/dnanoise.fsa dnanoise.fsa]&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/data1.gb data1.gb]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/data2.gb data2.gb]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/data3.gb data3.gb]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/data4.gb data4.gb]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/ex5.acc ex5.acc]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/test1.dat test1.dat]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/test2.dat test2.dat]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/test3.dat test3.dat]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/matrix.dat matrix.dat]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/pandas_exercise.zip pandas_exercise.zip]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/gene_combined.txt gene_combined.txt]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/Bioreactor_results.csv Bioreactor_results.csv]&amp;lt;br&amp;gt;&lt;br /&gt;
[https://teaching.healthtech.dtu.dk/material/22118/pathogen_abundance.tab pathogen_abundance.tab]&amp;lt;br&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Intermediate_classes&amp;diff=265</id>
		<title>Intermediate classes</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Intermediate_classes&amp;diff=265"/>
		<updated>2026-03-18T14:59:54Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Exercises to be handed in */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Beginning classes]]&lt;br /&gt;
|Next: [[Beginning unit test]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_07-Classes.ppt Classes]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Example code - Classes]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Magic methods in classes&amp;lt;br&amp;gt;&lt;br /&gt;
Object Oriented Programming&amp;lt;br&amp;gt;&lt;br /&gt;
Polymorphism and inheritance&amp;lt;br&amp;gt;&lt;br /&gt;
Practical knowledge&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
The first four exercises will continue with the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class from last time.&lt;br /&gt;
# Use magic methods to add &#039;&#039;iteration&#039;&#039; and &#039;&#039;length&#039;&#039; evaluation (using &#039;&#039;&#039;__iter__&#039;&#039;&#039; and &#039;&#039;&#039;__len__&#039;&#039;&#039; magic methods) to the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class. Do this so you can write code like &amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;if len(MyFastaInstance) &amp;gt; 0:&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;for header, sequence in MyFastaInstance:&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;# Do something with header and sequence&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;print(header, sequence)&amp;lt;/div&amp;gt;The function &#039;&#039;&#039;len&#039;&#039;&#039; returns the number of sequences.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add the methods &#039;&#039;&#039;deletethis()&#039;&#039;&#039;, &#039;&#039;&#039;insertthis(header, sequence)&#039;&#039;&#039;, &#039;&#039;&#039;verifythis(alphabet)&#039;&#039;&#039; and &#039;&#039;&#039;discardthis(alphabet)&#039;&#039;&#039; to the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class. The methods should only work when &#039;&#039;iterating over an instance at the current item&#039;&#039;, i.e. they work when you are iterating over the fasta sequences on the &#039;&#039;current&#039;&#039; sequence and header, like this:&amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;for header, sequence in MyFastaInstance:&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;if not MyFastaInstance.verifythis(&amp;quot;DNA&amp;quot;):&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;MyFastaInstance.deletethis()&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;continue&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;# Do something with header and sequence&amp;lt;/div&amp;gt;As some may remember, it is normally impossible to successfully iterate straightforward through a list and delete and/or add elements to the list during the iteration. You have to make this possible. Hint: change the way your iteration works in the previous exercise. You need to take a position on this issue: When iterating over entries, how should you continue after inserting entries at your current position? Example: You are at element in position 5, you insert 2 elements at that position. This WILL mean the new elements are at position 5 and 6, and the one you &amp;quot;looked at&amp;quot; is now on position 7. Do you continue the iteration on position 5 or is the next position 8? My opinion is that you should not look at the new elements and you have already looked at the &amp;quot;old&amp;quot; element ant 5, so the next one is at 8. You are free to make your own decision - just be clear about it.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Let&#039;s do something natural. Make it possible to add one FastaInstance to another using the &#039;&#039;&#039;+=&#039;&#039;&#039; operator, like this:&amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;FastaInstance1 += FastaInstance2&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;The headers and sequences in Fastainstance2 should be added (list extension) to the headers and sequences in FastaInstance1. Use the magic method [https://zetcode.com/python/dunder-iadd/ &#039;&#039;&#039;__iadd__&#039;&#039;&#039;].&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Implement the &#039;&#039;addition&#039;&#039;, using [https://zetcode.com/python/dunder-add/ &#039;&#039;&#039;__add__&#039;&#039;&#039;]. Addition creates a new Fasta instance, but leaves the originals untouched.&amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;FastaInstance3 = FastaInstance1 + FastaInstance2&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;The resulting Fasta object must contain the headers and sequences from FastaInstance1 and FastaInstance2 in that order. Note that this works as an alternative constructor. Now that the Fasta class is done, save it in a file, so you can import it for the next exercises.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# You can consider a &#039;&#039;&#039;Fasta&#039;&#039;&#039; instance as a &#039;&#039;set&#039;&#039; of headers/sequences. The sequences are obviously uniquely identified by the identifier in the header, which is what will be used as key in the set operations. In the rest of the exercises we will explore inheritance by making a new class called &#039;&#039;&#039;FastaSet&#039;&#039;&#039;, which inherits from the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class.&amp;lt;br&amp;gt;A) The original &#039;&#039;&#039;__init__&#039;&#039;&#039;, &#039;&#039;&#039;save&#039;&#039;&#039;, &#039;&#039;&#039;load&#039;&#039;&#039;, &#039;&#039;&#039;insert&#039;&#039;&#039;, the iteration and the corresponding &#039;&#039;&#039;deletethis&#039;&#039;&#039;, &#039;&#039;&#039;insertthis&#039;&#039;&#039;, &#039;&#039;&#039;verifythis&#039;&#039;&#039; and &#039;&#039;&#039;discardthis&#039;&#039;&#039; methods are fine to keep in the new class (meaning do nothing about them).&amp;lt;br&amp;gt;B) To help in the new class create a new getter method &#039;&#039;&#039;identifiers&#039;&#039;&#039;, which returns a list of identifiers from the header lines.&amp;lt;br&amp;gt;C) Override the &#039;&#039;&#039;content&#039;&#039;&#039; method such that it takes a set or list of identifiers and returns only the headers/sequences that corresponds to the identifiers in the list. If you do not specify a list/set of identifiers, it still returns all.&amp;lt;br&amp;gt;D) Override the &#039;&#039;&#039;delete&#039;&#039;&#039; method in a similar way - it deletes the headers/sequences that corresponds to the input.&amp;lt;br&amp;gt;E) Override the &#039;&#039;&#039;verify&#039;&#039;&#039; method in a similar way to &#039;&#039;&#039;content&#039;&#039;&#039; - it verifies the headers/sequences that corresponds to the input.&amp;lt;br&amp;gt;F) Override the &#039;&#039;&#039;discard&#039;&#039;&#039; method in a similar way to &#039;&#039;&#039;content&#039;&#039;&#039; - it discards the headers/sequences that corresponds to the input.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# As the new FastaSet class is set orientated, implement the following set operations in the class:&amp;lt;br&amp;gt;A) union, operator is &#039;&#039;&#039;|&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__or__&#039;&#039;&#039;.&amp;lt;br&amp;gt;B) intersection, operator is &#039;&#039;&#039;&amp;amp;&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__and__&#039;&#039;&#039;.&amp;lt;br&amp;gt;C) difference, operator is &#039;&#039;&#039;-&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__sub__&#039;&#039;&#039;.&amp;lt;br&amp;gt;D) symmetric difference, operator is &#039;&#039;&#039;^&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__xor__&#039;&#039;&#039;.&amp;lt;br&amp;gt;These are quite similar to the addition in exercise 4 - the operators are used in the same way and a new Fasta object is returned. The identity of the sequence depends on the identifier in the corresponding header. This is an example of operator overloading.&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;br /&gt;
# You continue to add the unique identifier control for all methods in Fasta and FastaSet, as mentioned last week.&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Intermediate_classes&amp;diff=264</id>
		<title>Intermediate classes</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Intermediate_classes&amp;diff=264"/>
		<updated>2026-03-18T14:59:31Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Exercises to be handed in */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Beginning classes]]&lt;br /&gt;
|Next: [[Beginning unit test]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_07-Classes.ppt Classes]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Example code - Classes]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Magic methods in classes&amp;lt;br&amp;gt;&lt;br /&gt;
Object Oriented Programming&amp;lt;br&amp;gt;&lt;br /&gt;
Polymorphism and inheritance&amp;lt;br&amp;gt;&lt;br /&gt;
Practical knowledge&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
The first four exercises will continue with the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class from last time.&lt;br /&gt;
# Use magic methods to add &#039;&#039;iteration&#039;&#039; and &#039;&#039;length&#039;&#039; evaluation (using &#039;&#039;&#039;__iter__&#039;&#039;&#039; and &#039;&#039;&#039;__len__&#039;&#039;&#039; magic methods) to the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class. Do this so you can write code like &amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;if len(MyFastaInstance) &amp;gt; 0:&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;for header, sequence in MyFastaInstance:&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;# Do something with header and sequence&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;print(header, sequence)&amp;lt;/div&amp;gt;The function &#039;&#039;&#039;len&#039;&#039;&#039; returns the number of sequences.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add the methods &#039;&#039;&#039;deletethis()&#039;&#039;&#039;, &#039;&#039;&#039;insertthis(header, sequence)&#039;&#039;&#039;, &#039;&#039;&#039;verifythis(alphabet)&#039;&#039;&#039; and &#039;&#039;&#039;discardthis(alphabet)&#039;&#039;&#039; to the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class. The methods should only work when &#039;&#039;iterating over an instance at the current item&#039;&#039;, i.e. they work when you are iterating over the fasta sequences on the &#039;&#039;current&#039;&#039; sequence and header, like this:&amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;for header, sequence in MyFastaInstance:&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;if not MyFastaInstance.verifythis(&amp;quot;DNA&amp;quot;):&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;MyFastaInstance.deletethis()&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;continue&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;# Do something with header and sequence&amp;lt;/div&amp;gt;As some may remember, it is normally impossible to successfully iterate straightforward through a list and delete and/or add elements to the list during the iteration. You have to make this possible. Hint: change the way your iteration works in the previous exercise. You need to take a position on this issue: When iteration over entries, how should you continue after inserting entries at your current position? Example: You are at element in position 5, you insert 2 elements at that position. This WILL mean the new elements are at position 5 and 6, and the one you &amp;quot;looked at&amp;quot; is now on position 7. Do you continue the iteration on position 5 or is the next position 8? My opinion is that you should not look at the new elements and you have already looked at the &amp;quot;old&amp;quot; element ant 5, so the next one is at 8. You are free to make your own decision - just be clear about it.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Let&#039;s do something natural. Make it possible to add one FastaInstance to another using the &#039;&#039;&#039;+=&#039;&#039;&#039; operator, like this:&amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;FastaInstance1 += FastaInstance2&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;The headers and sequences in Fastainstance2 should be added (list extension) to the headers and sequences in FastaInstance1. Use the magic method [https://zetcode.com/python/dunder-iadd/ &#039;&#039;&#039;__iadd__&#039;&#039;&#039;].&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Implement the &#039;&#039;addition&#039;&#039;, using [https://zetcode.com/python/dunder-add/ &#039;&#039;&#039;__add__&#039;&#039;&#039;]. Addition creates a new Fasta instance, but leaves the originals untouched.&amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;FastaInstance3 = FastaInstance1 + FastaInstance2&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;The resulting Fasta object must contain the headers and sequences from FastaInstance1 and FastaInstance2 in that order. Note that this works as an alternative constructor. Now that the Fasta class is done, save it in a file, so you can import it for the next exercises.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# You can consider a &#039;&#039;&#039;Fasta&#039;&#039;&#039; instance as a &#039;&#039;set&#039;&#039; of headers/sequences. The sequences are obviously uniquely identified by the identifier in the header, which is what will be used as key in the set operations. In the rest of the exercises we will explore inheritance by making a new class called &#039;&#039;&#039;FastaSet&#039;&#039;&#039;, which inherits from the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class.&amp;lt;br&amp;gt;A) The original &#039;&#039;&#039;__init__&#039;&#039;&#039;, &#039;&#039;&#039;save&#039;&#039;&#039;, &#039;&#039;&#039;load&#039;&#039;&#039;, &#039;&#039;&#039;insert&#039;&#039;&#039;, the iteration and the corresponding &#039;&#039;&#039;deletethis&#039;&#039;&#039;, &#039;&#039;&#039;insertthis&#039;&#039;&#039;, &#039;&#039;&#039;verifythis&#039;&#039;&#039; and &#039;&#039;&#039;discardthis&#039;&#039;&#039; methods are fine to keep in the new class (meaning do nothing about them).&amp;lt;br&amp;gt;B) To help in the new class create a new getter method &#039;&#039;&#039;identifiers&#039;&#039;&#039;, which returns a list of identifiers from the header lines.&amp;lt;br&amp;gt;C) Override the &#039;&#039;&#039;content&#039;&#039;&#039; method such that it takes a set or list of identifiers and returns only the headers/sequences that corresponds to the identifiers in the list. If you do not specify a list/set of identifiers, it still returns all.&amp;lt;br&amp;gt;D) Override the &#039;&#039;&#039;delete&#039;&#039;&#039; method in a similar way - it deletes the headers/sequences that corresponds to the input.&amp;lt;br&amp;gt;E) Override the &#039;&#039;&#039;verify&#039;&#039;&#039; method in a similar way to &#039;&#039;&#039;content&#039;&#039;&#039; - it verifies the headers/sequences that corresponds to the input.&amp;lt;br&amp;gt;F) Override the &#039;&#039;&#039;discard&#039;&#039;&#039; method in a similar way to &#039;&#039;&#039;content&#039;&#039;&#039; - it discards the headers/sequences that corresponds to the input.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# As the new FastaSet class is set orientated, implement the following set operations in the class:&amp;lt;br&amp;gt;A) union, operator is &#039;&#039;&#039;|&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__or__&#039;&#039;&#039;.&amp;lt;br&amp;gt;B) intersection, operator is &#039;&#039;&#039;&amp;amp;&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__and__&#039;&#039;&#039;.&amp;lt;br&amp;gt;C) difference, operator is &#039;&#039;&#039;-&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__sub__&#039;&#039;&#039;.&amp;lt;br&amp;gt;D) symmetric difference, operator is &#039;&#039;&#039;^&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__xor__&#039;&#039;&#039;.&amp;lt;br&amp;gt;These are quite similar to the addition in exercise 4 - the operators are used in the same way and a new Fasta object is returned. The identity of the sequence depends on the identifier in the corresponding header. This is an example of operator overloading.&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;br /&gt;
# You continue to add the unique identifier control for all methods in Fasta and FastaSet, as mentioned last week.&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Intermediate_classes&amp;diff=263</id>
		<title>Intermediate classes</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Intermediate_classes&amp;diff=263"/>
		<updated>2026-03-18T09:06:30Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Exercises for extra practice */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Beginning classes]]&lt;br /&gt;
|Next: [[Beginning unit test]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_07-Classes.ppt Classes]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Example code - Classes]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Magic methods in classes&amp;lt;br&amp;gt;&lt;br /&gt;
Object Oriented Programming&amp;lt;br&amp;gt;&lt;br /&gt;
Polymorphism and inheritance&amp;lt;br&amp;gt;&lt;br /&gt;
Practical knowledge&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
The first four exercises will continue with the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class from last time.&lt;br /&gt;
# Use magic methods to add &#039;&#039;iteration&#039;&#039; and &#039;&#039;length&#039;&#039; evaluation (using &#039;&#039;&#039;__iter__&#039;&#039;&#039; and &#039;&#039;&#039;__len__&#039;&#039;&#039; magic methods) to the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class. Do this so you can write code like &amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;if len(MyFastaInstance) &amp;gt; 0:&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;for header, sequence in MyFastaInstance:&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;# Do something with header and sequence&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;print(header, sequence)&amp;lt;/div&amp;gt;The function &#039;&#039;&#039;len&#039;&#039;&#039; returns the number of sequences.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add the methods &#039;&#039;&#039;deletethis()&#039;&#039;&#039;, &#039;&#039;&#039;insertthis(header, sequence)&#039;&#039;&#039;, &#039;&#039;&#039;verifythis(alphabet)&#039;&#039;&#039; and &#039;&#039;&#039;discardthis(alphabet)&#039;&#039;&#039; to the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class. The methods should only work when &#039;&#039;iterating over an instance at the current item&#039;&#039;, i.e. they work when you are iterating over the fasta sequences on the &#039;&#039;current&#039;&#039; sequence and header, like this:&amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;for header, sequence in MyFastaInstance:&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;if not MyFastaInstance.verifythis(&amp;quot;DNA&amp;quot;):&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;MyFastaInstance.deletethis()&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;continue&amp;lt;br&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;# Do something with header and sequence&amp;lt;/div&amp;gt;As some may remember, it is normally impossible to successfully iterate straightforward through a list and delete and/or add elements to the list during the iteration. You have to make this possible. Hint: change the way your iteration works in the previous exercise.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Let&#039;s do something natural. Make it possible to add one FastaInstance to another using the &#039;&#039;&#039;+=&#039;&#039;&#039; operator, like this:&amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;FastaInstance1 += FastaInstance2&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;The headers and sequences in Fastainstance2 should be added (list extension) to the headers and sequences in FastaInstance1. Use the magic method [https://zetcode.com/python/dunder-iadd/ &#039;&#039;&#039;__iadd__&#039;&#039;&#039;].&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Implement the &#039;&#039;addition&#039;&#039;, using [https://zetcode.com/python/dunder-add/ &#039;&#039;&#039;__add__&#039;&#039;&#039;]. Addition creates a new Fasta instance, but leaves the originals untouched.&amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;FastaInstance3 = FastaInstance1 + FastaInstance2&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;The resulting Fasta object must contain the headers and sequences from FastaInstance1 and FastaInstance2 in that order. Note that this works as an alternative constructor. Now that the Fasta class is done, save it in a file, so you can import it for the next exercises.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# You can consider a &#039;&#039;&#039;Fasta&#039;&#039;&#039; instance as a &#039;&#039;set&#039;&#039; of headers/sequences. The sequences are obviously uniquely identified by the identifier in the header, which is what will be used as key in the set operations. In the rest of the exercises we will explore inheritance by making a new class called &#039;&#039;&#039;FastaSet&#039;&#039;&#039;, which inherits from the &#039;&#039;&#039;Fasta&#039;&#039;&#039; class.&amp;lt;br&amp;gt;A) The original &#039;&#039;&#039;__init__&#039;&#039;&#039;, &#039;&#039;&#039;save&#039;&#039;&#039;, &#039;&#039;&#039;load&#039;&#039;&#039;, &#039;&#039;&#039;insert&#039;&#039;&#039;, the iteration and the corresponding &#039;&#039;&#039;deletethis&#039;&#039;&#039;, &#039;&#039;&#039;insertthis&#039;&#039;&#039;, &#039;&#039;&#039;verifythis&#039;&#039;&#039; and &#039;&#039;&#039;discardthis&#039;&#039;&#039; methods are fine to keep in the new class (meaning do nothing about them).&amp;lt;br&amp;gt;B) To help in the new class create a new getter method &#039;&#039;&#039;identifiers&#039;&#039;&#039;, which returns a list of identifiers from the header lines.&amp;lt;br&amp;gt;C) Override the &#039;&#039;&#039;content&#039;&#039;&#039; method such that it takes a set or list of identifiers and returns only the headers/sequences that corresponds to the identifiers in the list. If you do not specify a list/set of identifiers, it still returns all.&amp;lt;br&amp;gt;D) Override the &#039;&#039;&#039;delete&#039;&#039;&#039; method in a similar way - it deletes the headers/sequences that corresponds to the input.&amp;lt;br&amp;gt;E) Override the &#039;&#039;&#039;verify&#039;&#039;&#039; method in a similar way to &#039;&#039;&#039;content&#039;&#039;&#039; - it verifies the headers/sequences that corresponds to the input.&amp;lt;br&amp;gt;F) Override the &#039;&#039;&#039;discard&#039;&#039;&#039; method in a similar way to &#039;&#039;&#039;content&#039;&#039;&#039; - it discards the headers/sequences that corresponds to the input.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# As the new FastaSet class is set orientated, implement the following set operations in the class:&amp;lt;br&amp;gt;A) union, operator is &#039;&#039;&#039;|&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__or__&#039;&#039;&#039;.&amp;lt;br&amp;gt;B) intersection, operator is &#039;&#039;&#039;&amp;amp;&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__and__&#039;&#039;&#039;.&amp;lt;br&amp;gt;C) difference, operator is &#039;&#039;&#039;-&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__sub__&#039;&#039;&#039;.&amp;lt;br&amp;gt;D) symmetric difference, operator is &#039;&#039;&#039;^&#039;&#039;&#039;, magic method is &#039;&#039;&#039;__xor__&#039;&#039;&#039;.&amp;lt;br&amp;gt;These are quite similar to the addition in exercise 4 - the operators are used in the same way and a new Fasta object is returned. The identity of the sequence depends on the identifier in the corresponding header. This is an example of operator overloading.&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;br /&gt;
# You continue to add the unique identifier control for all methods in Fasta and FastaSet, as mentioned last week.&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_classes&amp;diff=262</id>
		<title>Beginning classes</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_classes&amp;diff=262"/>
		<updated>2026-03-18T09:04:12Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Exercises for extra practice */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Comprehension, generators, iteration]]&lt;br /&gt;
|Next: [[Intermediate classes]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_07-Decorators.ppt Decorators]&amp;lt;br&amp;gt;&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_07-Classes.ppt Classes]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Example code - Classes]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Overview and motivation for classes&amp;lt;br&amp;gt;&lt;br /&gt;
Class structure&amp;lt;br&amp;gt;&lt;br /&gt;
Creating simple classes&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
The first two exercises are about simple math functions, just to get used to making a class. Remember to add code outside the class (man program), which test the new methods you make as you make them.&amp;lt;br&amp;gt;&lt;br /&gt;
The last exercises will be about the making of a fasta file handling class. As the exercises goes on the class can do more and more. The class methods need some decent input control and you need to think about what is required. Notice how versatile the class becomes, as you progress through the exercises.&lt;br /&gt;
# Create a class called &#039;&#039;&#039;MyMath&#039;&#039;&#039;. Add the following methods; &#039;&#039;&#039;cube&#039;&#039;&#039; which raises the input number to the power of 3 and returns it, &#039;&#039;&#039;factorial&#039;&#039;&#039; which computes the factorial of the input integer and returns it, &#039;&#039;&#039;collatz_steps&#039;&#039;&#039; takes a positive integer and repeatedly solves [https://en.wikipedia.org/wiki/Collatz_conjecture Collatz conjecture] until 1 is reached and returns how many steps/iterations of the collatz function it took. It takes 350 steps for the number 77031.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# In your &#039;&#039;&#039;MyMath&#039;&#039;&#039; class, add a method to supply a list of numbers to an instance of the class. Now make the methods &#039;&#039;&#039;maximum&#039;&#039;&#039;, &#039;&#039;&#039;minimum&#039;&#039;&#039; and &#039;&#039;&#039;average&#039;&#039;&#039; that returns the obvious result from the list.&amp;lt;br&amp;gt;&amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;mm = MyMath()&amp;lt;br&amp;gt;mm.supply(mylist)&amp;lt;br&amp;gt;print(&#039;Max is&#039;, mm.maximum())&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Create a class called &#039;&#039;&#039;Fasta&#039;&#039;&#039;. The purpose of the class is to do various kinds of manipulation of fasta files and sequences. Start with adding 3 methods to the class:&amp;lt;br&amp;gt;&#039;&#039;&#039;load(filename)&#039;&#039;&#039;, which gets a file name/path and loads the fasta file into internal instance lists with header and sequence.&amp;lt;br&amp;gt;&#039;&#039;&#039;save(filename)&#039;&#039;&#039;, which writes the internal instance header/sequence lists into a fasta file.&amp;lt;br&amp;gt;&#039;&#039;&#039;content()&#039;&#039;&#039;, which returns two lists; the headers and the sequences.&amp;lt;br&amp;gt;You can likely reuse part of your functions in exercise 1 and 2 from [[Functions, namespace, memory_management]].&amp;lt;br&amp;gt;Example use of the Fasta class:&amp;lt;br&amp;gt;&amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;myfasta = Fasta()&amp;lt;br&amp;gt;myfasta.load(&amp;quot;dna7.fsa&amp;quot;)&amp;lt;br&amp;gt;print(myfasta.content())&amp;lt;br&amp;gt;myfasta.save(&amp;quot;newfile.fsa&amp;quot;)&amp;lt;/div&amp;gt; You can consider modifying the &#039;&#039;&#039;__init__&#039;&#039;&#039; so if you supply a filename, it calls the &#039;&#039;&#039;load&#039;&#039;&#039; method automatically.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add a method &#039;&#039;&#039;delete([start[,end]])&#039;&#039;&#039;, which deletes entries in the headers and sequences. If called with no arguments like &#039;&#039;&#039;delete()&#039;&#039;&#039; it deletes all headers/sequences. If called with one argument like &#039;&#039;&#039;delete(start)&#039;&#039;&#039; it deletes the header and sequence at position &#039;&#039;start&#039;&#039;. If called with two arguments, it deletes headers and sequences from position &#039;&#039;start&#039;&#039; up to but not including position &#039;&#039;end&#039;&#039;. &#039;&#039;start&#039;&#039; and &#039;&#039;end&#039;&#039; can also be negative numbers, and in such case we count from the end of the lists, just like it works in normal list manipulations.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Modify the &#039;&#039;&#039;content()&#039;&#039;&#039; method, so it works similar to &#039;&#039;&#039;delete()&#039;&#039;&#039;. If called with no arguments like &#039;&#039;&#039;content()&#039;&#039;&#039; it returns 2 lists with all headers and sequences. If called with one argument like &#039;&#039;&#039;content(start)&#039;&#039;&#039; it returns the header and sequence at position &#039;&#039;start&#039;&#039;. If called with two arguments, it returns the headers and sequences from position &#039;&#039;start&#039;&#039; up to but not including position &#039;&#039;end&#039;&#039; as two lists. Be careful that you return a copy of the lists and not the lists themselves as then the headers and sequences in the instance can be modified unintended outside the instance.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add a method &#039;&#039;&#039;insert(header,sequence[,position])&#039;&#039;&#039;, which adds header and sequence to the instance lists. &#039;&#039;header&#039;&#039; and &#039;&#039;sequence&#039;&#039; can either be simple strings (single header and sequence) or lists of headers and sequences. If &#039;&#039;position&#039;&#039; is not given, then the addition takes place at the end of the existing headers/sequences. If &#039;&#039;position&#039;&#039; is given then insertion takes places at that position.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add a method &#039;&#039;&#039;verify(alphabet,[start[,end]])&#039;&#039;&#039;, which verifies sequence entries according to an alphabet. It works in a way similar to &#039;&#039;&#039;delete()&#039;&#039;&#039; and &#039;&#039;&#039;content()&#039;&#039;&#039; for the range of what should be verified. The method returns True if all entries in the range are verified (belonging to the alphabet), False otherwise.&amp;lt;br&amp;gt;The alphabet could be a DNA alphabet (ATCG), a protein alphabet or something derived from those. You should put your alphabets into class variables, as they are common for all instances, and not subject to change. Think about generalizing this exercise; You could have short names for your alphabet, you could make methods that could dynamically increase the number of alphabets the class handle. After all, an alphabet is just certain chars that your method has to verify that only those are present in the sequence. You can have any number of alphabets, and the verification method is still the same. Try on &#039;&#039;dnanoise.fsa&#039;&#039;.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add a method &#039;&#039;&#039;discard(alphabet,[start[,end]])&#039;&#039;&#039;, which discards sequence entries and corresponding headers if they do not match the given alphabet. It works in a way similar to &#039;&#039;&#039;delete()&#039;&#039;&#039; and &#039;&#039;&#039;content()&#039;&#039;&#039; for the range of what should be verified. Try on &#039;&#039;dnanoise.fsa&#039;&#039;.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;br /&gt;
# The Fasta class exercises all have one thing in common, that has not been addressed: The identifiers on the header line in a fasta file HAVE TO BE UNIQUE within the file - that is why they are identifiers. That also goes for the lists of headers/sequences in the Fasta class. The extra work you do here is to make sure this unique property of the identifiers are upheld whenever you add header/sequences to the Fasta object. This is only relevant upon &#039;&#039;&#039;load&#039;&#039;&#039; and &#039;&#039;&#039;insert&#039;&#039;&#039;ion. Observation: When you delete unique headers/sequences from a Fasta object, the leftovers will still be unique.&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_classes&amp;diff=261</id>
		<title>Beginning classes</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_classes&amp;diff=261"/>
		<updated>2026-03-18T09:00:15Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Exercises for extra practice */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Comprehension, generators, iteration]]&lt;br /&gt;
|Next: [[Intermediate classes]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_07-Decorators.ppt Decorators]&amp;lt;br&amp;gt;&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_07-Classes.ppt Classes]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Example code - Classes]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Overview and motivation for classes&amp;lt;br&amp;gt;&lt;br /&gt;
Class structure&amp;lt;br&amp;gt;&lt;br /&gt;
Creating simple classes&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
The first two exercises are about simple math functions, just to get used to making a class. Remember to add code outside the class (man program), which test the new methods you make as you make them.&amp;lt;br&amp;gt;&lt;br /&gt;
The last exercises will be about the making of a fasta file handling class. As the exercises goes on the class can do more and more. The class methods need some decent input control and you need to think about what is required. Notice how versatile the class becomes, as you progress through the exercises.&lt;br /&gt;
# Create a class called &#039;&#039;&#039;MyMath&#039;&#039;&#039;. Add the following methods; &#039;&#039;&#039;cube&#039;&#039;&#039; which raises the input number to the power of 3 and returns it, &#039;&#039;&#039;factorial&#039;&#039;&#039; which computes the factorial of the input integer and returns it, &#039;&#039;&#039;collatz_steps&#039;&#039;&#039; takes a positive integer and repeatedly solves [https://en.wikipedia.org/wiki/Collatz_conjecture Collatz conjecture] until 1 is reached and returns how many steps/iterations of the collatz function it took. It takes 350 steps for the number 77031.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# In your &#039;&#039;&#039;MyMath&#039;&#039;&#039; class, add a method to supply a list of numbers to an instance of the class. Now make the methods &#039;&#039;&#039;maximum&#039;&#039;&#039;, &#039;&#039;&#039;minimum&#039;&#039;&#039; and &#039;&#039;&#039;average&#039;&#039;&#039; that returns the obvious result from the list.&amp;lt;br&amp;gt;&amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;mm = MyMath()&amp;lt;br&amp;gt;mm.supply(mylist)&amp;lt;br&amp;gt;print(&#039;Max is&#039;, mm.maximum())&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Create a class called &#039;&#039;&#039;Fasta&#039;&#039;&#039;. The purpose of the class is to do various kinds of manipulation of fasta files and sequences. Start with adding 3 methods to the class:&amp;lt;br&amp;gt;&#039;&#039;&#039;load(filename)&#039;&#039;&#039;, which gets a file name/path and loads the fasta file into internal instance lists with header and sequence.&amp;lt;br&amp;gt;&#039;&#039;&#039;save(filename)&#039;&#039;&#039;, which writes the internal instance header/sequence lists into a fasta file.&amp;lt;br&amp;gt;&#039;&#039;&#039;content()&#039;&#039;&#039;, which returns two lists; the headers and the sequences.&amp;lt;br&amp;gt;You can likely reuse part of your functions in exercise 1 and 2 from [[Functions, namespace, memory_management]].&amp;lt;br&amp;gt;Example use of the Fasta class:&amp;lt;br&amp;gt;&amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;myfasta = Fasta()&amp;lt;br&amp;gt;myfasta.load(&amp;quot;dna7.fsa&amp;quot;)&amp;lt;br&amp;gt;print(myfasta.content())&amp;lt;br&amp;gt;myfasta.save(&amp;quot;newfile.fsa&amp;quot;)&amp;lt;/div&amp;gt; You can consider modifying the &#039;&#039;&#039;__init__&#039;&#039;&#039; so if you supply a filename, it calls the &#039;&#039;&#039;load&#039;&#039;&#039; method automatically.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add a method &#039;&#039;&#039;delete([start[,end]])&#039;&#039;&#039;, which deletes entries in the headers and sequences. If called with no arguments like &#039;&#039;&#039;delete()&#039;&#039;&#039; it deletes all headers/sequences. If called with one argument like &#039;&#039;&#039;delete(start)&#039;&#039;&#039; it deletes the header and sequence at position &#039;&#039;start&#039;&#039;. If called with two arguments, it deletes headers and sequences from position &#039;&#039;start&#039;&#039; up to but not including position &#039;&#039;end&#039;&#039;. &#039;&#039;start&#039;&#039; and &#039;&#039;end&#039;&#039; can also be negative numbers, and in such case we count from the end of the lists, just like it works in normal list manipulations.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Modify the &#039;&#039;&#039;content()&#039;&#039;&#039; method, so it works similar to &#039;&#039;&#039;delete()&#039;&#039;&#039;. If called with no arguments like &#039;&#039;&#039;content()&#039;&#039;&#039; it returns 2 lists with all headers and sequences. If called with one argument like &#039;&#039;&#039;content(start)&#039;&#039;&#039; it returns the header and sequence at position &#039;&#039;start&#039;&#039;. If called with two arguments, it returns the headers and sequences from position &#039;&#039;start&#039;&#039; up to but not including position &#039;&#039;end&#039;&#039; as two lists. Be careful that you return a copy of the lists and not the lists themselves as then the headers and sequences in the instance can be modified unintended outside the instance.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add a method &#039;&#039;&#039;insert(header,sequence[,position])&#039;&#039;&#039;, which adds header and sequence to the instance lists. &#039;&#039;header&#039;&#039; and &#039;&#039;sequence&#039;&#039; can either be simple strings (single header and sequence) or lists of headers and sequences. If &#039;&#039;position&#039;&#039; is not given, then the addition takes place at the end of the existing headers/sequences. If &#039;&#039;position&#039;&#039; is given then insertion takes places at that position.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add a method &#039;&#039;&#039;verify(alphabet,[start[,end]])&#039;&#039;&#039;, which verifies sequence entries according to an alphabet. It works in a way similar to &#039;&#039;&#039;delete()&#039;&#039;&#039; and &#039;&#039;&#039;content()&#039;&#039;&#039; for the range of what should be verified. The method returns True if all entries in the range are verified (belonging to the alphabet), False otherwise.&amp;lt;br&amp;gt;The alphabet could be a DNA alphabet (ATCG), a protein alphabet or something derived from those. You should put your alphabets into class variables, as they are common for all instances, and not subject to change. Think about generalizing this exercise; You could have short names for your alphabet, you could make methods that could dynamically increase the number of alphabets the class handle. After all, an alphabet is just certain chars that your method has to verify that only those are present in the sequence. You can have any number of alphabets, and the verification method is still the same. Try on &#039;&#039;dnanoise.fsa&#039;&#039;.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add a method &#039;&#039;&#039;discard(alphabet,[start[,end]])&#039;&#039;&#039;, which discards sequence entries and corresponding headers if they do not match the given alphabet. It works in a way similar to &#039;&#039;&#039;delete()&#039;&#039;&#039; and &#039;&#039;&#039;content()&#039;&#039;&#039; for the range of what should be verified. Try on &#039;&#039;dnanoise.fsa&#039;&#039;.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;br /&gt;
# The Fasta class exercises all have one thing in common, that has not been addressed: The identifiers on the header line in a fasta file HAVE TO BE UNIQUE within the file - that is why they are identifiers. That also goes for the lists of headers/sequences in the Fasta class. The extra work you do here is to make sure this unique property of the identifiers are upheld whenever you add header/sequences to the Fasta object. You do not have to check this when you delete headers/sequences because if they were unique before the deletion, they will also be after.&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
	<entry>
		<id>https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_classes&amp;diff=260</id>
		<title>Beginning classes</title>
		<link rel="alternate" type="text/html" href="https://teaching.healthtech.dtu.dk:443/22118/index.php?title=Beginning_classes&amp;diff=260"/>
		<updated>2026-03-18T08:57:44Z</updated>

		<summary type="html">&lt;p&gt;WikiSysop: /* Exercises for extra practice */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{| width=500  style=&amp;quot;font-size: 10px; float:right; margin-left: 10px; margin-top: -56px;&amp;quot;&lt;br /&gt;
|Previous: [[Comprehension, generators, iteration]]&lt;br /&gt;
|Next: [[Intermediate classes]]&lt;br /&gt;
|}&lt;br /&gt;
== Required course material for the lesson ==&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_07-Decorators.ppt Decorators]&amp;lt;br&amp;gt;&lt;br /&gt;
Powerpoint: [https://teaching.healthtech.dtu.dk/material/22118/22118_07-Classes.ppt Classes]&amp;lt;br&amp;gt;&lt;br /&gt;
Resource: [[Example code - Classes]]&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Subjects covered ==&lt;br /&gt;
Overview and motivation for classes&amp;lt;br&amp;gt;&lt;br /&gt;
Class structure&amp;lt;br&amp;gt;&lt;br /&gt;
Creating simple classes&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Exercises to be handed in ==&lt;br /&gt;
The first two exercises are about simple math functions, just to get used to making a class. Remember to add code outside the class (man program), which test the new methods you make as you make them.&amp;lt;br&amp;gt;&lt;br /&gt;
The last exercises will be about the making of a fasta file handling class. As the exercises goes on the class can do more and more. The class methods need some decent input control and you need to think about what is required. Notice how versatile the class becomes, as you progress through the exercises.&lt;br /&gt;
# Create a class called &#039;&#039;&#039;MyMath&#039;&#039;&#039;. Add the following methods; &#039;&#039;&#039;cube&#039;&#039;&#039; which raises the input number to the power of 3 and returns it, &#039;&#039;&#039;factorial&#039;&#039;&#039; which computes the factorial of the input integer and returns it, &#039;&#039;&#039;collatz_steps&#039;&#039;&#039; takes a positive integer and repeatedly solves [https://en.wikipedia.org/wiki/Collatz_conjecture Collatz conjecture] until 1 is reached and returns how many steps/iterations of the collatz function it took. It takes 350 steps for the number 77031.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# In your &#039;&#039;&#039;MyMath&#039;&#039;&#039; class, add a method to supply a list of numbers to an instance of the class. Now make the methods &#039;&#039;&#039;maximum&#039;&#039;&#039;, &#039;&#039;&#039;minimum&#039;&#039;&#039; and &#039;&#039;&#039;average&#039;&#039;&#039; that returns the obvious result from the list.&amp;lt;br&amp;gt;&amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;mm = MyMath()&amp;lt;br&amp;gt;mm.supply(mylist)&amp;lt;br&amp;gt;print(&#039;Max is&#039;, mm.maximum())&amp;lt;/div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Create a class called &#039;&#039;&#039;Fasta&#039;&#039;&#039;. The purpose of the class is to do various kinds of manipulation of fasta files and sequences. Start with adding 3 methods to the class:&amp;lt;br&amp;gt;&#039;&#039;&#039;load(filename)&#039;&#039;&#039;, which gets a file name/path and loads the fasta file into internal instance lists with header and sequence.&amp;lt;br&amp;gt;&#039;&#039;&#039;save(filename)&#039;&#039;&#039;, which writes the internal instance header/sequence lists into a fasta file.&amp;lt;br&amp;gt;&#039;&#039;&#039;content()&#039;&#039;&#039;, which returns two lists; the headers and the sequences.&amp;lt;br&amp;gt;You can likely reuse part of your functions in exercise 1 and 2 from [[Functions, namespace, memory_management]].&amp;lt;br&amp;gt;Example use of the Fasta class:&amp;lt;br&amp;gt;&amp;lt;div style=&amp;quot;font-family:&#039;Courier New&#039;&amp;quot;&amp;gt;myfasta = Fasta()&amp;lt;br&amp;gt;myfasta.load(&amp;quot;dna7.fsa&amp;quot;)&amp;lt;br&amp;gt;print(myfasta.content())&amp;lt;br&amp;gt;myfasta.save(&amp;quot;newfile.fsa&amp;quot;)&amp;lt;/div&amp;gt; You can consider modifying the &#039;&#039;&#039;__init__&#039;&#039;&#039; so if you supply a filename, it calls the &#039;&#039;&#039;load&#039;&#039;&#039; method automatically.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add a method &#039;&#039;&#039;delete([start[,end]])&#039;&#039;&#039;, which deletes entries in the headers and sequences. If called with no arguments like &#039;&#039;&#039;delete()&#039;&#039;&#039; it deletes all headers/sequences. If called with one argument like &#039;&#039;&#039;delete(start)&#039;&#039;&#039; it deletes the header and sequence at position &#039;&#039;start&#039;&#039;. If called with two arguments, it deletes headers and sequences from position &#039;&#039;start&#039;&#039; up to but not including position &#039;&#039;end&#039;&#039;. &#039;&#039;start&#039;&#039; and &#039;&#039;end&#039;&#039; can also be negative numbers, and in such case we count from the end of the lists, just like it works in normal list manipulations.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Modify the &#039;&#039;&#039;content()&#039;&#039;&#039; method, so it works similar to &#039;&#039;&#039;delete()&#039;&#039;&#039;. If called with no arguments like &#039;&#039;&#039;content()&#039;&#039;&#039; it returns 2 lists with all headers and sequences. If called with one argument like &#039;&#039;&#039;content(start)&#039;&#039;&#039; it returns the header and sequence at position &#039;&#039;start&#039;&#039;. If called with two arguments, it returns the headers and sequences from position &#039;&#039;start&#039;&#039; up to but not including position &#039;&#039;end&#039;&#039; as two lists. Be careful that you return a copy of the lists and not the lists themselves as then the headers and sequences in the instance can be modified unintended outside the instance.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add a method &#039;&#039;&#039;insert(header,sequence[,position])&#039;&#039;&#039;, which adds header and sequence to the instance lists. &#039;&#039;header&#039;&#039; and &#039;&#039;sequence&#039;&#039; can either be simple strings (single header and sequence) or lists of headers and sequences. If &#039;&#039;position&#039;&#039; is not given, then the addition takes place at the end of the existing headers/sequences. If &#039;&#039;position&#039;&#039; is given then insertion takes places at that position.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add a method &#039;&#039;&#039;verify(alphabet,[start[,end]])&#039;&#039;&#039;, which verifies sequence entries according to an alphabet. It works in a way similar to &#039;&#039;&#039;delete()&#039;&#039;&#039; and &#039;&#039;&#039;content()&#039;&#039;&#039; for the range of what should be verified. The method returns True if all entries in the range are verified (belonging to the alphabet), False otherwise.&amp;lt;br&amp;gt;The alphabet could be a DNA alphabet (ATCG), a protein alphabet or something derived from those. You should put your alphabets into class variables, as they are common for all instances, and not subject to change. Think about generalizing this exercise; You could have short names for your alphabet, you could make methods that could dynamically increase the number of alphabets the class handle. After all, an alphabet is just certain chars that your method has to verify that only those are present in the sequence. You can have any number of alphabets, and the verification method is still the same. Try on &#039;&#039;dnanoise.fsa&#039;&#039;.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
# Add a method &#039;&#039;&#039;discard(alphabet,[start[,end]])&#039;&#039;&#039;, which discards sequence entries and corresponding headers if they do not match the given alphabet. It works in a way similar to &#039;&#039;&#039;delete()&#039;&#039;&#039; and &#039;&#039;&#039;content()&#039;&#039;&#039; for the range of what should be verified. Try on &#039;&#039;dnanoise.fsa&#039;&#039;.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Exercises for extra practice ==&lt;br /&gt;
# The Fasta class exercises all have one thing in common, that has not been addressed: The identifiers on the header line in a fasta file HAVE TO BE UNIQUE within the file - that is why they are identifiers. That also goes for the lists of headers/sequences in the Fasta class. The extra work you do here is to make sure this unique property of the identifiers are upheld whenever you add header/sequences to the Fasta object.&lt;/div&gt;</summary>
		<author><name>WikiSysop</name></author>
	</entry>
</feed>