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.
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.
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:
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:
Super simple illustration
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
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)
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
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.
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)
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:
Thank you for your attention! The library on the Github—https://github.com/dmytrostriletskyi/accessify
#python