{ "cells": [ { "cell_type": "markdown", "id": "4184a769551cb96a", "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "source": [ "# Class method <-> static method \n", "\n", "## Class methods\n", "\n", "Method is bound to a class, not an object of a class, hence does not require the\n", "creation of a class instance.\n", "\n", "-> The class method works with the class since its parameter is the class itself.\n", "\n", "### Convert a method into a class method (via `classmethod()`)" ] }, { "cell_type": "code", "execution_count": null, "id": "8f9b15e3381891c8", "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "class Person:\n", " age = 25\n", "\n", " def print_age(cls):\n", " print('The age is: ', cls.age)\n", "\n", "Person.print_age = classmethod(Person.print_age)\n", "Person.print_age()" ] }, { "cell_type": "markdown", "id": "cd8d10ef74bc56e1", "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "source": [ "### Use class method for 'overloading' a constructor\n", "\n", "Since overloading a method is not available in Python, classmethods are used to\n", "return a class object" ] }, { "cell_type": "code", "execution_count": null, "id": "b604a9000940955", "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "from datetime import date\n", "\n", "# random Person\n", "class Person:\n", " def __init__(self, name, age):\n", " self.name = name\n", " self.age = age\n", "\n", " @classmethod\n", " def from_birth_year(cls, name, birth_year):\n", " return cls(name, date.today().year - birth_year)\n", "\n", " def display(self):\n", " print(self.name + \"'s age is: \" + str(self.age))\n", "\n", "person = Person('Adam', 19)\n", "person.display()\n", "\n", "person1 = Person.from_birth_year('John', 1985)\n", "person1.display()" ] }, { "cell_type": "markdown", "id": "abd8d897808f17d3", "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "source": [ "Here an additional constructor was created by declaring the from_birth_year()\n", "function a class method via the `@classmethod` decorator.\n", "\n", "### Correct instance creation in inheritance\n", "\n", "When you derive a new class from a class, which contains a class method returning\n", "a class object (cls), the correct class is instantiated, whereas a similar static\n", "method will always return the **hardcoded** base class object." ] }, { "cell_type": "code", "execution_count": null, "id": "52b2e306983e9d8", "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "from datetime import date\n", "\n", "# random Person\n", "class Person:\n", " def __init__(self, name, age):\n", " self.name = name\n", " self.age = age\n", "\n", " @staticmethod\n", " def from_fathers_age(name, father_age, father_person_age_diff):\n", " return Person(name, date.today().year - father_age + father_person_age_diff)\n", "\n", " @classmethod\n", " def from_birth_year(cls, name, birth_year):\n", " return cls(name, date.today().year - birth_year)\n", "\n", " def display(self):\n", " print(self.name + \"'s age is: \" + str(self.age))\n", "\n", "class Man(Person):\n", " sex = 'Male'\n", "\n", "man = Man.from_birth_year('John', 1985)\n", "print(isinstance(man, Man))\n", "\n", "man1 = Man.from_fathers_age('John', 1965, 20)\n", "print(isinstance(man1, Man))" ] }, { "cell_type": "markdown", "id": "85867a973771bc", "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "source": [ "Here, the static method returns a 'Person' object, since the return value is\n", "hardcoded as Person(), whereas the class method returns a Man() object, since it\n", "was executed from within the Man class and 'cls' is defined as returning class.\n", "\n", "| static -> hardcoded class (Person)\n", "| class -> versatile class (cls)\n", "\n", "## Static methods\n", "\n", "Same as class methods, static methods are bound to a class, not an object, hence\n", "don't require the creation of an object of a class in order to use it.\n", "\n", "-> A static method knows nothing about the class and just deals with the parameters\n", "(cls context is missing)\n", "\n", "### Convert a method into a static method (via `staticmethod()`)" ] }, { "cell_type": "code", "execution_count": null, "id": "405527a6f4b79b9f", "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "class Mathematics:\n", "\n", " def add_numbers(x, y):\n", " return x + y\n", "\n", "# create addNumbers static method\n", "Mathematics.add_numbers = staticmethod(Mathematics.add_numbers)\n", "\n", "print('The sum is:', Mathematics.add_numbers(5, 10))" ] }, { "cell_type": "markdown", "id": "63de6343657cb7db", "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "source": [ "So far, the same as with classmethod(), except that the class method requires\n", "the 'cls' class parameter as function parameter.\n", "\n", "**Static methods cannot access any properties of a class**. But when it\n", "makes sense, that a function still belongs to a class, a static method is used.\n", "\n", "Static methods are used, if you don't want subclasses to be able to change/override\n", "a specific implementation of a method." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.2" } }, "nbformat": 4, "nbformat_minor": 5 }