13 KiB
Отчет по теме 9
Шинкаренко Варвара, А-02-23
1. Настроили рабочий каталог
import os
os.chdir('C:\\Users\\LENOVO\\Desktop\\python-labs\\TEMA9')
2. Классов и их наследников
2.1. Создание автономного класса
class Class1:
def zad_zn(self, znach):
self.data = znach # self - ссылка на экземпляр класса
def otobrazh(self):
print(self.data)
Класс — это шаблон для создания объектов (экземпляров). Он определяет свойства (данные) и методы (функции), которые будут доступны у созданных объектов. У этого класса есть два метода: zad_zn (устанавливает значение свойства объекта) и otobrazh (выводит это значение на экран). Еще у него есть один атрибут - data. self — это обязательный первый параметр всех методов в классе ссылающийся на конкретный экземпляр класса и нужный для определения обращения к атрибутам и методам.
z1 = Class1()
z2 = Class1()
z1.zad_zn('экз.класса 1')
z2.zad_zn(-632.453)
z1.otobrazh()
экз.класса 1
z2.otobrazh()
-632.453
z1.data = 'Новое значение атрибута у экз. 1'
z1.otobrazh()
Новое значение атрибута у экз. 1
# Если вывести имя экземпляра без чего-либо еще, вернется адрес в памяти z1
<__main__.Class1 object at 0x000001D1B6566090>
2.2. Создание класса-наследника
class Class2(Class1):
def otobrazh(self):
print('значение =', self.data)
z3 = Class2()
z3
<__main__.Class2 object at 0x000001D1B66F9370>
dir(z3)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__',
'__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__',
'__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'otobrazh', 'zad_zn']
Объекты с нижними подчеркиваниями - встроенные атрибуты и методы, которые есть у каждого класса. Кроме этого, есть унаследованные от родительского класса методы, один из которых переопределен. Этот пример хорошо иллюстрирует сразу две парадигмы ООП: наследование и полиморфизм. При создании дочернего класса атрибуты и методы родительского класса переносятся дочернему. В дочернем классе методы могут быть переопределены. То есть метод с одинаковым именем в разных классах будет вести себя по-разному. Это - пример полиморфизма.
z3.zad_zn('Совсем новое')
z3.otobrazh()
значение = Совсем новое
# Но при этом:
z1.otobrazh()
Новое значение атрибута у экз. 1
del z1, z2, z3
3. Использование классов, содержащихся в модулях
from mod3 import Class1
z4 = Class1()
z4.otobrazh()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "D:\STUDY\POAS\Тема9\progs\mod3.py", line 5, in otobrazh
print(self.data)
^^^^^^^^^
AttributeError: 'Class1' object has no attribute 'data'
Ошибка возникла потому, что otobrazh было вызвано раньше, чем метод, инициализирующий атрибут data. Проще говоря, мы пытаемся напечатать значение несуществующего объекта.
del z4
import mod3
z4 = mod3.Class2()
z4.zad_zn('Класс из модуля')
z4.otobrazh()
значение = Класс из модуля
Здесь otobrazh - это метод класса Class2 и соответствующего ему экземпляра класса z2. Этот метод не принимает значимых параметров, кроме формального self.
mod3.otobrazh('Объект') значение объекта = Объект
Здесь otobrazh - это уже просто функция, глобально определенная в модуле mod3. Она определена вне пользовательского класса, поэтому атрибута data в ее зоне доступа нет. Так что эта функция принимает один обязательный параметр - выводимую переменную.
4. Использование специальных методов
class Class3(Class2): # Наследник класса Class2, а через него – и класса Class1
def __init__(self,znach): # Конструктор-вызывается при создании нового экземпляра класса
self.data=znach
def __add__(self,drug_zn): #Вызывается, когда экземпляр участвует в операции «+»
return Class3(self.data + drug_zn)
def zad_dr_zn(self,povtor): #А это - обычный метод
self.data *= povtor
from mod3 import Class3
# Примечание: при импорте класса его родительские классы подгружаются автоматически
z5 = Class3('abc')
z5.otobrazh()
значение = abc
z6 = z5 + 'def'
z6.otobrazh()
значение = abcdef
z6.zad_dr_zn(3)
z6.otobrazh()
значение = abcdefabcdefabcdef
5. Присоединение атрибутов к классу
dir(Class3)
['__add__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__',
'__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
'__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'otobrazh', 'zad_dr_zn', 'zad_zn']
Class3.fio='Иванов И.И.'
dir(Class3)
['__add__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__',
'__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
'__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'fio', 'otobrazh', 'zad_dr_zn', 'zad_zn']
z7 = Class3(123)
dir(z7)
['__add__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__',
'__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
'__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'data', 'fio', 'otobrazh', 'zad_dr_zn', 'zad_zn']
В dir(z7), по сравнению с dir(Class3), указаны также атрибуты, относящиеся непосредтсвенно к экзаемпляру. dir(Class3) показывает атрибуты класса Class3. Это включает методы, свойства, и встроенные специальные методы класса, но не атрибуты конкретных объектов, созданных на основе этого класса. dir(z7) показывает атрибуты объекта z7. Это включает все атрибуты класса, а также любые другие атрибуты, добавленные динамически постфактум.
dir(z7)==dir(Class3)
False
# Добавим еще один атрибут:
z7.rozden='1987'
dir(z7)
['__add__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__',
'__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
'__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'data', 'fio', 'otobrazh', 'rozden', 'zad_dr_zn', 'zad_zn']
# При этом у dir(Class3) его не будет:
dir(Class3)
['__add__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__',
'__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
'__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'fio', 'otobrazh', 'zad_dr_zn', 'zad_zn']
6. Выявление родительских классов
Class3.__bases__
(<class 'mod3.Class2'>,)
Class2.__bases__
(<class 'mod3.Class1'>,)
Class1.__bases__
(<class 'object'>,)
# При этом:
object.__bases__
()
Полный порядок наследования (Method Resolution Order)
Class3.__mro__
(<class 'mod3.Class3'>, <class 'mod3.Class2'>, <class 'mod3.Class1'>, <class 'object'>)
ZeroDivisionError.__mro__
(<class 'ZeroDivisionError'>, <class 'ArithmeticError'>, <class 'Exception'>, <class 'BaseException'>, <class 'object'>)
IndexError.__mro__
(<class 'IndexError'>, <class 'LookupError'>, <class 'Exception'>, <class 'BaseException'>, <class 'object'>)
7. Создание свойства класса.
class Class4:
def __init__(sam,znach):
sam.__prm=znach
def chten(sam):
return sam.__prm --- геттер
def zapis(sam,znch):
sam.__prm=znch --- сеттер
def stiran(sam):
del sam.__prm --- делеттер
svojstvo=property(chten,zapis,stiran)
Свойства нужны для того, чтобы инкапсулировать атрибут, т.е. ограничить прямой доступ к изменению атрибута. Еще с их помощью можно проверять правильность введенных данных.
importlib.reload(mod3)
<module 'mod3' from 'D:\\STUDY\\POAS\\Тема9\\progs\\mod3.py'>
from mod3 import Class4
exempl=Class4(12)
exempl.svojstvo
12
exempl.svojstvo=45
print(exempl.svojstvo)
45
del exempl.svojstvo
exempl.svojstvo
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "D:\STUDY\POAS\Тема9\progs\mod3.py", line 25, in chten
return sam.__prm
^^^^^^^^^
AttributeError: 'Class4' object has no attribute '_Class4__prm'
#Такой вывод происходит, потому что этот атрибут уже удален.
Пункт 8. Рассмотрите пример представления в виде класса модели системы автоматического регулиро-вания (САР), состоящей из последовательного соединения усилителя и двух инерционных звеньев, охваченных отрицательной обратной связью с усилителем.
# SAU.pu
class SAU:
def __init__(self, zn_param):
self.param = zn_param
self.ypr = [0, 0]
def zdn_zn(self, upr):
self.x = upr
def model(self):
def inerz(x, T, yy):
return (x + T * yy) / (T + 1)
y0 = self.x - self.ypr[1] * self.param[3] # Обр.связь с усилителем 2
y1 = self.param[0] * y0 # Усилитель1
y2 = inerz(y1, self.param[1], self.ypr[0]) # Инерционное звено1
y3 = inerz(y2, self.param[2], self.ypr[1]) # Инерционное звено2
self.ypr[0] = y2
self.ypr[1] = y3
def otobraz(self):
print('y=', self.ypr[1])
# testSAU.py
###main_SAU
prm=[2.5,4,1.3,0.8] #Параметры модели: коэф.усиления, 2 пост.времени, обратная связь
from SAU import *
xx=[0]+[1]*20 #Входной сигнал – «ступенька»
SAUe=SAU(prm) # Создаём экземпляр класса
yt=[]
for xt in xx: # Прохождение входного сигнала
SAUe.zdn_zn(xt)
SAUe.model()
SAUe.otobraz()
yt.append(SAUe.ypr[1])
import pylab
pylab.plot(yt)
pylab.show()
Вывод:
y= 0.0
y= 0.2173913043478261
y= 0.4763705103969754
y= 0.686594887811293
y= 0.8199324616478645
y= 0.8837201137353929
y= 0.8994188484874774
y= 0.8892777072047301
y= 0.870097963179993
y= 0.8518346102696789
y= 0.8387499784485772
y= 0.8314204114211459
y= 0.8286051955249649
y= 0.8285656555914835
y= 0.8297915186846528
y= 0.8312697736438287
y= 0.8324765218921963
y= 0.8332456979978418
y= 0.8336163607592184
y= 0.8337101315489143
y= 0.833654237067147