Python создать класс type

Python type Class

Summary: in this tutorial, you’ll learn about the Python type class and understand how Python uses the type class to create other classes.

Introduction to the Python type class

In Python, a class is an object of the class type . For example, the following defines the Person class with two methods __init__ and greeting :

class Person: def __init__(self, name, age): self.name = name self.age = age def greeting(self): return f'Hi, I am . I am year old.'Code language: Python (python)

The Person class is an object of the class type as shown in the following statement:

print(type(Person))Code language: Python (python)
class 'type'>Code language: Python (python)

The Person class is an instance of the type class:

print(isinstance(Person, type))Code language: Python (python)

Python uses the type class to create other classes. The type class itself is a callable. The following shows one of the constructors of the type class:

type(name, bases, dict) -> a new typeCode language: Python (python)

The constructor has three parameters for creating a new class:

  • name : is the name of the class e.g., Person
  • bases is a tuple that contains the base classes of the new class. For example, the Person inherits from the object class, so the bases contains one class (object,)
  • dict is the class namespace

Technically, you can use the type class to create a class dynamically. Before doing it, you need to understand how Python creates the classes.

When the Python interpreter encounters a class definition in the code, it will:

  • First, extract the class body as string.
  • Second, create a class dictionary for the class namespace.
  • Third, execute the class body to fill up the class dictionary.
  • Finally, create a new instance of type using the above type() constructor.

Let’s emulate the steps above to create a Person class dynamically:

First, extract the class body:

class_body = """ def __init__(self, name, age): self.name = name self.age = age def greeting(self): return f'Hi, I am . I am year old.' """Code language: Python (python)

Second, create a class dictionary:

class_dict = <>Code language: Python (python)

Third, execute the class body and fill up the class dictionary:

exec(class_body, globals(), class_dict)Code language: Python (python)

The exec() function executes the class body and fills up the global and class namespaces.

Finally, create a new Person class using the type constructor:

Person = type('Person', (object,), class_dict)Code language: Python (python)

Note that the Person is a class, which is also an object. The Person class inherits from the object class and has the namespace of the class_dict .

The following shows the type of the Person class which is the type class:

class 'type'>Code language: Python (python)

And it is an instance of the type class:

print(isinstance(Person, type))Code language: Python (python)
TrueCode language: Python (python)

The class_dict has the two functions __init__ and greeting :

'__init__': 0x0000024E28465160>, 'greeting': 0x0000024E28931550>>Code language: Python (python)

The Person.__dict__ also contains these functions :

mappingproxy('__dict__': '__dict__' of 'Person' objects>, '__doc__': None, '__init__': 0x00000165F7725160>, '__module__': '__main__', '__weakref__': '__weakref__' of 'Person' objects>, 'greeting': 0x00000165F7F71550>>)Code language: Python (python)

In this example, Python creates the type class dynamically, which is the same as the one that you define statically in the code.

Because the type class creates other classes, we often refer to it as a metaclass. A metaclass is a class used to create other classes.

Summary

  • In Python, a class is an instance of the type class.
  • The type class creates other classs, therefore, it is called a metaclass.

Источник

Динамическое определение класса в Python

Под динамическим определением объекта можно понимать определение во время исполнения. В отличие от статического определения, которое используется в привычном определении класса с помощью ключевого слова class , динамическое определение использует встроенный класс type .

Метакласс type

Класс type часто используется для получения типа объекта. Например так:

Но у него есть другое применение. Он может инициализировать новые типы. Как известно, всё в Python – объект. Из этого следует, что у всех определений имеются типы, включая классы и объекты. Например:

Может быть не совсем понятно, почему классу присваивается тип класса type , в отличие от его экземпляров:

Объекту a в качестве типа присваивается класс. Так интерпретатор обрабатывает объект как экземпляр класса. Сам же класс имеет тип класса type потому, что он наследует его от базового класса object :

Класс object наследуют все классы по умолчанию, то есть:

Определяемый класс наследует базовый в качестве типа. Однако, это не объясняет, почему базовый класс object имеет тип класса type . Дело в том, что type – это метакласс. Как это уже известно, все классы наследуют базовый класс object , который имеет тип метакласса type . Поэтому, все классы так же имеют этот тип, включая сам метакласс type :

Это «конечная точка типизации» в Python. Цепочка наследования типов замыкается на классе type . Метакласс type служит базой для всех классов в Python. В этом несложно убедиться:

builtins = [list, dict, tuple] for obj in builtins: type(obj)

Класс – это абстрактный тип данных, а его экземпляры имеют ссылку на класс в качестве типа.

Инициализация новых типов с помощью класса type

При проверке типов класс type инициализируется с единственным аргументом:

При этом он возвращает тип объекта. Однако в классе реализован другой способ инициализации с тремя аргументами, который возвращает новый тип:

type(name, bases, dict) -> new type 

Параметры инициализации класса type

  • name
    Строка, которая определяет имя нового класса (типа).
  • bases
    Кортеж базовых классов (классов, которые унаследует новый класс).
  • dict
    Словарь с атрибутами будущего класса. Обычно со строками в ключах и вызываемых типах в значениях.

Динамическое определение класса

Инициализируем класс нового типа, предоставив все необходимые аргументы и вызываем его:

MyClass = type("MyClass", (object, ), dict()) MyClass

С новым классом можно работать как обычно:

Причём, способ эквивалентен обычному определению класса:

Динамическое определение атрибутов класса

В пустом классе мало смысла, поэтому возникает вопрос: как добавить атрибуты и методы?

Чтобы ответить на этот вопрос, рассмотрим изначальный код инициализации:

MyClass = type(“MyClass”, (object, ), dict()) 

Обычно, атрибуты добавляются в класс на стадии инициализации в качестве третьего аргумента – словаря. В словаре можно указать имена атрибутов и значения. Например, это может быть переменная:

MyClass = type(“MyClass”, (object, ), dict(foo=“bar”) m = MyClass() m.foo 'bar'

Динамическое определение методов

В словарь можно передать и вызываемые объекты, например методы:

def foo(self): return “bar” MyClass = type(“MyClass”, (object, ), dict(foo=foo)) m = MyClass() m.foo 'bar'

У этого способа есть один существенный недостаток – необходимость определять метод статически (думаю, что в контексте задач метапрограммирования, это можно рассматривать как недостаток). Кроме этого, определение метода с параметром self вне тела класса выглядит странно. Поэтому вернёмся к динамической инициализации класса без атрибутов:

MyClass = type(“MyClass”, (object, ), dict()) 

После инициализации пустого класса, можно добавить в него методы динамически, то есть, без явного статического определения:

code = compile('def foo(self): print(“bar”)', "", "exec") 

compile – это встроенная функция, которая компилирует исходный код в объект. Код можно выполнить функциями exec() или eval() .

Параметры функции compile

  • source
    Исходный код, может быть ссылкой на модуль.
  • filename
    Имя файла, в который скомпилируется объект.
  • mode
    Если указать «exec» , то функция скомпилирует исходный код в модуль.

Объект code нужно преобразовать в метод. Так как метод – это функция, то начнём с преобразования объекта класса code в объект класса function . Для этого импортируем модуль types :

from types import FunctionType, MethodType 

Я импортирую MethodType , так как он понадобится в дальнейшем для преобразования функции в метод класса.

function = FunctionType(code.co_consts[0], globals(), “foo”) 

Параметры метода инициализации класса FunctionType

  • code
    Объект класса code . code.co_consts[0] – это обращение к дискриптору co_consts класса code , который представляет из себя кортеж с константами в коде объекта. Представьте себе объект code как модуль с одной единственной функцией, которую мы пытаемся добавить в качестве метода класса. 0 – это её индекс, так как она единственная константа в модуле.
  • globals()
    Словарь глобальных переменных.
  • name
    Необязательный параметр, определяющий название функции.

Далее необходимо добавить эту функцию в качестве метода класса MyClass :

MyClass.foo = MethodType(function, MyClass) 

Достаточно простое выражение, которое назначает нашу функцию методом класса MyClass .

Предупреждение

В 99% случаев можно обойтись статическим определением классов. Однако концепция метапрограммирования хорошо раскрывает внутреннее устройство Python. Скорее всего вам будет сложно найти применение описанных здесь методов, хотя в моей практике такой случай, все же, был.

А вы работали с динамическими объектами? Может быть в других языках?

Ссылки

Источник

Читайте также:  Sudo update alternatives config python
Оцените статью