Специальный метод: 4.3. Специальные методы научного исследования

Специальные методы научного исследования: особенности и описание

Специальные методы научного исследования являются способом познания объективной реальности. Этот способ предполагает некую последовательность приемов, действий, операций. С учетом содержания рассматриваемых объектов выделяют методы социально-гуманитарного исследования и естествознания.

Классификация

Специальные методы исследования подразделяют по научным отраслям:

  • медицинские;
  • математические;
  • социально-экономические;
  • биологические;
  • правовые.

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

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

Деление по степени общности

С учетом сферы использования и степени общности выделяют:

  • философские (всеобщие), которые применимы в любых науках, на всех этапах познания;
  • общенаучные, используемые в естественных, гуманитарных, технических сферах;
  • частные, применяемые для родственных научных областей;
  • специальные, создаваемые для конкретной области научного познания.

Важные термины

Специальные методы исследования связаны с процедурой и методикой научного познания. Техникой исследования называют сумму специальных приемов для применения определенного метода. Процедурой исследования считается последовательность действий, вариант организации непосредственного исследования. Методикой считается сумма приемов и способов познания. Любое исследование в науке проводится определенными способами и приемами, с учетом конкретных правил.

Методология

Ее составляют специальные методы, приемы. Данное понятие используют в двух значениях:

  • сумма методов, которые применяются в некой сфере деятельности: политике, науке;
  • учение о научном варианте познания.

В любой науке существует собственная методология. В научном исследовании — это система правил, принципов, приемов, которые предназначены для качественного решения познавательных задач.

Уровни методологии

Существуют разные методы специального образования, позволяющие воспитывать и развивать подрастающее поколение. Выделяют такие уровни методологии:

  • всеобщая часть, являющаяся универсальной для всех наук, в содержание которой входят общенаучные и философские методы познания;
  • частная методология характерна для общенаучных вариантов познания, к примеру, для государственно-правовых явлений;
  • методология научных исследований определенной науки, в основе которой есть общенаучные, философские, специальные, частные методы познания, например, теоретическая основа коррекционной педагогики.

Философские методы

Специальные научные методы философского плана – это метафизический и диалектический подходы. Они связаны с разными философскими системами. К примеру, Гете соединял метод с идеализмом, Маркс – с материализмом.

Диалектика при рассмотрении явлений и предметов рекомендует исходить из конкретных принципов:

  • изучать объекты в свете диалектических законов: единства и борьбы противоположностей, отрицания отрицания, перехода количественных изменений в качественные;
  • объяснять, описывать, прогнозировать рассматриваемые процессы и явления, основываясь на философских категориях: особенного, общего, единичного, явления и сущности, следствия и причины, случайного и необходимого;
  • относиться к исследуемому объекту как к объективной реальности;
  • рассматривать явления и предметы: в развитии, изменении;
  • проверять на практике полученные знания.

Общенаучные методы

Общие и специальные методы распределяют на несколько групп. Среди общенаучных выделяют теоретические, общелогические, эмпирические. Общелогическими вариантами считают синтез, анализ, дедукцию, индукцию, аналогию. Они востребованы в современной педагогике. Анализ представляет собой разделение на части объекта исследования. Например, специальные методы обучения выделяют для каждой предметной области, рассматриваемой в отечественной педагогике.

В качестве разновидностей анализа отмечают классификацию и периодизацию. Они широко применяются в естественных науках. К примеру, при рассмотрении неорганических соединений учащиеся знакомятся с отдельными классами, дают каждому из них характеристику.

Синтезом называют объединение отдельных сторон, частей анализируемого объекта в одно целое. Специальные методы выделяют в каждой сфере, они зависят от ее специфики и предназначения.

Индукция и дедукция

Среди педагогических приемов и методов, без которых сложно представить образование, выделим индукцию и дедукцию.

Индукцией является выведение частного из общей теории, движение в науке от общих положений к конкретным явлениям и предметам.

Методы специальной психологии предполагают «выведение» какой-то идеи из иных мыслей. Аналогия, которая предполагает получение информации о явлениях и предметах на базе того, что они обладают сходством с другими объектами, применяется в преподавании учебных дисциплин, а также в воспитательной деятельности.

Среди методов теоретического уровня, которые применяют педагоги в своей работе, интерес представляют гипотетический, аксиоматический виды, а также системный анализ, обобщение.

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

Гипотетический метод – это вариант исследования с применением научной гипотезы, предположения причины, которая характеризует это следствие либо объясняет существование предмета (явления). В качестве разновидности метода выступает гипотетико-дедуктивный способ исследования, суть которого заключается в формировании системы дедуктивно связанных друг с другом гипотез, из которых выводят утверждения об эмпирических закономерностях.

Структура гипотетико-дедуктивного метода

Поскольку он применяется в современной педагогике, остановимся на нем подробнее. В его структуру входят:

  • выдвижение предположения о закономерностях и причинах анализируемых предметов и методов;
  • отбор самых вероятных версий из множества догадок;
  • выведение с помощью дедукции из предположения заключения;
  • экспериментальное подтверждение следствий, выведенных из гипотезы.

Какие еще специально-педагогические методы используют в настоящее время в отечественной педагогике?

Формализацией называют отображение предмета либо явления в знаковом виде. Это актуально в химии, математике, логике при изучении тем школьной программы. Применение искусственного формализованного языка способствует устранению недостатков естественного языка: неточности, неопределенности, многозначности.

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

Формализация – это основа программирования и алгоритмизации. С помощью данного метода осуществляется компьютеризация информации, происходит процесс исследования конкретного знания.

Особенности абстракции

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

В рамках абстрагирования отделяют второстепенные связи и свойства рассматриваемого процесса (явления) от основных характеристик. Существует несколько видов абстрагирования:

  • отождествление, предполагающее выделение общих отношений и свойств рассматриваемых предметов, объединение предметов в отдельный класс;
  • изолирование, касающееся выделения некоторых отношений и свойств, рассмотрение их в виде самостоятельных предметов исследования.

Выделяют и иные виды абстракции: актуальная бесконечность, потенциальная осуществимость.

Обобщение является способом установления отношений и свойств явлений и предметов, выявлением общего понятия, в котором могут отражаться основные признаки анализируемого класса. Данный метод научного исследования основывается на философских категориях особенного, общего, единичного.

Исторический метод состоит в выявлении исторических признаков, воссоздании процесса на их основе, сопровождающемся раскрытием логики исследования в хронологическом порядке.

Системный метод предполагает анализ системы, то есть рассмотрение определенной суммы идеальных либо материальных объектов, их связей с внешним миром. Эти взаимодействия и взаимосвязи способствуют появлению новых параметров системы, отсутствующих у ее объектов.

Заключение

Методы исследования являются основой для анализа, изучения, построения закономерностей, протекающих в природе, технике, общественной жизни. Например, интерес представляют методы: измерения, наблюдения, эксперимента, описания, моделирования, сравнения. Наблюдение предполагает способ познания, базируемый на непосредственном восприятии явлений и предметов через чувственное восприятие. В рамках наблюдения у исследователя появляется информация о внешних признаках предмета (явления). Описание связано с их фиксацией, к примеру, в процессе осуществления измерения либо наблюдения. Существует несколько разновидностей описания. При непосредственном исследователь указывает и воспринимает признаки рассматриваемого объекта. При опосредованной форме он отмечает признаки, которые воспринимались иными лицами.

Отдельного внимания заслуживает экспериментальный метод. Он предполагает воспроизведение процесса, явления, сопровождается выдвижением гипотезы (предположения). Исследовательская деятельность характерна не только для научно-исследовательских лабораторий и университетов. В рамках обновления содержания отечественного школьного образования этот вид научной деятельности стал широко использоваться и в ходе обучения и развития подрастающего поколения. Юные исследователи учатся самостоятельно проводить небольшие эксперименты, оформлять их результаты, анализировать их.

ФГОС нового поколения, внедренные в дошкольное и школьное российское образование, предполагают обязательное применение исследовательских методов во всех предметных областях. В настоящее время существует множество научных методов, благодаря которым в науке и технике объясняются свойства и признаки предметов, создаются новые подходы в педагогике, совершенствуются приемы работы в психологии. Сложно представить себе полноценное развитие общества, формирование подрастающего поколения без применения разнообразных научных методов в образовательном процессе.

Объектно-ориентированное программирование. Специальные методы.

Содержание

  • Статические и классовые методы
  • Специальные методы (магические) вида _ < param > _
  • Задачи:
    • Задача 1:
    • Задача 2:

Существуют 2 особенных декоратора, которые можно повесить на функции внутри класса: — @staticmethod — @classmethod

Декоратор @staticmethod определяет обычную функцию (статический метод) в пространстве имён класса. У него нет обязательного параметра-ссылки self. Может быть полезно для вспомогательных функций, чтобы не мусорить пространство имён модуля. Доступ к таким методам можно получить как из экземпляра класса, так и из самого класса:

class SomeClass(object):
  @staticmethod
  def hello():
    print("Hello, world")
SomeClass.hello()  # Hello, world
obj = SomeClass()
obj.hello()        # Hello, world
Hello, world
Hello, world

Декоратор @classmethod создаёт метод класса и требует обязательную ссылку на класс (cls). Поэтому объект класса явно передаётся через первый параметр как это с параметром self происходит для обычных методов. Также как и для self, переданный cls может отличаться от класса, в котором определён класс-метод (может быть потомок). Часто используется для создания альтернативных конструкторов.

class SomeClass(object):
  @classmethod
  def hello(cls):
    print('Hello, класс {}'.format(cls.__name__))
SomeClass.hello() # Hello, класс SomeClass
Hello, класс SomeClass

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

class Person:
    def __init__(self, name, age):
        self. name = name
        self.age = age
    # classmethod чтобы создать объект по году рождения,
    # "альтернативный" конструктор
    @classmethod
    def fromBirthYear(cls, name, year):
        return cls(name, 2019 - year)
    # статический метод,чтобы проверить совершеннолетие
    @staticmethod
    def isAdult(age):
        return age > 18
person1 = Person('Петя', 21)
person2 = Person.fromBirthYear('Петя', 1996)
print(person1.age)
print(person2.age)
# print the result
print(Person.isAdult(22))
21
23
True

Важно понимать, что ни classmethod ни staticmethod НЕ являются функциями от конкретного объекта класса и соответственно не принимают self. Подчеркнем еще раз их различия: — classmethod принимает cls как первый параметр, тогда как staticmethod в специальных аргументах не нуждается — classmethod может получать доступ или менять состояние класса, в то время как staticmethod нет — staticmethod в целом вообще ничего не знают про класс. Это просто функция над аргументами, объявленная внутри класса.

В Python существует огромное количество специальных методов, расширяющих возможности пользовательских классов. Например, можно определить вид объекта на печати, его «официальное» строковое представление или поведение при сравнениях.

Эти методы могут эмулировать поведение встроенных классов, но при этом они необязательно существуют у самих встроенных классов. Например, у объектов int при сложении не вызывается метод add. Таким образом, их нельзя переопределить.

Давайте для примера переопределим стандартную операцию сложения. Рассмотрим класс Vector, используемый для представления радиус-векторов на координатной плоскости, и определим в нем поля-координаты: x и y. Также очень хотелось бы определить для векторов операцию +, чтобы их можно было складывать столь же удобно, как и числа или строки.

Для этого необходимо перегрузить операцию +: определить функцию, которая будет использоваться, если операция + будет вызвана для объекта класса Vector. Для этого нужно определить метод

add класса Vector, у которого два параметра: неявная ссылка self на экземпляр класса, для которого она будет вызвана (это левый операнд операции +) и явная ссылка other на правый операнд:

class Vector():
    def __init__(self, x = 0, y = 0):
        self. x = x
        self.y = y
    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)
A = Vector(1, 2)
B = Vector(3, 4)
C = A + B
print(C.x, C.y)
4 6

Теперь при вызове оператора A + B Питон вызовет метод A.add(B), то есть вызовет указанный метод, где self = A, other = B.

Аналогично можно определить и оставшиеся операции. Полезной для переопределения является операция <. Она должна возвращать логическое значение True, если левый операнд меньше правого или False в противном случае (также в том случае, если объекты равны). Для переопределения этого операнда нужно определить метод

lt (less than):

class Vector:
    def __lt__(self, other):
        return self.x < other.x or self.x == other.x and self.y < other.y

В этом примере оператор вернет True, если у левого операнда поле x меньше, чем у правого операнда, а также если поля x у них равны, а поле y меньше у левого операнда.

После определения оператора <, появляется возможность упорядочивать объекты, используя этот оператор. Теперь можно сортировать списки объектов при помощи метода sort() или функции sorted, при этом будет использоваться именно определенный оператор сравнения <.

Список основных перегружаемых операторов

МетодИспользование
Операторы сравнения 
__lt__(self, other)x < y
__le__(self, other)x <= y
__eq__(self, other)x == y
__ne__(self, other)x != y
__gt__(self, other)x > y
__ge__(self, other)x >= y
Арифметические операторы
Сложение
__add__(self, other)x + y
__radd__(self, other)y + x
__iadd__(self, other)x += y
Вычитание
__sub__(self, other)x — y
__rsub__(self, other)y — x
__isub__(self, other)x -= y
Умножение
__mul__(self, other)x * y
__rmul__(self, other)y * x
__imul__(self, other)x *= y
Математическое умножение (например векторное)
__matmul__(self, other)x @ y
__rmatmul__(self, other)y @ x
__imatmul__(self, other)x @= y
Деление
__truediv__(self, other)x / y
__rtruediv__(self, other)y / x
__itruediv__(self, other)x /= y
Целочисленное деление
__floordiv__(self, other)x // y
__rfloordiv__(self, other)y // x
__ifloordiv__(self, other)x //= y
__divmod__(self, other)divmod(x, y)
Остаток
__mod__(self, other) x % y
__rmod__(self, other)y % x
__imod__(self, other)x %= y
Возведение в степень
__pow__(self, other)x ** y
__rpow__(self, other)y ** x
__ipow__(self, other)x **= y
Отрицание, модуль
__pos__(self)+x
__neg__(self)-x
__abs__(self)abs(x)
__len__(self)len(x)
Преобразование к стандартным типам
__int__(self)int(x)
__float__(self)float(x)
__complex__(self)complex(x)
__str__(self)str(x)
__round__(self, digits = 0)round(x, digits)
Блок with
__enter__(self)
 
__exit__(self) 

Задача 1:

Реализуйте свой класс Complex для комплексных чисел, аналогично встроенной реализации complex:

  1. Добавьте инициализатор класса
  2. Реализуйте основные математические операции
  3. Реализуйте операцию модуля (abs, вызываемую как |c|)
  4. Оба класса должны давать осмысленный вывод как при print, так и просто при вызове в ячейке

Задача 2:

  1. Создайте класс Vector с полями x, y, z определите для него конструктор, метод __str__, необходимые арифметические операции. Реализуйте конструктор, который принимает строку в формате «x,y».
  2. Программа получает на вход число N, далее координаты N точек. Доопределите в классе Vector недостающие операторы, найдите и выведите координаты точки, наиболее удаленной от начала координат.
  3. Используя класс Vector выведите координаты центра масс данного множества точек.
  4. Даны два вектора. Выведите площадь параллелограмма, построенного на заданных векторах.
  5. Даны три вектора. Выведите объём параллелепипеда, построенного на заданных векторах.
  6. Среди данных точек найдите три точки, образующие треугольник с наибольшим периметром. Выведите данный периметр.
  7. Среди данных точек найдите три точки, образующие треугольник с наибольшей площадью. Выведите данную площадь.

Python — имена специальных методов

Существует несколько специальных методов, необходимых для реализация класса. У каждого из них есть имя, которое начинается и заканчивается с двойным подчеркиванием. Эти имена методов используются неявно Питон. Раздел 3.3 языка Python Ссылка содержит полный список этих специальных методов. имена.

Мы подробно рассмотрим имена специальных методов в главе 24,

Создание или расширение типов данных . А пока мы рассмотрим несколько специальных имена методов, которые используются интенсивно.

__в этом__

Метод __init__ класса является вызывается Python для инициализации вновь созданного объекта

__str__

Метод __str__ класса является вызывается всякий раз, когда Python печатает объект. Это метод, используемый встроенной функцией str .

__repr__

Метод __repr__ класса является используется, когда мы хотим увидеть детали значений объекта. Этот метод используется repr функция.

__cmp__

Когда мы сортируем список объектов, cmp функция использует метод __cmp__ каждого объект.

Инициализация объекта с помощью __инициализация__ . Когда вы создаете объект, Python создает объект а также вызвать метод объекта __init__ . Этот функция может создавать переменные экземпляра объекта и выполнять любые другая одноразовая инициализация. Обычно выделяют два вида переменные экземпляра, созданные методом __init__: переменные на основе параметров и переменных, которые не зависят ни от параметры.

Вот пример описания компании, которое может подойти для оценки эффективности акций. В этом примере все экземпляры переменные ( self.name , self.symbol , собственная цена ) основаны на параметрах __init__ метод.

 класс Компания (объект):
    def __init__( self, name, symbol, stockPrice ):
        self.name= имя
        self.symbol= символ
        self.price= stockPrice
    def valueOf (я, акции):
        возврат акций * self.price 

Когда мы создаем экземпляр Company, мы используем такой код это.

 c1= Company( "General Electric", "GE", 30.125 ) 

Это обеспечит три значения параметров __в этом__.

Строковое значение объекта с __str__ . Вызывается функция метода __str__ всякий раз, когда экземпляр класса необходимо преобразовать в строку. Как правило, это occus, когда мы используем стр функцию на объекте. Неявно, когда мы ссылаемся на объект в печать заявление, стр оценивается функция. Другой пример: wРассмотрите это определение класса Карточка .

 Карта класса ( объект ):
    def __init__(я, ранг, костюм):
        self.rank = ранг
        self.suit = костюм
        self.points = ранг
    деф трудно(я):
        возврат селф.баллов
    деф мягкий(я):
        возврат селф.баллов
 

Когда мы пытаемся напечатать экземпляр класса, мы получаем что-то как следующее.

 >>> 
  c= Карта(3, "D") 
 
  >>>  
  печать c 
 
 
<__main__. Объект карты по адресу 0x2e5f6c>
  

Это поведение по умолчанию для __str__ метод. Однако мы можем переопределить это с помощью функции, которая производит более полезный результат.

 по определению __str__(я):
        вернуть "%2d%s" % (self.rank, self.suit)
 

Добавление этой функции метода преобразует текущее значение кубика в строку и возвращает это. Теперь мы получаем нечто большее полезный.

 >>> 
  d= Карта(4, "D") 
 
  >>>  
  печать д 
 
 
 4D
  

Детали представления с __repr__ . Хотя метод __str__ создает удобочитаемая строка, иногда нам нужны мельчайшие детали. __repr__ Функция метода оценивается всякий раз, когда экземпляр класса должен иметь подробное представление показано. Обычно это делается в ответ на оценку repr функция. Примеры включают далее:

 >>> 
  печать репр(с) 
 
 
<__main__. Объект карты по адресу 0x2f639c>
  

Если мы хотим получить более полезный результат, мы можем переопределить функция __repr__ . Цель состоит в том, чтобы произвести кусок программирования Python, который реконструировал бы оригинал объект.

 по определению __repr__(сам):
        return "Карта(%d,%r)" % (self.rank,self.suit)
 

Мы используем __repr__ для получения четкого определения как воссоздать данный объект.

 >>> 
  f= Карта(5,"D") 
 
  >>>  
  печать репр(ф) 
 
 
Карточка(5,'D')
  

Сортировка и сравнение с __cmp__ . Еще один полезный специальный метод: __cmp__ . Мы используем __cmp__ для обеспечения результаты, используемые для сортировки и сравнения объектов. встроенный 9Функция 0015 cmp , как правило, использует этот метод. если ты не делайте других договоренностей, то этот метод также используется для < , <= , > , >= , == и != .

 по определению __cmp__(я, другой):
        вернуть cmp(self.rank, other.rank) или cmp(self.suit, self.suit)
 

После добавления метода __cmp__ мы можно сравнить карты, чтобы проверить их относительный ранг.

 >>> 
  см (в, г) 
 
  -1 
  >>>  
  с < д 
 
  Правда 
  >>>  
  с >= д 
 
  Ложь  

Имена специальных атрибутов. В дополнение к именам специальных методов каждый объект имеет количество специальных атрибутов. Они описаны в разделе 2.3.10. Справочник по библиотеке Python . Есть __dict__ , __класс__ и __базы__ .

Переменные атрибутов экземпляра класса хранятся в специальном объект словаря с именем __dict__ . Как следствие, когда вы говорите self.attribute= value , это почти значение идентично self. __dict__['attribute']= значение .

В сочетании с операцией форматирования строки % эта функция удобно писать __str__ и __repr__ функций.

 по определению __str__(я):
        return "%(rank)2s%(suit)s" % self.__dict__
    защита __repr__(сам):
        return "Карта(%(ранг)r,%(масть)r)" % self.__dict__
 

Расширение классов Python с помощью методов Dunder (магических, специальных) — dbader.org

Боб Белдербос

Что такое «магические методы» Python и как их использовать, чтобы сделать простой класс учетной записи более питоническим.

Что такое методы Дандера?

В Python специальные методы представляют собой набор предопределенных методов, которые вы можете использовать для обогащения своих классов. Их легко узнать, потому что они начинаются и заканчиваются двойным подчеркиванием, например __init__ или __str__ .

Поскольку быстро стало надоедать говорить «под-под-методом-под-под», питонисты приняли термин «дандер-методы», краткую форму «двойного под».

Эти «дандеры» или «специальные методы» в Python также иногда называют «магическими методами». Но использование этой терминологии может сделать их более сложными, чем они есть на самом деле — в конце концов, в них нет ничего «волшебного». Вы должны относиться к этим методам как к обычной языковой функции.

Методы Dunder позволяют эмулировать поведение встроенных типов. Например, чтобы получить длину строки, вы можете вызвать len('string') . Но пустое определение класса не поддерживает это поведение из коробки:

 класс NoLenSupport:
    проходить
>>> объект = NoLenSupport()
>>> лен(объект)
TypeError: "объект типа NoLenSupport не имеет len()"
 

Чтобы исправить это, вы можете добавить в свой класс метод __len__ dunder:

 класс LenSupport:
    защита __len__(я):
        вернуться 42
>>> объект = LenSupport()
>>> лен(объект)
42
 

Другой пример — нарезка. Вы можете реализовать метод __getitem__ , который позволяет использовать синтаксис нарезки списка Python: obj[start:stop] .

Специальные методы и модель данных Python

Этот элегантный дизайн известен как модель данных Python и позволяет разработчикам использовать богатые языковые функции, такие как последовательности, итерация, перегрузка операторов, доступ к атрибутам и т. д.

Вы можете рассматривать модель данных Python как мощный API, с которым вы можете взаимодействовать, реализуя один или несколько методов dunder. Если вы хотите писать больше Pythonic-кода, важно знать, как и когда использовать методы dunder.

Хотя для новичка это может поначалу быть немного ошеломляющим. Не беспокойтесь, в этой статье я расскажу вам об использовании методов dunder на примере простого класса Account .

Расширение класса простой учетной записи

В этой статье я буду дополнять простой класс Python различными методами dunder, чтобы разблокировать следующие функции языка:

  • Инициализация новых объектов
  • Представление объекта
  • Включить итерацию
  • Перегрузка оператора (сравнение)
  • Перегрузка оператора (дополнение)
  • Вызов метода
  • Поддержка диспетчера контекста ( с оператором )

Вы можете найти окончательный пример кода здесь. Я также составил блокнот Jupyter, чтобы вам было легче играть с примерами.

Инициализация объекта:

__init__

Сразу после начала занятий мне уже нужен специальный метод. Чтобы построить объекты счета из Класс Account Мне нужен конструктор, который в Python является __init__ dunder:

Учетная запись класса
:
    """Простой класс счетов"""
    def __init__(я, владелец, количество=0):
        """
        Это конструктор, который позволяет нам создавать
        объекты из этого класса
        """
        self.owner = владелец
        самостоятельная сумма = сумма
        self._transactions = []
 

Конструктор заботится о настройке объекта. В этом случае он получает имя владельца, необязательную начальную сумму и определяет список внутренних транзакций для отслеживания депозитов и снятия средств.

Это позволяет нам создавать новые учетные записи следующим образом:

 >>> acc = Account('bob') # сумма по умолчанию = 0
>>> акк = Счет('боб', 10)
 

Представление объекта:

__str__ , __repr__

В Python обычной практикой является предоставление строкового представления вашего объекта для потребителя вашего класса (немного похоже на документацию API). Есть два способа сделать это с помощью методов dunder:

  1. __repr__ : «Официальное» строковое представление объекта. Вот как вы могли бы сделать объект класса. Цель __repr__ — быть недвусмысленным.

  2. __str__ : «Неофициальное» или красивое строковое представление объекта. Это для конечного пользователя.

Давайте реализуем эти два метода в классе Account :

Учетная запись класса
:
    # ... (см. выше)
    защита __repr__(сам):
        return 'Account({!r}, {!r})'.format(self.owner, self.amount)
    защита __str__(я):
        return 'Счет {} с начальной суммой: {}'.format(
            self.owner, self.amount)
 

Если вы не хотите жестко кодировать «Учетная запись» в качестве имени класса, вы также можете использовать self.__class__.__name__ для доступа к нему программно.

Если вы хотите реализовать только один из этих методов to-string в классе Python, убедитесь, что это __repr__ .

Теперь я могу запрашивать объект разными способами и всегда получать красивое строковое представление:

 >>> ул(соотв.)
'Счет боба со стартовой суммой: 10'
>>> распечатать (соотв.)
"Счет Боба со стартовой суммой: 10"
>>> репр(акк)
"Счет('боб', 10)"
 

Итерация:

__len__ , __getitem__ , __reversed__

Чтобы перебрать наш объект учетной записи, мне нужно добавить несколько транзакций. Итак, сначала я определю простой метод для добавления транзакций. Я буду упрощать, потому что это просто установочный код для объяснения методов dunder, а не готовая к работе система учета:

 по определению add_transaction (я, сумма):
    если не isinstance (сумма, int):
        поднять ValueError («пожалуйста, используйте int для суммы»)
    self._transactions.append(сумма)
 

Я также определил свойство для расчета баланса на счете, поэтому я могу легко получить к нему доступ с помощью account.balance . Этот метод берет начальную сумму и добавляет сумму всех транзакций:

 @property
деф баланс(я):
    вернуть self.amount + sum(self._transactions)
 

Давайте сделаем несколько пополнений и выводов со счета:

 >>> acc = Account('bob', 10)
>>> acc.add_transaction(20)
>>> acc.add_transaction(-10)
>>> acc.add_transaction(50)
>>> acc.add_transaction(-20)
>>> acc.add_transaction(30)
>>> по балансу
80
 

Теперь у меня есть некоторые данные, и я хочу знать:

  1. Сколько было транзакций?

  2. Индексировать объект счета для получения номера транзакции …

  3. Цикл по транзакциям

С моим определением класса в настоящее время это невозможно. Все следующие операторы вызывают исключения TypeError :

 >>> длина(соотв.)
Ошибка типа
>>> для t в соотв.:
... печать (т)
Ошибка типа
>>> согл[1]
Ошибка типа
 

Методы Дандера на помощь! Чтобы сделать класс итерируемым, требуется совсем немного кода:

Учетная запись класса
:
    # . .. (см. выше)
    защита __len__(я):
        вернуть len(self._transactions)
    def __getitem__(я, позиция):
        вернуть self._transactions[позиция]
 

Теперь работают предыдущие операторы:

 >>> длина(соотв.)
5
>>> для t в соотв.:
... печать (т)
20
-10
50
-20
30
>>> согл[1]
-10
 

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

 по определению __reversed__(сам):
    вернуть себя[::-1]
>>> список (обратный (акк))
[30, -20, 50, -10, 20]
 

Чтобы перевернуть список транзакций, я использовал синтаксис обратного списка Python. Мне также пришлось обернуть результат reversed(acc) в вызов list() , потому что reversed() возвращает обратный итератор, а не объект списка, который мы можем красиво напечатать в REPL. Ознакомьтесь с этим руководством по итераторам в Python, если вы хотите узнать больше о том, как работает этот подход.

В общем, этот класс учетной записи теперь начинает казаться мне довольно Pythonic.

Перегрузка оператора для сравнения счетов:

__eq__ , __lt__

Мы все ежедневно пишем десятки операторов для сравнения объектов Python:

 >>> 2 > 1
Истинный
>>> 'а' > 'б'
ЛОЖЬ
 

Это кажется совершенно естественным, но на самом деле просто удивительно, что здесь происходит за кулисами. Почему > одинаково хорошо работают с целыми числами, строками и другими объектами (при условии, что они одного типа)? Такое полиморфное поведение возможно, потому что эти объекты реализуют один или несколько методов сравнения dunder.

Простой способ проверить это — использовать встроенную функцию dir() :

 >>> директор('а')
['__добавлять__',
...
'__eq__', <----------------
'__формат__',
'__ge__', <---------------
'__получить атрибут__',
'__получить__',
'__getnewargs__',
'__gt__', <---------------
.. .]
 

Давайте создадим второй объект учетной записи и сравним его с первым (я добавляю пару транзакций для дальнейшего использования):

 >>> acc2 = Account('tim', 100)
>>> acc2.add_transaction(20)
>>> acc2.add_transaction(40)
>>> согл2.баланс
160
>>> акк2 > акк
Ошибка типа:
"'>' не поддерживается между экземплярами "Учетная запись" и "Учетная запись""
 

Что здесь произошло? Мы получили TypeError , потому что я не реализовал никаких ошибок сравнения и не унаследовал их от родительского класса.

Давайте добавим их. Чтобы не реализовывать все методы сравнения dunder, я использую декоратор functools.total_ordering, который позволяет мне сократить путь, реализовав только __eq__ и __lt__ :

.
 из functools import total_ordering
@total_ordering
Учетная запись класса:
    # ... (см. выше)
    def __eq__(я, другой):
        вернуть self.balance == other.balance
    def __lt__(я, другой):
        вернуть self. balance < other.balance
 

И теперь я могу сравнить учетных записей экземпляров без проблем:

 >>> акк2 > акк
Истинный
>>> акк2 < акк
ЛОЖЬ
>>> акк == акк2
ЛОЖЬ
 

Перегрузка оператора для объединения учетных записей:

__add__

В Python все является объектом. Мы совершенно нормально добавляем два целых числа или две строки с помощью оператора + (плюс), он ведет себя ожидаемым образом:

 >>> 1 + 2
3
>>> 'привет' + 'мир'
'Привет, мир'
 

Опять же, мы видим полиморфизм в игре: вы заметили, как + ведет себя по-разному в зависимости от типа объекта? Для целых чисел он суммирует, для строк объединяет. Снова быстрое выполнение dir() для объекта показывает соответствующий интерфейс «dunder» в модели данных:

 >>> директор(1)
[...
'__добавлять__',
...
'__радд__',
...]
 

Наш объект Account еще не поддерживает добавление, поэтому, когда вы пытаетесь добавить два его экземпляра, возникает ошибка 9. 0015 Ошибка типа :

 >>> акк + акк2
TypeError: «неподдерживаемые типы операндов для +:« Учетная запись »и« Учетная запись »»
 

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

.
 по определению __add__(я, другой):
    владелец = '{}&{}'.format(self.owner, other.owner)
    начальная_сумма = собственная.сумма + другая.сумма
    acc = Аккаунт (владелец, начальная_сумма)
    для t в списке (я) + список (другое):
        acc.add_transaction(t)
    возврат согласно
 

Да, это немного сложнее, чем другие реализации dunder. Это должно показать вам, что вы находитесь на месте водителя. Вы можете реализовать дополнение, как вам заблагорассудится. Если мы хотели игнорировать исторические транзакции — отлично, можно реализовать и так:

 по определению __add__(я, другой):
    владелец = сам. владелец + другой.владелец
    start_amount = self.balance + other.balance
    вернуть Аккаунт (владелец, start_amount)
 

Я думаю, что предыдущая реализация была бы более реалистичной с точки зрения того, что ожидает потребитель этого класса.

Теперь у нас есть новый объединенный аккаунт со стартовой суммой 110$ (10+100) и балансом 240$ (80+160):

 >>> акк3 = акк2 + акк
>>> согл3
Аккаунт('тим&боб', 110)
>>> acc3.сумма
110
>>> согл3.баланс
240
>>> acc3._transactions
[20, 40, 20, -10, 50, -20, 30]
 

Обратите внимание, что это работает в обоих направлениях, потому что мы добавляем объекты одного и того же типа. В общем, если вы добавите свой объект во встроенный ( int , str , …) встроенный метод __add__ ничего не знает о вашем объекте. В этом случае вам также необходимо реализовать обратный метод добавления ( __radd__ ). Вы можете увидеть пример для этого здесь.

Вызываемые объекты Python:

__call__

Вы можете сделать объект вызываемым как обычную функцию, добавив метод __call__ dunder. Для нашего класса счета мы могли бы напечатать отчет обо всех транзакциях, составляющих его баланс:

Учетная запись класса
:
    # ... (см. выше)
    защита __call__(сам):
        print('Начальная сумма: {}'.format(self.amount))
        print('Транзакции:')
        для транзакции в себе:
            печать (транзакция)
        print('\nБаланс: {}'.format(self.balance))
 

Теперь, когда я вызываю объект с синтаксисом acc() в двойных скобках, я получаю красивую выписку по счету с обзором всех транзакций и текущим балансом:

 >>> acc = Account('bob', 10)
>>> acc.add_transaction(20)
>>> acc.add_transaction(-10)
>>> acc.add_transaction(50)
>>> acc.add_transaction(-20)
>>> acc.add_transaction(30)
>>> акк()
Начальная сумма: 10
Транзакции:
20
-10
50
-20
30
Баланс: 80
 

Имейте в виду, что это всего лишь игрушечный пример. «Настоящий» класс учетной записи, вероятно, не будет печатать на консоли, если вы используете синтаксис вызова функции в одном из его экземпляров. В общем, недостатком метода __call__ для ваших объектов является то, что может быть трудно понять, какова цель вызова объекта.

Поэтому в большинстве случаев лучше добавить в класс явный метод. В этом случае, вероятно, было бы более прозрачно иметь отдельный Метод Account.print_statement() .

Поддержка диспетчера контекста

и заявление

с : __enter__ , __exit__

Мой последний пример в этом руководстве касается несколько более продвинутой концепции в Python: менеджеры контекста и добавление поддержки оператора с .

Итак, что такое «менеджер контекста» в Python? Вот краткий обзор:

Менеджер контекста — это простой «протокол» (или интерфейс), которому должен следовать ваш объект, чтобы его можно было использовать с с оператором . В основном все, что вам нужно сделать, это добавить методы __enter__ и __exit__ к объекту, если вы хотите, чтобы он функционировал как менеджер контекста.

Давайте воспользуемся поддержкой контекстного менеджера, чтобы добавить механизм отката в наш класс Account . Если при добавлении очередной транзакции баланс становится отрицательным, мы откатываемся к предыдущему состоянию.

Мы можем использовать оператор Pythonic with , добавив еще два метода dunder. Я также добавляю несколько вызовов печати, чтобы сделать пример более понятным, когда мы его демонстрируем:

Учетная запись класса
:
    # ... (см. выше)
    защита __enter__(сам):
        print('ENTER WITH: Создание резервной копии транзакций для отката')
        self._copy_transactions = список(self._transactions)
        вернуть себя
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('ВЫХОД С:', end=' ')
        если exc_type:
            self._transactions = self._copy_transactions
            print('Откат к предыдущим транзакциям')
            print('Транзакция привела к {} ({})'.format(
                exc_type. __name__, exc_val))
        еще:
            print('Транзакция прошла успешно')
 

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

 по определению validate_transaction(acc, amount_to_add):
    с акк как:
        print('Добавление {} в аккаунт'.format(amount_to_add))
        a.add_transaction(сумма_к_добавлению)
        print('Новый баланс будет следующим: {}'.format(a.balance))
        если а.баланс < 0:
            поднять ValueError('извините, не могу остаться в долгу!')
 

Теперь я могу использовать Объект Account с выпиской with . Когда я делаю транзакцию, чтобы добавить положительную сумму, все хорошо:

 acc4 = Счет('иск', 10)
print('\nНачало баланса: {}'.format(acc4.balance))
validate_transaction (acc4, 20)
print('\nКонец баланса: {}'.format(acc4.balance))
 

При выполнении приведенного выше фрагмента Python выводится следующая распечатка:

 Начало баланса: 10
ENTER WITH: Создание резервной копии транзакций для отката
Добавление 20 к счету
Новый баланс будет: 30
ВЫХОД С: Транзакция ОК
Конец баланса: 30
 

Однако, когда я пытаюсь снять слишком много денег, срабатывает код __exit__ и откатывает транзакцию:

 acc4 = Счет('иск', 10)
print('\nНачало баланса: {}'. format(acc4.balance))
пытаться:
    validate_transaction (acc4, -50)
кроме ValueError как exc:
    печать (отл.)
print('\nКонец баланса: {}'.format(acc4.balance))
 

В этом случае мы получаем другой результат:

 Начало баланса: 10
ENTER WITH: Создание резервной копии транзакций для отката
Добавление -50 к аккаунту
Новый баланс будет: -40
ВЫХОД С: Откат к предыдущим транзакциям
ValueError: извините, не могу остаться в долгу!
Конец баланса: 10
 

Заключение

Я надеюсь, что после прочтения этой статьи вы стали немного меньше бояться дандер-методов. Стратегическое их использование делает ваши классы более питоническими, потому что они эмулируют встроенные типы с поведением, подобным Python.

Как и с любой другой функцией, пожалуйста, не злоупотребляйте ею. Например, перегрузка операторов может быть довольно неясной. Добавление «кармы» к объекту человека с помощью +bob или tim << 3 определенно возможно с использованием dunders, но может быть не самым очевидным или подходящим способом использования этих специальных методов.