Объекты и классы python
Содержание:
- Оператор цикла for
- 9.4. Random Remarks¶
- 9.5. Inheritance¶
- Создание объекта
- Конструктор классов
- Public and Internal Interfaces
- Приоритеты операторов
- Как работают методы класса в Python?
- Переопределяющие методы
- Атрибут __metaclass__
- Множественная логистическая регрессия
- Линейный Дискриминантный Анализ
- 1 Python issubclass() в наследовании
- Переопределение метода
- Init-only variables
- Определение конструктора для класса
- Уничтожение объектов (Сборка мусора)
- LDA для одного предсказателя
- Обзор терминологии ООП
- @classmethod и @staticmethod
Оператор цикла for
Следующий и,
наверное, самый часто используемый оператор цикла – это оператор for, который имеет
такой синтаксис:
for <переменная> in <список> :
операторы 1…N
Например,
for x in 1,5,2,4: print(x**2)
выведет в
консоль квадраты соответствующих чисел. Но что, если мы хотим перебрать
значения по порядку в соответствии с правилом:
начальное
значение, шаг, конечное значение
Для этого
используется генератор последовательностей
range(start, stop, step)
Например, если
мы запишем его вот так:
for x in range(1,5,1): print(x)
то в консоли
увидим числа от 1 до 4 с шагом 1. То есть, range генерирует
последовательность в интервале
[1;5)
Последнее
значение не входит в интервал. Если в нашем примере поставить шаг отрицательный
-1, то конечное значение 5 не может быть достигнуто и в этом случае Python возвратит пустую
последовательность:
for x in range(1,5,-1): print(x)
Если нам нужны
числа от 5 до 1, то следует записывать range в таком виде:
for x in range(5,,-1): print(x)
Причем, в range можно записывать
только целые числа, с вещественными он не работает.
Давайте
перепишем нашу программу подсчета суммы
с помощью цикла for, получим:
S= for i in range(1, 1001, 1): S += 1/i print(S)
Здесь весь цикл
записан буквально в одну строчку, а тело цикла состоит из одного оператора –
подсчета суммы ряда.
Вторым примером
рассмотрим задачу вычисления значений линейной функции
Программа будет
выглядеть так:
k = 0.5; b = 2 lst = , 0.1, 0.2, 0.3, 0.4, 0.5 for x in lst: print(x*k+b)
Этот пример
показывает, что для перебора значений счетчика x можно
использовать списки, сформированные ранее в программе. (О списках мы подробнее
будем говорить на последующих занятиях). Здесь же приведем еще один пример:
msg = "Hello World!" for x in msg: print(x)
Он показывает,
что строку можно воспринимать как список и перебирать с помощью цикла for.
Также в цикле for можно
использовать блок else, о котором мы говорили ранее:
for <переменная> in <список> :
операторы 1…N
else:
операторы 1…N
9.4. Random Remarks¶
If the same attribute name occurs in both an instance and in a class,
then attribute lookup prioritizes the instance:
>>> class Warehouse purpose = 'storage' region = 'west' >>> w1 = Warehouse() >>> print(w1.purpose, w1.region) storage west >>> w2 = Warehouse() >>> w2.region = 'east' >>> print(w2.purpose, w2.region) storage east
Data attributes may be referenced by methods as well as by ordinary users
(“clients”) of an object. In other words, classes are not usable to implement
pure abstract data types. In fact, nothing in Python makes it possible to
enforce data hiding — it is all based upon convention. (On the other hand,
the Python implementation, written in C, can completely hide implementation
details and control access to an object if necessary; this can be used by
extensions to Python written in C.)
Clients should use data attributes with care — clients may mess up invariants
maintained by the methods by stamping on their data attributes. Note that
clients may add data attributes of their own to an instance object without
affecting the validity of the methods, as long as name conflicts are avoided —
again, a naming convention can save a lot of headaches here.
There is no shorthand for referencing data attributes (or other methods!) from
within methods. I find that this actually increases the readability of methods:
there is no chance of confusing local variables and instance variables when
glancing through a method.
Often, the first argument of a method is called . This is nothing more
than a convention: the name has absolutely no special meaning to
Python. Note, however, that by not following the convention your code may be
less readable to other Python programmers, and it is also conceivable that a
class browser program might be written that relies upon such a convention.
Any function object that is a class attribute defines a method for instances of
that class. It is not necessary that the function definition is textually
enclosed in the class definition: assigning a function object to a local
variable in the class is also ok. For example:
# Function defined outside the class def f1(self, x, y): return min(x, x+y) class C f = f1 def g(self): return 'hello world' h = g
Now , and are all attributes of class that refer to
function objects, and consequently they are all methods of instances of
— being exactly equivalent to . Note that this practice
usually only serves to confuse the reader of a program.
Methods may call other methods by using method attributes of the
argument:
class Bag def __init__(self): self.data = [] def add(self, x): self.data.append(x) def addtwice(self, x): self.add(x) self.add(x)
Methods may reference global names in the same way as ordinary functions. The
global scope associated with a method is the module containing its
definition. (A class is never used as a global scope.) While one
rarely encounters a good reason for using global data in a method, there are
many legitimate uses of the global scope: for one thing, functions and modules
imported into the global scope can be used by methods, as well as functions and
classes defined in it. Usually, the class containing the method is itself
defined in this global scope, and in the next section we’ll find some good
reasons why a method would want to reference its own class.
9.5. Inheritance¶
Of course, a language feature would not be worthy of the name “class” without
supporting inheritance. The syntax for a derived class definition looks like
this:
class DerivedClassName(BaseClassName): <statement-1> . . . <statement-N>
The name must be defined in a scope containing the
derived class definition. In place of a base class name, other arbitrary
expressions are also allowed. This can be useful, for example, when the base
class is defined in another module:
class DerivedClassName(modname.BaseClassName):
Execution of a derived class definition proceeds the same as for a base class.
When the class object is constructed, the base class is remembered. This is
used for resolving attribute references: if a requested attribute is not found
in the class, the search proceeds to look in the base class. This rule is
applied recursively if the base class itself is derived from some other class.
There’s nothing special about instantiation of derived classes:
creates a new instance of the class. Method references
are resolved as follows: the corresponding class attribute is searched,
descending down the chain of base classes if necessary, and the method reference
is valid if this yields a function object.
Derived classes may override methods of their base classes. Because methods
have no special privileges when calling other methods of the same object, a
method of a base class that calls another method defined in the same base class
may end up calling a method of a derived class that overrides it. (For C++
programmers: all methods in Python are effectively .)
An overriding method in a derived class may in fact want to extend rather than
simply replace the base class method of the same name. There is a simple way to
call the base class method directly: just call . This is occasionally useful to clients as well. (Note that this
only works if the base class is accessible as in the global
scope.)
Python has two built-in functions that work with inheritance:
-
Use to check an instance’s type:
will be only if is or some class
derived from . -
Use to check class inheritance:
is since is a subclass of . However,
is since is not a
subclass of .
Создание объекта
Мы увидели, что объект класса можно использовать для доступа к различным атрибутам.
Его также можно использовать для создания новых экземпляров объекта (создания экземпляров) этого класса. Процедура создания объекта аналогична вызову функции.
>>> harry = Person()
Это создаст новый экземпляр объекта с именем harry. Мы можем получить доступ к атрибутам объектов, используя префикс имени объекта.
Атрибуты могут быть данными или методом. Методы объекта ‒ это соответствующие функции этого класса.
Это означает, что поскольку Person.greet является объектом функции (атрибутом класса), Person.greet будет объектом метода.
class Person: "This is a person class" age = 10 def greet(self): print('Hello') # create a new object of Person class harry = Person() # Output: <function Person.greet> print(Person.greet) # Output: <bound method Person.greet of <__main__.Person object>> print(harry.greet) # Calling object's greet() method # Output: Hello harry.greet()
Выход
<function Person.greet at 0x7fd288e4e160> <bound method Person.greet of <__main__.Person object at 0x7fd288e9fa30>> Hello
Вы могли заметить параметр self в определении функции внутри класса, но мы вызвали этот метод просто как harry.greet() без каких-либо аргументов. Это все еще работало.
Это потому, что всякий раз, когда объект вызывает свой метод, сам объект передается в качестве первого аргумента. Итак, harry.greet() переводится как Person.greet (harry).
В общем случае вызов метода со списком из n аргументов эквивалентен вызову соответствующей функции со списком аргументов, который создается путем вставки объекта метода перед первым аргументом.
По этим причинам первым аргументом функции в классе должен быть сам объект. Это условно называется self. Его можно назвать иначе, но мы настоятельно рекомендуем следовать правилам.
Теперь вы ознакомились с объектом класса, объектом экземпляра, объектом функции, объектом метода и их различиями.
Конструктор классов
#defining constructor def __init__(self, personName, personAge): self.name = personName self.age = personAge
Конструктор класса в Python – это первый фрагмент кода, который должен выполняться при создании нового объекта класса.
Прежде всего, конструктор можно использовать для помещения значений в переменные-члены. Вы также можете распечатать сообщения в конструкторе, чтобы убедиться, что объект был создан.
Метод конструктора начинается с def __init__. После этого первым параметром должно быть значение «self», так как он передает ссылку на экземпляр самого класса. Вы также можете добавить дополнительные параметры, как показано в примере. «personName» и «personAge» – это два параметра, которые необходимо отправить, когда должен быть создан новый объект.
Public and Internal Interfaces
Any backwards compatibility guarantees apply only to public interfaces.
Accordingly, it is important that users be able to clearly distinguish
between public and internal interfaces.
Documented interfaces are considered public, unless the documentation
explicitly declares them to be provisional or internal interfaces exempt
from the usual backwards compatibility guarantees. All undocumented
interfaces should be assumed to be internal.
To better support introspection, modules should explicitly declare the
names in their public API using the __all__ attribute. Setting
__all__ to an empty list indicates that the module has no public API.
Even with __all__ set appropriately, internal interfaces (packages,
modules, classes, functions, attributes or other names) should still be
prefixed with a single leading underscore.
An interface is also considered internal if any containing namespace
(package, module or class) is considered internal.
Приоритеты операторов
Consider this expression:
>>> 20 + 4 * 10 60
There is ambiguity here. Should Python perform the addition first and then multiply the sum by ? Or should the multiplication be performed first, and the addition of second?
Clearly, since the result is , Python has chosen the latter; if it had chosen the former, the result would be . This is standard algebraic procedure, found universally in virtually all programming languages.
Всем операторам, которые поддерживает язык, присваивается приоритет. В выражении все операторы с наивысшим приоритетом выполняются первыми. Как только эти результаты получены, выполняются операторы следующего наивысшего приоритета. Так продолжается до тех пор, пока выражение не будет полностью оценено. Все операторы с одинаковым приоритетом выполняются в порядке слева направо.
Вот порядок приоритета операторов Python, которые вы видели до сих пор, от низшего к высшему:
Оператор
Описание
низший приоритет
Логическое ИЛИ
Логическое И
Логическое НЕ
, , , , , , ,
сравнения, идентификация
побитовое ИЛИ
побитовое ИСКЛЮЧАЮЩЕЕ ИЛИ
побитовое И
,
битовый сдвиг
,
сложение, вычитание
, , ,
умножение, деление, окруляющее деление, остаток от деления
, ,
плюс, минус, побитовый минус
наивысший приоритет
возведение в степень
Операторы в верхней части таблицы имеют самый низкий приоритет, а операторы в нижней части таблицы имеют самый высокий. Любые операторы в одной строке таблицы имеют одинаковый приоритет.
Понятно, почему умножение выполняется первым в приведенном выше примере: умножение имеет более высокий приоритет, чем сложение.
Аналогично, в приведенном ниже примере сначала возводится в степень , что равно , а затем выполняется умножение в порядок слева направо():
>>> 2 * 3 ** 4 * 5 810
Приоритеты операторов могут быть переопределены с помощью скобок. Выражения в скобках всегда выполняются в первую очередь, перед выражениями, которые не заключены в скобки. Таким образом, происходит следующее:
>>> 20 + 4 * 10 60 >>>(20 + 4) * 10 240
>>> 2 * 3 ** 4 * 5 810 >>> 2 * 3 **(4 * 5) 6973568802
В первом примере сначала вычисляется , затем результат умножается на . Во втором примере сначала вычисляется , затем значение увеличивается до этой степени, а затем результат умножается на .
Нет ничего плохого в том, чтобы свободно использовать круглые скобки, даже если они не нужны для изменения порядка оценки. Фактически, это считается хорошей практикой, потому что это может сделать код более читабельным, и это освобождает читателя от необходимости вызывать Приоритеты операторов из памяти. Учтите следующее:
(a < 10) and(b > 30)
Здесь круглые скобки совершенно не нужны, поскольку операторы сравнения имеют более высокий приоритет, чем , и в любом случае выполнялись бы первыми. Но некоторые могут считать намерение версии в скобках более очевидным, чем эта версия без скобок:
a < 10 and b > 30
С другой стороны, вероятно, есть те, кто предпочел бы последнее; это вопрос личных предпочтений. Дело в том, что вы всегда можете использовать круглые скобки, если считаете, что это делает код более читабельным, даже если в них нет необходимости менять порядок вычислений.
Как работают методы класса в Python?
В Python, методы класса отмечаются декоратором , следовательно в приведенном выше примере, метод класса будет определен в функции .
Как можно заметить, метод класса вместо того, чтобы принимать аргумент , принимает аргумент . При вызове метода этот аргумент указывает на сам класс, а не на экземпляр класса.
Поскольку метод класса имеет доступ только к аргументу , он не может изменять состояние экземпляра объекта. Для этого потребуется доступ к аргументу . НО все же методы класса могут изменять состояние класса, которое применяется ко всем экземплярам класса.
настроен таким образом, что реализация каждого метода возвращает кортеж для отслеживания, что происходит, и к каким частям класса или объекта метод может получить доступ.
Вот что происходит, когда мы вызываем метод экземпляра:
>>> obj = MyClass() >>> obj.method() # ('instance method called', <__main__.MyClass object at 0x7f9748403f40>) # Можно передать объект `obj` экземпляра вручную, # для получения того же результата >>> MyClass.method(obj) # ('instance method called', <__main__.MyClass object at 0x7f9748403f40>)
Этот кусок кода подтвердил, что метод экземпляра класса имеет доступ к экземпляру объекта, напечатанному как через аргумент .
Кстати, методы экземпляра также могут получить доступ к самому классу через атрибут . Это делает методы экземпляра мощными с точки зрения ограничений доступа — они могут изменять состояние как экземпляра объекта, так и самого класса.
Попробуем вызвать метод класса:
>>> obj.classmethod() # ('class method called', <class '__main__.MyClass'>)
Вызов метода класса показал, что он не имеет доступа к объекту , а только к объекту , представляющему сам класс (в Python все является объектом, даже сами классы).
Обратите внимание, как Python автоматически передает класс в качестве первого аргумента функции, когда вызывается. Вызов метода в Python через точечную нотацию запускает это поведение
Параметр в методах экземпляра работает точно так же.
Теперь посмотрим, что происходит, когда попытаться вызвать эти методы в самом классе — без предварительного создания экземпляра объекта:
>>> MyClass.classmethod() # ('class method called', <class '__main__.MyClass'>) >>> MyClass.method() # Traceback (most recent call last): # File "<stdin>", line 1, in <module> # TypeError: method() missing 1 required positional argument: 'self'
Из примера видно, что можно нормально вызвать метод класса , но попытка вызвать метод экземпляра завершилась ошибкой . Этого следовало ожидать, ведь экземпляр объекта не создан, что означает, что Python не может заполнить аргумент и следовательно, вызов не выполняется.
Переопределяющие методы
Вы всегда можете переопределить ваши родительские методы класса. Одна из причин переопределения родительских методов заключается в том, что вам может потребоваться особая или другая функциональность в вашем подклассе.
пример
#!/usr/bin/python class Parent: # define parent class def myMethod(self): print 'Calling parent method' class Child(Parent): # define child class def myMethod(self): print 'Calling child method' c = Child() # instance of child c.myMethod() # child calls overridden method
Когда приведенный выше код выполняется, он дает следующий результат —
Calling child method
Атрибут __metaclass__
В Python 2 вы можете добавить атрибут __metaclass__ при описание класса:
class Foo(object): __metaclass__ = something...
Если вы это сделаете, Python будет использовать этот метакласс для создания класса Foo.
Сначала вы пишете class Foo(object), но объект класса Foo еще не создан в памяти. Python будет искать __metaclass__ в определении класса. Если он его найдет, он будет использовать его для создания класса объекта Foo. Если не найдет, он будет использовать type для создания класса. Прочтите это несколько раз.
Когда вы это сделаете:
class Foo(Bar): pass
Python делает следующее:
Есть ли атрибут __metaclass__ в Foo ?
Если да, то будет создан в памяти объект класса с именем Foo, используя то, что находится в __metaclass__.
Если Python не может найти __metaclass__, он будет искать __metaclass__ на уровне MODULE и пытаться сделать то же самое (но только для классов, которые ничего не наследуют, в основном классов старого стиля).
Затем, если он вообще не может найти какой-либо __metaclass__, он будет использовать собственный метакласс Bar (первого родителя) (который может быть type по умолчанию) для создания объекта класса.
Примечание: атрибут __metaclass__ не будет унаследован, а метакласс родительского элемента (Bar .__ class__) будет. Если Bar использовал атрибут __metaclass__, который создал Bar с помощью type () (а не type .__ new __ ()), подклассы не унаследуют это поведение.
Теперь главный вопрос: что можно добавить в __metaclass__?
Ответ — то, что может создать класс.
А что можно создать класс? type или что-либо, что его подклассы использует для этого.
Множественная логистическая регрессия
Конечно, логистическая регрессия может быть легко расширена для размещения более одного предиктора:
Множественная логистическая регрессия
Обратите внимание, что использование множественной логистической регрессии может дать лучшие результаты, поскольку она может учитывать корреляции между предикторами, явление, известное какозадачив, Кроме того, редко будет достаточно одного предсказателя, чтобы создать точную модель для предсказания
Линейный Дискриминантный Анализ
Теперь мы понимаем, как работает логистическая регрессия, но, как и любая модель, она имеет некоторые недостатки:
- Когда классы хорошо разделены, оценка параметров из логистической регрессии имеет тенденцию быть нестабильной
- Когда набор данных небольшой, логистическая регрессия также нестабильна
- Не лучший прогноз более двух классов
Вот где линейный дискриминантный анализ (LDA) пригодится. Он более стабилен, чем логистическая регрессия, и широко используется для прогнозирования более двух классов.
Особенность LDA заключается в том, что он моделирует распределение предикторов отдельно в каждом из классов ответов, а затем использует теорему Байеса для оценки вероятности.
Хорошо, это немного сложно понять. Давайте разберемся с этим.
1 Python issubclass() в наследовании
Когда мы говорим о наследовании в Python, очень важна концепция родительских и дочерних классов. Когда дочерний элемент наследуется от родительского класса, он наследует или расширяет его свойства. В этот момент говорят, что дочерний класс является подклассом родительского класса.
Следовательно, метод пригодится, когда мы хотим получить информацию о наследовании класса. Или проверить, наследуется ли он от другого класса или нет.
Итак, давайте рассмотрим пример.
class Animals: pass class Humans(Animals): pass class Men(Humans): pass class Women(Humans): pass print("issubclass(Women, Humans) :", issubclass(Women, Humans)) print("issubclass(Men, Humans) :", issubclass(Men, Humans)) print("issubclass(Women, Men) :", issubclass(Women, Men)) #both are child of the same Humans Class print("issubclass(Humans, Animals) :", issubclass(Humans, Animals)) print("issubclass(Animals, Humans) :", issubclass(Animals, Humans)) #not the opposite print("issubclass(Women, Animals) :", issubclass(Women, Animals)) #multi-level inheritance print("issubclass(Animals, object) :", issubclass(Animals, object)) #object is the baseclass of all classes
Выход:
Здесь — родительский класс с дочерним классом . Два класса, и снова наследуются от класса (многоуровневое наследование). Следовательно, классы и являются подклассами и . А — это подкласс .
Далее для последнего случая получаем . Это связано с тем, что все классы в Python являются подклассами класса .
Переопределение метода
Обратите внимание, что в приведенном выше примере метод __init __() был определен в обоих классах, Triangle и Polygon. Когда это происходит, метод производного класса переопределяет метод базового класса
Это означает, что __init __() в Triangle получает предпочтение перед __init__ в Polygon.
Обычно при переопределении базового метода мы стремимся расширить определение, а не просто заменить его. То же самое делается путем вызова метода в базовом классе из метода в производном классе (вызов Polygon .__ init __() из __init __() в Triangle).
Лучшим вариантом было бы использовать встроенную функцию super(). Итак, super() .__ init __ (3) эквивалентен Polygon .__ init __ (self, 3) и является предпочтительным. Чтобы узнать больше о функции super() в Python, посетите функцию Python super().
Две встроенные функции isinstance() и issubclass() используются для проверки наследования.
Функция isinstance() возвращает True, если объект является экземпляром класса или других классов, производных от него. Каждый класс в Python наследуется от объекта базового класса.
>>> isinstance(t,Triangle) True >>> isinstance(t,Polygon) True >>> isinstance(t,int) False >>> isinstance(t,object) True
Точно так же issubclass() используется для проверки наследования классов.
>>> issubclass(Polygon,Triangle) False >>> issubclass(Triangle,Polygon) True >>> issubclass(bool,int) True
Было полезно224
Нет28
878cookie-checkНаследование в Python
Init-only variables
The other place where dataclass inspects a type annotation is to
determine if a field is an init-only variable. It does this by seeing
if the type of a field is of type dataclasses.InitVar. If a field
is an InitVar, it is considered a pseudo-field called an init-only
field. As it is not a true field, it is not returned by the
module-level fields() function. Init-only fields are added as
parameters to the generated __init__ method, and are passed to
the optional __post_init__ method. They are not otherwise used
by Data Classes.
For example, suppose a field will be initialized from a database, if a
value is not provided when creating the class:
@dataclass class C: i: int j: int = None database: InitVar = None def __post_init__(self, database): if self.j is None and database is not None: self.j = database.lookup('j') c = C(10, database=my_database)
Определение конструктора для класса
Если вы заметите реализацию класса сотрудников, нет способа установить значение SORDUE_ID. Мы можем определить отдельный метод для установки значения Otheree_ID. Но это обязательное свойство объекта сотрудника. Лучшее место для установки этих свойств проходит через конструктор.
Python Constructor – это специальная функция, которая вызывается, когда мы создаем экземпляр класса. Это имя функции всегда __init__, и он может иметь любое количество параметров. Первый параметр всегда является самим объектом, обычно называемым как самостоятельная переменная.
Давайте пойдем вперед и создадим конструктор для класса сотрудников. Мы ожидаем, что программа вызывающего абонента передает значение WARDEEE_ID в качестве аргумента.
class Employee: def __init__(self, i): self.employee_id = i def work(self): print(f'{self.employee_id} is working') emp = Employee(100) emp.work()
Выход :
Примечание Более ранний код для создания объекта сотрудника не будет работать сейчас, потому что конструктор сотрудника ожидает аргумента. Если мы позвоним это будет поднять TypeError: init () Отсутствует 1 Требуемый позиционный аргумент: «ID» Отказ
Уничтожение объектов (Сборка мусора)
Python автоматически удаляет ненужные объекты (встроенные типы или экземпляры классов), чтобы освободить пространство памяти. Процесс, с помощью которого Python периодически восстанавливает блоки памяти, которые больше не используются, называется сбором мусора.
Сборщик мусора в Python запускается во время выполнения программы и запускается, когда счетчик ссылок на объект достигает нуля. Количество ссылок объекта изменяется по мере изменения количества псевдонимов, которые на него указывают.
Счетчик ссылок на объект увеличивается, когда ему присваивается новое имя или он помещается в контейнер (список, кортеж или словарь). Счетчик ссылок объекта уменьшается, когда он удаляется с помощью del , его ссылка переназначается или его ссылка выходит за пределы области видимости. Когда счетчик ссылок объекта достигает нуля, Python собирает его автоматически.
a = 40 # Create object <40> b = a # Increase ref. count of <40> c = # Increase ref. count of <40> del a # Decrease ref. count of <40> b = 100 # Decrease ref. count of <40> c = -1 # Decrease ref. count of <40>
Обычно вы не замечаете, когда сборщик мусора уничтожает потерянный экземпляр и освобождает его пространство. Но класс может реализовать специальный метод __del __ () , называемый деструктором, который вызывается, когда экземпляр собирается быть уничтоженным. Этот метод может использоваться для очистки любых ресурсов памяти, используемых экземпляром.
пример
Этот деструктор __del __ () печатает имя класса экземпляра, который должен быть уничтожен —
#!/usr/bin/python class Point: def __init__( self, x=0, y=0): self.x = x self.y = y def __del__(self): class_name = self.__class__.__name__ print class_name, "destroyed" pt1 = Point() pt2 = pt1 pt3 = pt1 print id(pt1), id(pt2), id(pt3) # prints the ids of the obejcts del pt1 del pt2 del pt3
Когда приведенный выше код выполняется, он дает следующий результат —
3083401324 3083401324 3083401324 Point destroyed
Примечание. В идеале вы должны определить свои классы в отдельном файле, а затем импортировать их в основной файл программы с помощью оператора import .
LDA для одного предсказателя
Предположим, у нас есть только один предиктор и что функция плотности нормальная. Затем вы можете выразить функцию плотности как:
Нормальная функция распределения
Теперь мы хотим назначить наблюдениеХ = хдля которогоP_k (Х)самый большой. Если вы подключите функцию плотности вP_k (Х)и взятьжурналВы обнаружите, что хотите максимально увеличить:
Дискриминантное уравнение
Уравнение выше называетсядискриминант.Как видите, это линейное уравнение. Отсюда и название:линейный дискриминантный анализ!
Теперь, предполагая только два класса с равным распределением, вы найдете:
Граничное уравнение
Это граничное уравнение. Графическое представление показано ниже.
Граничная линия для разделения 2 классов с использованием LDA
Конечно, это идеальное решение. В действительности, мы не можем точно рассчитать граничную линию.
Поэтому LDA использует следующее приближение:
Для среднего всех тренировочных наблюдений
Среднее из всех тренировочных наблюдений
Для средневзвешенной выборочной дисперсии для каждого класса
Средневзвешенное значение выборочных отклонений для каждого класса
гдеNколичество наблюдений
Важно знать, что LDA предполагаетнормальное распределениедля каждого классасреднее по классуиобщая разница,
Обзор терминологии ООП
-
Класс — определенный пользователем прототип для объекта, который определяет набор атрибутов, которые характеризуют любой объект класса. Атрибутами являются члены данных (переменные класса и переменные экземпляра) и методы, доступ к которым осуществляется через точечную запись.
-
Переменная класса — переменная, которая используется всеми экземплярами класса. Переменные класса определены внутри класса, но за пределами любого из методов класса. Переменные класса используются не так часто, как переменные экземпляра.
-
Член данных — переменная класса или переменная экземпляра, которая содержит данные, связанные с классом и его объектами.
-
Перегрузка функций — назначение более чем одного поведения определенной функции. Выполняемая операция варьируется в зависимости от типов объектов или аргументов.
-
Переменная экземпляра — переменная, которая определена внутри метода и принадлежит только текущему экземпляру класса.
-
Наследование — передача характеристик класса другим классам, которые являются его производными.
-
Экземпляр — это отдельный объект определенного класса. Например, объект obj, принадлежащий классу Circle, является экземпляром класса Circle.
-
Instantiation — создание экземпляра класса.
-
Метод — особый вид функции, который определен в определении класса.
-
Объект — уникальный экземпляр структуры данных, который определяется его классом. Объект включает в себя как члены данных (переменные класса и переменные экземпляра), так и методы.
-
Перегрузка оператора — назначение более чем одной функции определенному оператору.
@classmethod и @staticmethod
Я не пользовался ими ранее, так что сделал небольшое исследование.
- Декоратор <*@classmethod>* может быть вызван при помощи экземпляра класса, или напрямую, через собственный класс Python в качестве первого аргумента. В соответствии с документацией Python: он может быть вызван как в классе (например, C.f()), или в экземпляре (например, C().f()). Экземпляр игнорируется, за исключением его класса. Если метод класса вызван для выведенного класса, то объект выведенного класса передается в качестве подразумеваемого первого аргумента.
- Декоратор @classmethod, в первую очередь, используется как чередуемый конструктор или вспомогательный метод для инициализации.
- Декоратор <*@staticmethod>* — это просто функция внутри класса. Вы можете вызывать их обоих как с инициализацией класса так и без создания экземпляра класса. Обычно это применяется в тех случаях, когда у вас есть функция, которая, по вашему убеждению, имеет связь с классом. По большей части, это выбор стиля.
Если мы взглянем на пример кода, в котором показано, как работает декоратор, это может помочь понять основные принципы:
Python
# -*- coding: utf-8 -*-
class DecoratorTest(object):
«»»
Тестируем обычный метод против @classmethod против @staticmethod
«»»
def __init__(self):
«»»Конструктор»»»
pass
def doubler(self, x):
print(«умножаем на 2»)
return x*2
@classmethod
def class_tripler(klass, x):
print(«умножаем на 3: %s» % klass)
return x*3
@staticmethod
def static_quad(x):
print(«умножаем на 4»)
return x*4
if __name__ == «__main__»:
decor = DecoratorTest()
print(decor.doubler(5))
print(decor.class_tripler(3))
print(DecoratorTest.class_tripler(3))
print(DecoratorTest.static_quad(2))
print(decor.static_quad(3))
print(decor.doubler)
print(decor.class_tripler)
print(decor.static_quad)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# -*- coding: utf-8 -*- classDecoratorTest(object) «»» Тестируем обычный метод против @classmethod против @staticmethod def__init__(self) «»»Конструктор»»» pass defdoubler(self,x) print(«умножаем на 2») returnx*2 @classmethod defclass_tripler(klass,x) print(«умножаем на 3: %s»%klass) returnx*3 @staticmethod defstatic_quad(x) print(«умножаем на 4») returnx*4 if__name__==»__main__» decor=DecoratorTest() print(decor.doubler(5)) print(decor.class_tripler(3)) print(DecoratorTest.class_tripler(3)) print(DecoratorTest.static_quad(2)) print(decor.static_quad(3)) print(decor.doubler) print(decor.class_tripler) print(decor.static_quad) |
Этот пример демонстрирует, что вы можете вызывать обычный метод и оба метода декоратора одним и тем же путем
Обратите внимание на то, что вы можете вызывать обе функции @classmethod и @staticmethod прямо из класса или из экземпляра класса. Если вы попытаетесь вызвать обычную функцию при помощи класса (другими словами, DecoratorTest.doubler(2)), вы получите ошибку TypeError
Также стоит обратить внимание на то, что последний оператор вывода показывает, что decor.static_quad возвращает обычную функцию вместо связанного метода.