<jupyter_start><jupyter_text>Классы и экземпляры классаКлассы представляют собой средства объединения данных и поведения. Каждый новый класс задает новый тип данных и позволяет создавать объекты или экземпляры этого типа. Экземпляр может содержать атрибуты, необходимые для хранения данных и характеризующие состояние объекта, а также методы для изменения состояния, которые определяются классом. Класс является одним из ключевых понятий в объектно-ориентированном программировании (ООП).По сравнению с другими языками программирования, механизм классов Python характерен минимумом нового синтаксиса и семантики. Классы Python предоставляют все стандартные возможности объектно-ориентированного программирования: механизм наследования классов позволяет использовать несколько базовых классов, способствуя повторному использованию кода, производный класс может переопределять любые методы своего базового класса или классов, а метод может вызывать метод базового класса с тем же именем. Объекты могут содержать произвольные количества и виды данных. Как и в случае с модулями, классы обладают динамической природой Python: они создаются во время выполнения и могут быть изменены в дальнейшем после создания.Синтаксис определения класса довольно прост. Для этого используется ключевое слово ```class```, за которым следует имя класса. Имена классов принято писать, используя ```CamelCase``` или «верблюжью» нотацию.Определения классов, также как и определения функций должны располагаться до их использования.В Python классы это тоже объекты (всё – объекты!). При определении класса создается объект класса, который связывается с переменной (имя класса) в глобальной области видимости, имеющей тоже имя, что и имя класса.Объекты классов поддерживают несколько операций: создание экземпляров и ссылки на атрибуты.<jupyter_code># простейший класс
class A:
    pass

# класс это вызываемый объект, т.е. он реализует специальный 
# метод __call__, который позволяет использовать круглые скобки
print(f'{hasattr(A, "__call__") = }')

# создание экземпляров класса путем вызова класса как функции
foo = A()
bar = A()
baz = A()

# каждый экземпляр имеет тип соответствующий классу
print(f'{type(foo) = }')
print(f'{type(bar) = }')
print(f'{type(baz) = }')

# все экземпляры это разные! объекты
print(f'{foo is bar is baz = }')
attrs = []
magic_attrs = []
for attr in dir(A):
    if attr.startswith('__') and attr.endswith('__'):
        magic_attrs.append(attr)
    else:
        attrs.append(attr)

# примитивный вариант класса ничего не содержит 
# кроме некоторых специальных атрибутов
print(f'Обычные атрибуты: {attrs}')
print(f'"Маггические" атрибуты: {magic_attrs}')<jupyter_output>Обычные атрибуты: []
"Маггические" атрибуты: ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']<jupyter_text>Для проверки принадлежности экземпляра конкретному классу стоит использовать функцию ```isinstance```, а не другие способы.<jupyter_code>print(f'{type(foo) == A = }')  # Нет
print(f'{type(foo) is A = }')  # Нет
print(f'{isinstance(foo, A) = }')  # Да!<jupyter_output>type(foo) == A = True
type(foo) is A = True
isinstance(foo, A) = True<jupyter_text>Классы могут содержать строку документации, которая располагается сразу после объявления класса и использоваться для вывода справки с помощью функции ```help(B)```. Строка документации храниться в специальном атрибуте ```__doc__```, получить к нему доступ можно через точечную нотацию ```B.__doc__```.<jupyter_code>class B:
    """Это класс B"""
    pass

print(f'{B.__doc__ = }')
help(B)<jupyter_output>B.__doc__ = 'Это класс B'
Help on class B in module __main__:

class B(builtins.object)
 |  Это класс B
 |  
 |  Data descriptors defined here:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)
{'fraction_non_alphanumeric': 0.09462729912875122, 'fraction_numerical': 0.0, 'mean_word_length': 5.876871880199667, 'pattern_counts': {'":': 0, '<': 10, '<?xml version=': 0, '>': 10, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '337909', 'license': 'MIT', 'n_tokens_mistral': 1606, 'n_tokens_neox': 1941, 'n_words': 445, 'path': 'python_pd/06_classes/01_class.ipynb', 'repo_name': 'Alexey-smurf/python-bp', 'size': '4132'}