Because the abstract class of Python was unexpectedly special I want to explain a little carefully based on the explanation of the metaclass
Python's Abstract is a bit special, something called a metaclass Define a class by specifying ABCmeta (metaclass will be explained later)
from abc import ABC, ABCMeta, abstractmethod
class Person(metaclass = ABCMeta):
pass
By the way, because there is also an ABC class, this does not specify the meta class Basically this is easier to understand because it only inherits
class Person(ABC):
pass
Add @abstractmethod to the method you want to abstract
@abstractmethod
def greeting(self):
pass
Implement in inherited class
class Yamada(Person):
def greeting(self):
print("Hello, this is Yamada.")
Of course, if you do not implement it and instantiate it, an error will occur
class Yamada(Person):
pass
yamada = Yamada()
---------------------------------------------------------------------------------------------------------------
TypeError: Can't instantiate abstract class Yamada with abstract methods greeting
That's how to use the basic abstract class
A little off here, talk about metaclasses, skip if you're not interested
What is a metaclass?
In object-oriented programming, a metaclass is a class whose instance is a class. A metaclass defines a class that is an instance of it, and further defines the behavior of an instance of that class, just as a regular class defines the behavior of that instance.
[Source]: Metaclass-wikipedia </ cite>
I'm not sure, so if you give an example In fact, Python's hidden function (?) Allows you to dynamically define a class from type.
def test_init(self):
pass
Test_Class = type('Test_Class', (object, ), dict(__init__ = test_init, ))
Of course, you can instantiate this class
Test_Class_instance = Test_Class()
print(type(Test_Class_instance))
-------------------------------------------------------------------------------------------------------------------
<class '__main__.Test_Class'>
Test_Class generated by type at this time can be said to be an instance and a class definition. This is a metaclass in a narrow sense
Surprisingly, the classes that are usually casually defined in Python It can be an instance of type type
class define_class:
pass
print(type(define_class))
-------------------------------------------------------------------------------------------------------------------
<class 'type'>
After all, Python defines a class internally
type ('classname', ...) </ code> is called automatically.
It turns out that
Change the class that can be called automatically A super powerful function is the identity of \ _ \ _ metaclass \ _ \ _, ABCmeta is a class that inherits type ABC meta source code
By the way, metaclass is too powerful and changes the language specification itself. It ’s black magic, so you should n’t abuse it.
@abstractclassmethod、@abstractstaticmethod、@abstractproperty Have both been deprecated, so you need to add more decorators
class Person(ABC):
@staticmethod
@abstractmethod
def age_fudging(age):
pass
@classmethod
@abstractmethod
def weight_fudging(cls, weight):
pass
@property
@abstractmethod
def age(self):
pass
@age.setter
@abstractmethod
def age(self, val):
pass
@property
@abstractmethod
def weight(self):
pass
@weight.setter
@abstractmethod
def weight(self, val):
pass
class Yamada(Person):
def __init__(self):
self.__age = 30
self.__weight = 120
#10-year-old mackerel reading
@staticmethod
def age_fudging(age):
return age - 10
#20kg mackerel reading
@classmethod
def weight_fudging(cls, weight):
return weight - 20
@property
def age(self):
return Yamada.age_fudging(self.__age)
@age.setter
def age(self):
return
@property
def weight(self):
return self.weight_fudging(self.__weight)
@weight.setter
def weight(self):
return
y = Yamada()
print("name:Yamada age:{0}body weight:{1}".format(y.age, y.weight))
-----------------------------------------------------------------------------------------------------------------
name:Yamada age:20 weight:100
It's been a little longer, but the basic usage is the same However, please note that if you do not make @abstractmethod below, you will get an error.
By the way, in Python you can make it private by prepending "__" to the member variable.
Multiple inheritance is available in Python, but what about abstract classes?
As you know, multiple inheritance has various problems (diamond inheritance problem, name collision). Basically, it is safer not to use multiple inheritance, but if you use it, it is required to be a Mixin class.
What is a mixin in an object-oriented programming language? It is a class that provides functions by being inherited by subclasses and is not intended to operate independently. Depending on the language There may be a mixin as a separate system from what the language calls a class or inheritance (detailed in the #Variations section).
[Source]: Mixin --wikipedia </ cite>
Also quoted from Wikipedia, but in short A class that doesn't work properly unless inherited </ b> Abstract classes and interfaces are also Mixin classes
So, we will create a beastman class that inherits cats and humans
class Cat(ABC):
@abstractmethod
def mew(self):
pass
#Also in Person
@abstractmethod
def sleep(self):
pass
class Person(ABC):
@abstractmethod
def greeting(self):
pass
#Also in Cat
@abstractmethod
def sleep(self):
pass
class Therianthrope(Person, Cat):
def greeting(self):
print("Hello")
def mew(self):
print("Meow")
def sleep(self):
print("zzz…")
cat_human = Therianthrope()
cat_human.greeting()
cat_human.mew()
cat_human.sleep()
-----------------------------------------------------------------------------------------------------------------
Hello
Meow
zzz…
You can see that it works without difficulty even with ABC meta This time, the name of the method called sleep is collided. There is no problem because it is not implemented in the inheritance source
Finally, as written on the official Python website You should be careful about collisions between metaclasses
The concern with multi-stage inheritance is whether ABCmeta will inherit when inherited In other words, when Python inherits an abstract class, it becomes an abstract class. The point of becoming
In conclusion, ABCmeta inherits, and if you inherit an abstract class, it becomes an abstract class.
class Animal(metaclass=ABCMeta):
pass
class Person(Animal):
pass
class Yamada(Person):
pass
print(type(Person))
print(type(Yamada))
-------------------------------------------------------------------------------------------------------------------
<class 'abc.ABCMeta'>
<class 'abc.ABCMeta'>
After all, where is the abstract method? It means that it should be implemented
class Animal(metaclass=ABCMeta):
@abstractmethod
def run(self):
pass
class Person(Animal):
pass
class Yamada(Person):
def run(self):
print("12km / h")
y = Yamada()
y.run()
-------------------------------------------------------------------------------------------------------------------
12km / h
It's been a long time, but at the end it's a rough sketch of the abstract class Introducing an example of usage that can also be used in Python
Actually, even in Python, you can specify the type of formal argument and return value. I specified "Person", which is the parent class and abstract class created earlier, as the formal argument type. Let's create a function called fall_asleep
from abstract import Person
import time
def fall_asleep(p:Person):
sleep_time = p.sleep()
time.sleep(sleep_time)
print("!")
class Person(ABC):
@abstractmethod
def greeting(self):
pass
@abstractmethod
def sleep(self) -> float:
pass
Abstract classes, typing, etc. are no longer Python. This kind of technique is used when creating a slightly larger software in Python. It's useful for something.
For example, the person making fall_asleep can see the actual state of the concrete class (Yamada, Ikeda, Yosida). Don't worry (don't know), no matter how much you change, as long as the function called sleep meets the requirements Since it is completed, it can be said that fall_asleep depends on the abstract class (Person) rather than the concrete class.
This is what the architecture calls the "Dependency Reversal Principle (DIP)". Say
The following items are applicable to DIP
After all, relying on abstract classes is better You can achieve a robust architecture.
y = Yamada()
fall_asleep(y)
-------------------------------------------------------------------------------------------------------------------
zzz…
!
Recommended Posts