-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #9 from davidhozic/develop
Merge develop for release
- Loading branch information
Showing
8 changed files
with
234 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
=================== | ||
Abstract classes | ||
=================== | ||
|
||
Abstract classes in Object Oriented Programming (OOP) are classes that cannot be instantiated. | ||
In Python, abstract classes can be by inheriting the :class:`abc.ABC` class. Abstract classes also need to have | ||
abstract methods, otherwise Python will not treat the class as abstract. Trying to create an instance (object) | ||
from an abstract class results in a TypeError exception. | ||
|
||
.. code-block:: python | ||
from abc import ABC, abstractmethod | ||
class MyAbstractClass(ABC): | ||
@abstractmethod | ||
def some_method(self): | ||
pass | ||
class MyClass(MyAbstractClass): | ||
def some_method(self): | ||
return 5 * 5 | ||
# OK | ||
my_instance = MyClass() | ||
# TypeError: Can't instantiate abstract class MyClass with abstract method some_method | ||
my_abstract_instance = MyAbstractClass() | ||
Let's modify our example from :ref:`Polymorphism`. | ||
|
||
.. code-block:: python | ||
:linenos: | ||
:emphasize-lines: 1, 8, 12 | ||
from abc import ABC, abstractmethod | ||
import tkinter as tk | ||
import tkinter.ttk as ttk | ||
import tkclasswiz as wiz | ||
# An abstract class | ||
class Wheel(ABC): | ||
def __init__(self, diameter: float): | ||
self.diameter = diameter | ||
@abstractmethod | ||
def get_info(self) -> str: | ||
pass | ||
class WinterWheel(Wheel): | ||
def get_info(self) -> str: | ||
return "Wheel for winter." | ||
class SummerWheel(Wheel): | ||
def get_info(self) -> str: | ||
return "Wheel for summer." | ||
class Car: | ||
def __init__(self, name: str, speed: float, wheels: list[Wheel]): | ||
self.name = name | ||
self.speed = speed | ||
self.wheels = wheels | ||
if speed > 50_000: | ||
raise ValueError("Car can go up to 50 000 km / h") | ||
if len(wheels) != 4: | ||
raise ValueError("The car must have 4 wheels!") | ||
# Tkinter main window | ||
root = tk.Tk("Test") | ||
# Modified tkinter Combobox that will store actual objects instead of strings | ||
combo = wiz.ComboBoxObjects(root) | ||
combo.pack(fill=tk.X, padx=5) | ||
def make_car(old = None): | ||
""" | ||
Function for opening a window either in new definition mode (old = None) or | ||
edit mode (old != None) | ||
""" | ||
assert old is None or isinstance(old, wiz.ObjectInfo) | ||
window = wiz.ObjectEditWindow() # The object definition window / wizard | ||
window.open_object_edit_frame(Car, combo, old_data=old) # Open the actual frame | ||
def print_defined(): | ||
data = combo.get() | ||
data = wiz.convert_to_objects(data) # Convert any abstract ObjectInfo objects into actual Python objects | ||
print(f"Object: {data}; Type: {type(data)}",) # Print the object and it's datatype | ||
# Main GUI structure | ||
ttk.Button(text="Define Car", command=make_car).pack() | ||
ttk.Button(text="Edit Car", command=lambda: make_car(combo.get())).pack() | ||
ttk.Button(text="Print defined", command=print_defined).pack() | ||
root.mainloop() | ||
We can see that the ``Wheel`` is now an abstract class. | ||
It is then inherited by ``WinterWheel`` and ``SummerWheel``. | ||
If we try to define the ``wheels`` parameter of our ``Car`` object, only these two inherited classes | ||
will be definable. | ||
|
||
.. image:: ./images/new_define_frame_list_abstractclass.png | ||
:width: 15cm | ||
|
||
We can see that while ``WinterWheel`` and ``SummerWheel`` are definable (due to :ref:`Polymorphism`), | ||
``Wheel`` is not. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,3 +13,5 @@ Index: | |
validation | ||
annotations | ||
conversion | ||
polymorphism | ||
abstractclasses |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
|
||
==================================== | ||
Polymorphism | ||
==================================== | ||
|
||
Polymorphism is a term used to describe the phenomenon of something appearing in multiple forms. | ||
In nature an example would be a dog. A dog can appear in different forms (breeds). It also means | ||
that multiple dog forms (breeds) are all derived from a common form - dog. | ||
|
||
In the Object Oriented Programming (OOP), this means that an object might appear as either | ||
an instance of a its actual class or an instance of a superclass. | ||
|
||
Let's modify our original guide example: | ||
|
||
|
||
.. code-block:: python | ||
:linenos: | ||
:emphasize-lines: 10,11,13,14,22 | ||
import tkinter as tk | ||
import tkinter.ttk as ttk | ||
import tkclasswiz as wiz | ||
# Normal Python classes with annotations (type hints) | ||
class Wheel: | ||
def __init__(self, diameter: float): | ||
self.diameter = diameter | ||
class WinterWheel(Wheel): | ||
pass | ||
class SummerWheel(Wheel): | ||
pass | ||
class Car: | ||
def __init__( | ||
self, | ||
name: str, | ||
speed: float, | ||
wheels: list[Wheel] | ||
): | ||
self.name = name | ||
self.speed = speed | ||
self.wheels = wheels | ||
if speed > 50_000: | ||
raise ValueError("Car can go up to 50 000 km / h") | ||
if len(wheels) != 4: | ||
raise ValueError("The car must have 4 wheels!") | ||
# Tkinter main window | ||
root = tk.Tk("Test") | ||
# Modified tkinter Combobox that will store actual objects instead of strings | ||
combo = wiz.ComboBoxObjects(root) | ||
combo.pack(fill=tk.X, padx=5) | ||
def make_car(old = None): | ||
""" | ||
Function for opening a window either in new definition mode (old = None) or | ||
edit mode (old != None) | ||
""" | ||
assert old is None or isinstance(old, wiz.ObjectInfo) | ||
window = wiz.ObjectEditWindow() # The object definition window / wizard | ||
window.open_object_edit_frame(Car, combo, old_data=old) # Open the actual frame | ||
def print_defined(): | ||
data = combo.get() | ||
data = wiz.convert_to_objects(data) # Convert any abstract ObjectInfo objects into actual Python objects | ||
print(f"Object: {data}; Type: {type(data)}",) # Print the object and it's datatype | ||
# Main GUI structure | ||
ttk.Button(text="Define Car", command=make_car).pack() | ||
ttk.Button(text="Edit Car", command=lambda: make_car(combo.get())).pack() | ||
ttk.Button(text="Print defined", command=print_defined).pack() | ||
root.mainloop() | ||
We can see that two new classes are created - ``WinterWheel`` and ``SummerWheel``. | ||
We also see that ``Car``'s ``wheels`` parameter is still a list of type ``Wheel``. | ||
TkClassWizard not only considers the annotated type when constructing a GUI, but also the annotated type's subclasses, | ||
implementing the concept of polymorphism, thus allowing us definition of | ||
``Wheel``, ``WinterWheel`` and ``SummerWheel`` classes. | ||
|
||
.. image:: ./images/new_define_frame_list_polymorphism.png | ||
:width: 15cm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters