Private method without underscores and interfaces in Python

Private method without underscores and interfaces in Python

I am a fan of the engineering design, including class members access modifiers and interfaces, but Python does not have them from the box. I have created own ones. The reference to the library on the Github is presented at the end of the article.

I am a fan of the engineering design, including class members access modifiers and interfaces, but Python does not have them from the box. I have created own ones. The reference to the library on the Github is presented at the end of the article.

Class members access modifiers

They restrict access to the object’s methods and parent class methods from the child class in case of inheritance. When you call the method under the private access modifier, you get the corresponding error message. You cannot use details of the realization (as you shouldn’t get access to your car’s engine) of the class or change its data (e.g. counting variables), you can only use public functionality.

A private method can be only called inside the particular class, a protectedmethod inside the particular class and by its child classes.

How declare private and protected methods in Python

In Python, «privacy» depends on «consenting adults» levels of agreement. A single leading underscore means you’re not supposed to get access to it from the outside. Two leading underscores carry the message even more seriously. But, in the end, it still depends on social convention and consensus.

class Car:


        def _start_engine(self):
            return "Engine's sound."


        def run(self):
            return self._start_engine()




    if __name__ == '__main__':
        car = Car()


        assert "Engine's sound." == car.run()
        assert "Engine's sound." == car._start_engine()

The following cons are there:

  • Imaging method *_start_engine *modifies any class variables or save any state. If you call this method, it could break the class behavior.
  • If you need to call protected method anyway, you should really spend the time to research — «will I break something in my another code by accessing it?».
  • In most cases, you use the class methods from libraries. A class provides public functionality which relies on private methods. Private methods could be changed (refactored, divided by separated code, etc.), without changing the public functionality. Author of the library still offers the promised functionality, but what about you?
  • Imagine your teammate wrote the class with public and private functionality. Another teammate uses a private method outside the class. If you refactor this class, you should pay attention on the class and the code which uses its private functionality. Instead of one place you get two.
  • And you should track your team members do not access private and protected methods on code review. And spend time for it.

    How you declare protected methods using the library

from accessify import protected




    class Car:


        @protected
        def start_engine(self):
            return "Engine's sound."


        def run(self):
            return self.start_engine()




    if __name__ == '__main__':
        car = Car()


        assert "Engine's sound." == car.run()


        car.start_engine()

When you call the method *start_engine, *you get an exception — method is inaccessible due to its protection level.

Traceback (most recent call last):
      File "examples/access/private.py", line 24, in <module>
        car.start_engine()
      File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/accessify/main.py", line 92, in private_wrapper
        class_name=instance_class.__name__, method_name=method.__name__,
    accessify.errors.InaccessibleDueToItsProtectionLevelException: Car.start_engine() is 
      inaccessible due to its protection level

So, using the library:

  • You do not use ugly underscores.
  • Instead, you have a native Python way — decorators.
  • Move responsibility of checking the accessing to the methods from human to machine.

    How does it work

  1. Decorators private *and *protected are the top placed decorators. They are executed before the method is executed.

  1. Using built-in Python library called inspect, decorator fetches the current frame—inspect.currentframe(). Current frame, as an object, has the following attributes: a namespace and a reference to the previous frame (a frame that calls current frame).

Super simple illustration

  1. Then decorator use inspect.currentframe().f_back *to know if the frame that called the current frame is located in the class body. Looking for attribute *self in the namespace. If it is presented there, the decorator was called from the body of the class. If it isn’t presented, inaccessible due to its protection level exception is raised.

    Interfaces

Interface—it is a set of the methods signatures (name, incoming arguments). Interfaces could be implemented by classes. If a class implements an interface, a class is required to implement its methods signatures completely. It allows to declaring high-level requirements for application without a detailed description of the implementation. Below the interface of human is presented—human eats food and goes somewhere.

class HumanInterface:


        @staticmethod
        def eat(food, *args, allergy=None, **kwargs):
            pass

        def walk(self, destination):
            pass

How you declare interfaces using the library

Methods

If a class implements an interface, a class is required to implement allinterface’s** methods**. In the example below, interface «HumanInterface» contains the method «eat», class «Human» implements the interface, but does not implement the method «eat».

from accessify import implements




    class HumanInterface:


        @staticmethod
        def eat(food, *args, allergy=None, **kwargs):
            pass




    if __name__ == '__main__':


        @implements(HumanInterface)
        class Human:


            pass

The script will be finished with the following exception:

Traceback (most recent call last): File "examples/interfaces/single.py", line 18, in <module> @implements(HumanInterface) File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/accessify/interfaces.py", line 66, in decorator interface_method_arguments=interface_method.arguments_as_string,accessify.errors.InterfaceMemberHasNotBeenImplementedException: class Human does not implement interface member HumanInterface.eat(food, args, allergy, kwargs)

Arguments

If a class implements an interface, a class is required to implement allinterface’s methods incoming arguments. In the example below, interface «HumanInterface» contains the method «eat» that accept 4 arguments, class «Human» implements the interface, implements the method «eat», but only with 1 argument.

from accessify import implements




    class HumanInterface:


        @staticmethod
        def eat(food, *args, allergy=None, **kwargs):
            pass




    if __name__ == '__main__':


        @implements(HumanInterface)
        class Human:


            @staticmethod
            def eat(food):
                pass

The script will be finished with the following exception:

Traceback (most recent call last):
      File "examples/interfaces/single_arguments.py", line 16, in <module>
        @implements(HumanInterface)
      File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/accessify/interfaces.py", line 87, in decorator
        interface_method_arguments=interface_method.arguments_as_string,
    accessify.errors.InterfaceMemberHasNotBeenImplementedWithMismatchedArgumentsException: 
      class Human implements interface member HumanInterface.eat(food, args, allergy, kwargs) 
      with mismatched arguments

Access modifiers

If a class implements an interface, a class is required to implement all the interface’s methods, their incoming arguments, and access modifiers. In the example below, interface «HumanInterface» contains the private method «eat», class «Human» implements the interface, but implement the method «eat» without private access modifier.

from accessify import implements, private




    class HumanInterface:


        @private
        @staticmethod
        def eat(food, *args, allergy=None, **kwargs):
            pass




    if __name__ == '__main__':


        @implements(HumanInterface)
        class Human:


            @staticmethod
            def eat(food, *args, allergy=None, **kwargs):
                pass

The script will be finished with the following exception:

Traceback (most recent call last):
      File "examples/interfaces/single_access.py", line 18, in <module>
        @implements(HumanInterface)
      File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/accessify/interfaces.py", line 77, in decorator
        interface_method_name=interface_method.name,
    accessify.errors.ImplementedInterfaceMemberHasIncorrectAccessModifierException: 
      Human.eat(food, args, allergy, kwargs) mismatches 
      HumanInterface.eat() member access modifier.

Multiple interfaces

A class could implement multiple interfaces. If a class implements multiple interfaces, a class is required to implement all interface’s methods, their incoming arguments, and access modifiers. In the example below, interface «Human» implements the method «eat» from the interface «HumanBasicsInterface», but does not implement the method «love» from the interface «HumanSoulInterface».

from accessify import implements




    class HumanSoulInterface:


        def love(self, who, *args, **kwargs):
            pass




    class HumanBasicsInterface:


        @staticmethod
        def eat(food, *args, allergy=None, **kwargs):
            pass




    if __name__ == '__main__':


        @implements(HumanSoulInterface, HumanBasicsInterface)
        class Human:


            def love(self, who, *args, **kwargs):
                pass

The script will be finished with the following exception:

Traceback (most recent call last): File "examples/interfaces/multiple.py", line 19, in <module> @implements(HumanSoulInterface, HumanBasicsInterface) File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/accessify/interfaces.py", line 66, in decorator interface_method_arguments=interface_method.arguments_as_string,accessify.errors.InterfaceMemberHasNotBeenImplementedException: class Human does not implement interface member HumanBasicsInterface.eat(food, args, allergy, kwargs)

Declare exceptions required to be thrown

There is a feature when you declare exceptions required to be thrown by the class method. In the example below, the method «love» from the interface «HumanInterface» says that implementation should raise «HumanDoesNotExistError» and «HumanAlreadyInLoveError» errors. But method «love» in the class «Human» does not raise one of them.

from accessify import implements, throws




    class HumanDoesNotExistError(Exception):
        pass




    class HumanAlreadyInLoveError(Exception):
        pass




    class HumanInterface:


        @throws(HumanDoesNotExistError, HumanAlreadyInLoveError)
        def love(self, who, *args, **kwargs):
            pass




    if __name__ == '__main__':


        @implements(HumanInterface)
        class Human:


            def love(self, who, *args, **kwargs):


                if who is None:
                    raise HumanDoesNotExistError('Human whom need to love does not exist')

The script will be finished with the following exception:

Traceback (most recent call last):
      File "examples/interfaces/throws.py", line 21, in <module>
        @implements(HumanInterface)
      File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/accessify/interfaces.py", line 103, in decorator
        class_method_arguments=class_member.arguments_as_string,
    accessify.errors.DeclaredInterfaceExceptionHasNotBeenImplementedException: 
      Declared exception HumanAlreadyInLoveError by HumanInterface.love() 
      member has not been implemented by Human.love(self, who, args, kwargs)

So, using the library:

  • You can implement one or multiple interfaces.
  • Interfaces incorporate with access modifiers.
  • You do not need to create interfaces based on the ABC module in Python.
  • When you define an abstract class with the ABC module, *you will get errors during the *calling the class. If you use interfaces, you will get errors during defining a class-implementation.

    How does it work

  1. Decorator implements *using the **inspect.getmembers() *fetch **allmembers of the classes and their interfaces.
  2. With inspect.signature() **decorator fetch each **method’s arguments.
  3. Iterate the methods in the loop and compare methods names, arguments, access modifiers, and declare exceptions required to be thrown.

Thank you for your attention! The library on the Github—https://github.com/dmytrostriletskyi/accessify

python

Bootstrap 5 Complete Course with Examples

Bootstrap 5 Tutorial - Bootstrap 5 Crash Course for Beginners

Nest.JS Tutorial for Beginners

Hello Vue 3: A First Look at Vue 3 and the Composition API

Building a simple Applications with Vue 3

Deno Crash Course: Explore Deno and Create a full REST API with Deno

How to Build a Real-time Chat App with Deno and WebSockets

Convert HTML to Markdown Online

HTML entity encoder decoder Online

Basic Data Types in Python | Python Web Development For Beginners

In the programming world, Data types play an important role. Each Variable is stored in different data types and responsible for various functions. Python had two different objects, and They are mutable and immutable objects.

How To Compare Tesla and Ford Company By Using Magic Methods in Python

Magic Methods are the special methods which gives us the ability to access built in syntactical features such as ‘<’, ‘>’, ‘==’, ‘+’ etc.. You must have worked with such methods without knowing them to be as magic methods. Magic methods can be identified with their names which start with __ and ends with __ like __init__, __call__, __str__ etc. These methods are also called Dunder Methods, because of their name starting and ending with Double Underscore (Dunder).

Python Programming: A Beginner’s Guide

Python is an interpreted, high-level, powerful general-purpose programming language. You may ask, Python’s a snake right? and Why is this programming language named after it?

Hire Python Developers

Are you looking for experienced, reliable, and qualified Python developers? If yes, you have reached the right place. At **[HourlyDeveloper.io](https://hourlydeveloper.io/ "HourlyDeveloper.io")**, our full-stack Python development services...

Python any: How to Check If Element is Iterable or Not

Python any() function returns True if any element of an iterable is True otherwise any() function returns False. The syntax is any().