Introduction to Advanced Python

Class

Jul 2024
@1995parham
python-logo

Class


    class Person:
        '''
        Person class is used for representation person
        '''
        def say(self):
            print("Hello")
    

Multi-Inheritance


    class SubClassName(ParentClass1[, ParentClass2]):
        """
        Optional class documentation string
        """
        # class code
    

C3 Linearization

The C3 superclass linearization is an algorithm used primarily to obtain the order in which methods should be inherited (the "linearization") in the presence of multiple inheritance, and is often termed Method Resolution Order (MRO).

@staticmethod

A static method does not receive an implicit first argument.

@classmethod

A class method receives the class as implicit first argument, just like an instance method receives the instance.

@classmethod


    class C:
        @classmethod
        def f(cls, arg1, arg2, ...): ...
    

@staticmethod


    class C:
        @staticmethod
        def f(arg1, arg2, ...): ..
    

<Code Time.py>

By using @classmethod create inner class database.

Duck Typing

It is a term used in dynamic languages that do not have strong typing.

The idea is that you don't need a type in order to invoke an existing method on an object - if a method is defined on it, you can invoke it.

If it looks like a duck and quacks like a duck, it's a duck

Boolean

__bool__

Called to implement truth value testing and the built-in operation bool()

Boolean (cont'd)


    class IsBool:
        def __init__(self, age):
            self.age = age

        def __bool__(self):
            return self.age > 20

    if is_bool:
        print("is_bool.age > 20")
    else:
        print("is_bool.age <= 20")
    
code bool.py

Wrap

Extend

Invent

@abc.abstractmethod

@abc.abstractclassmethod

@abc.abstractstaticmethod

<Code Time.py>

Create Person class with abstract walk method and say method, then create Runner class that inherits from Person.

Person Abstract Class


    import abc


    class Person(abc.ABC):
        def say(self):
            print('Hello')

        @abc.abstractmethod
        def walk(self):
            raise NotImplementedError()
    

ABC

This module provides the infrastructure for defining abstract base classes (ABCs) in Python

  • A way to overload isinstance() and issubclass().

class abc.ABC
An abstract base class can be created by simply deriving from ABC.

Meta-Class

meta-class

Meta-Class (cont'd)

Classes are callable. These objects normally act as factories for new instances of themselves, but variations are possible for class types that override __new__(). The arguments of the call are passed to __new__() and, in the typical case, to __init__() to initialize the new instance.

Meta-Class (cont'd)

Instances of arbitrary classes can be made callable by defining a __call__() method in their class.

Meta-Class (cont'd)

Once the appropriate metaclass has been identified, then the class namespace is prepared. If the metaclass has a __prepare__ attribute, it is called as namespace = metaclass.__prepare__(name, bases, **kwds) (where the additional keyword arguments, if any, come from the class definition).

Meta-Class (Python 3.0)


    class ParhamClass(type):

        def __new__(cls, name, bases, namespace, **kwargs):
            print('cls: ', cls)
            print('name: ', name)
            print('bases: ', bases)
            print('namespace: ', namespace)
            print('kwargs: ', kwargs)
            result = super().__new__(cls, name, bases, namespace)

            return result


    class A(str, when='never', metaclass=ParhamClass):
        name = 'parham'

        def one(): pass

        def two(): pass

        def three(): pass

        def four(): pass
    
code meta-class-1.py

Meta-Class (Python 3.6)


    class BotFather:
        bots = []

        @classmethod
        def __init_subclass__(cls, name, **kwargs):
            super().__init_subclass__(**kwargs)
            print("New subclass from BotFather")
            BotFather.bots.append(cls)

    class HelloBot(BotFather, name='hello'):
        def __init__(self):
            print('New instance from HelloBot')
    
code meta-class-2.py

<Code Time.py>

Let's create plugin system, write parent class which holds a collection of loaded plugin.

Learn class customization in deep

See Me

What are descriptors?

Descriptors were introduced to Python way back in version 2.2.

They provide the developer with the ability to add managed attributes to objects.

The Descriptor Protocol

If any of these methods are defined for an object, it is said to be a descriptor.

  • __set__
  • __get__
  • __del__

__get__(self, instance, owner)

Called to get the attribute of the owner class (class attribute access) or of an instance of that class (instance attribute access). owner is always the owner class, while instance is the instance that the attribute was accessed through, or None when the attribute is accessed through the owner. This method should return the (computed) attribute value or raise an AttributeError exception.

__set__(self, instance, value)

Called to set the attribute on an instance instance of the owner class to a new value, value.

__del__(self, instnace)

Called to delete the attribute on an instance instance of the owner class.

__set_name__(self, owner, name)

New in version 3.6.

Called at the time the owning class owner is created. The descriptor has been assigned to name.


    class RevealAccess:
        '''
        A data descriptor that sets and returns values
        normally and prints a message logging their access.
        '''

        def __init__(self, initval=None, name='var'):
            self.val = initval
            self.name = name

        def __get__(self, instance, owner):
            print('Retrieving', self.name, instance, owner)
            return self.val

        def __set__(self, instance, val):
            print('Updating', self.name, instance, val)
            self.val = val

        def __set_name__(self, owner, name):
            print('Set name', name, owner)
    
code descriptor.py

<Code Time.py>

Let's see SQLAlchemy Object-Relational Mapping (ORM)

Properties

Calling property() is a succinct way of building a data descriptor that triggers function calls upon access to an attribute.


    property(fget=None, fset=None, fdel=None, doc=None) -> property attribute
    

Properties in Action


    class Celsius:
        def __init__(self, temperature = 0):
            self._temperature = temperature

        def to_fahrenheit(self):
            return (self.temperature * 1.8) + 32

        @property
        def temperature(self):
            print("Getting value")
            return self._temperature

        @temperature.setter
        def temperature(self, value):
            if value < -273:
                raise ValueError("Temperature below -273 is not possible")
            print("Setting value")
            self._temperature = value
    
code properties.py
Fork me on GitHub