Найти - Пользователи
Полная версия: Расширение класса ImageDraw
Начало » Python для новичков » Расширение класса ImageDraw
1
dmitry_79
Добрый день. Есть желание попрактиковаться в ООП.
Начал решать задачку по расширению классов. Сразу возник вопрос как отличить класс от модуля?

При импорте библиотеки PIL : from PIL import Image, ImageDraw
ImageDrive - это класс или модуль?

При создании дочернего класса он должен унаследовать все атрибуты и методы родительского класса. Т.е если дочерний класс создать пустым то его экземпляры должны вести себя точно так же как экземпляры родительского класса.

Тогда почему не работает код в colabe ? выдает ошибку что в новом классе не существует атрибутов? Его родитель ведь определен?

Первая ячейка в колабе использует для рисования ImageDraw. Вторая - новый класс NewImageDrive.

xam1816
  
from PIL import ImageDraw
print(type(ImageDraw))
print(ImageDraw)
print(ImageDraw.ImageDraw)
print(ImageDraw.Image.Image)
dmitry_79
Это первое что я сделал.

<class ‘module’>
<class ‘type’>
<class ‘PIL.Image.Image’>

Как интерпретировать этот вывод?
Это все классы?
xam1816
без type выведи все
  
print(ImageDraw)
dmitry_79
Убрал type. Получил такой вывод:

<module ‘PIL.ImageDraw’ from ‘/usr/local/lib/python3.8/dist-packages/PIL/ImageDraw.py’>
<class ‘PIL.ImageDraw.ImageDraw’>
<class ‘PIL.Image.Image’>

Если я указываю эти имена в качестве родителя - все равно ругается на отсутсвие метода Draw
py.user.next
dmitry_79
При импорте библиотеки PIL : from PIL import Image, ImageDraw
ImageDrive - это класс или модуль?
  
>>> import PIL
>>> 
>>> import PIL.ImageDraw
>>> 
>>> PIL.ImageDraw
<module 'PIL.ImageDraw' from '/usr/lib64/python3.6/site-packages/PIL/ImageDraw.py'>
>>> 
>>> PIL.ImageDraw.ImageDraw
<class 'PIL.ImageDraw.ImageDraw'>
>>>
>>> PIL.ImageDraw.Draw
<function Draw at 0x7f67f7389f28>
>>>

dmitry_79
Есть желание попрактиковаться в ООП.
ООП - это не то, что ты думаешь. Сначала отыскиваются абстракции, затем абстракции преобразуются в объекты, затем объекты группируются в классы, затем классы выстраиваются в единую иерархию классов, затем единая иерархия классов разбивается на уровни абстракции. Если получилось всё это сделать, значит правильная иерархия найдена; если не получилось всё это сделать, значит надо по новой всё проделать, чтобы получить в конечном итоге правильную иерархию. Если же ты думаешь, что ООП - это просто записать класс и пронаследоваться от него, то такое “ООП” тебе просто ничего не даст ни на малых программах, ни на больших.

dmitry_79
Т.е если дочерний класс создать пустым
Нет такого понятия “дочерний класс”, есть понятие подкласс. Подкласс/субкласс и надкласс/суперкласс. Есть также базовый класс, который находится на самом верху иерархии классов и не имеет суперкласса. Есть также неправильное толкование терминов, которое породил Страуструп. Из-за этого есть путаница в понятиях, потому что многие из них одноимённые, а по смыслу разные.

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

dmitry_79
Первая ячейка в колабе использует для рисования ImageDraw. Вторая - новый класс NewImageDrive.
Ты лучше сбрось код сюда. Как-то не хочется в Google заходить, чтобы это было возможно запускать или редактировать. Так-то он тебе говорит, что ты пытаешься в классе найти Draw, которая является функцией в модуле.

help(PIL.ImageDraw)
FUNCTIONS
Draw(im, mode=None)
A simple 2D drawing interface for PIL images.

:param im: The image to draw in.
:param mode: Optional mode to use for color values. For RGB
images, this argument can be RGB or RGBA (to blend the
drawing into the image). For all other modes, this argument
must be the same as the image mode. If omitted, the mode
defaults to the mode of the image.
xam1816
dmitry_79
Убрал type. Получил такой вывод:
там написано что есть модуль, что есть класс.
dmitry_79
все равно ругается на отсутсвие метода Draw
чтобы расширить класс, нужно понимать из чего он состоит, для этого нужно смотреть в документации из чего он состоит. Либо использовать
  
help(ImageDraw)
если там что-то отсутствует, значит оно отсутствует и нет смысла вызывать это что-то отсутствующее
dmitry_79
Здорово! Спасибо за потраченное время на столь развернутый ответ!
Ваше видение ООП несколько отличается от того что имею я, со своим небольшим багажом.

Набросал следующий работающий код, который выводит красный треугольник в черном квадрате:
 from PIL import Image, ImageDraw
# Create empty black canvas
im = Image.new('RGB', (255, 255))
dr = ImageDraw.Draw(im)
dr.polygon([(30,30), (30, 230), (220,130)], fill = (255,0,0))
display(im)

display(im) - особенность вывода в Google Colab. (не понимаю почему Вы его боитесь… Он охренительно облегчает жизнь в изучении пайтона… но не буду спорить, не в этом суть вопроса)

Теперь хочу расширить класс ImageDraw создав его подкласс NewImageDraw который, будет рисовать такой же равносторониий треугольник но новым методом, которому нужно передать координаты левой вершины и длинну стороны.

Вот код с созданием нового подкласса который должен наследовать все методы родительского класса. Метод рисования треугольника в нем пока точно такой же как и в предидущем коде, только вызыватся он должен из дочернего класса:
 from PIL import Image, ImageDraw
#создание дочернего класса
class NewImageDraw(ImageDraw.ImageDraw):
  pass
# Create empty black canvas
im = Image.new('RGB', (255, 255))
dr = NewImageDraw.Draw(im)
dr.polygon([(30,30), (30, 230), (220,130)], fill = (255,0,0))
display(im)

При выполнении первого кода ошибок нет.
При выполении второго:


py.user.next
dmitry_79
Набросал следующий работающий код, который выводит красный треугольник в черном квадрате:
  
from PIL import Image, ImageDraw
# Create empty black canvas
im = Image.new('RGB', (255, 255))
dr = ImageDraw.Draw(im)
dr.polygon([(30,30), (30, 230), (220,130)], fill = (255,0,0))
display(im)
Вот этот код тоже выводит красный треугольник в чёрном квадрате
  
>>> from PIL import Image, ImageDraw
>>> 
>>> # Create empty black canvas
... im = Image.new('RGB', (255, 255))
>>> dr = ImageDraw.Draw(im)
>>> dr.polygon([(30,30), (30, 230), (220,130)], fill = (255,0,0))
>>> im.show()
>>>
Только для этого нужно просто в консоли питона запустить код.

dmitry_79
Вот код с созданием нового подкласса который должен наследовать все методы родительского класса. Метод рисования треугольника в нем пока точно такой же как и в предидущем коде, только вызыватся он должен из дочернего класса:
В нём нет метода рисования.

Вот этот рисуется через класс NewImageDraw
  
>>> from PIL import Image, ImageDraw
>>> 
>>> class NewImageDraw(ImageDraw.ImageDraw):
...   pass
... 
>>> im = Image.new('RGB', (255, 255))
>>> ndr = NewImageDraw(im)
>>> ndr.polygon([(30, 30), (30, 230), (220, 130)], fill = (255, 0, 0))
>>> im.show()
>>>
Как только ты метод .polygon() вызвал, тот сразу нарисовал это на картинке im.

dmitry_79
При выполении второго:
Я даже не знаю, кто тебя надоумил заняться этим “ООП”, которое не ООП. Ты же даже пространства имён не освоил, поэтому и не понимаешь, что никакого Draw там нет. Draw - это не метод класса, а это функция модуля. В модуле есть классы, а есть ещё функции, которые не принадлежат никаким классам. И вот эта Draw - одна из функций в модуле ImageDraw. А также в модуле ImageDraw есть класс с таким же именем ImageDraw. Если бы ты понимал пространства имён, что это такое и так далее, то для тебя бы эти сообщения об ошибках не представляли бы никакой загадки.
dmitry_79
Вооот! Спасибо большое я увидел свою ошибку! И понял смысл Ваших слов насчет пространства имен. …надеюсь что понял. Надо уделить больше внимания этому вопросу!
Еще раз спасибо!
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB