# Intro to Python Dataclasses

from dataclasses import dataclass

# Here is a fantastic in-depth guide for Data Classes
# https://www.dataquest.io/blog/how-to-use-python-data-classes/

# In Python, a data class is a class that is designed to only hold data values.
# They aren't different from regular classes, but they usually don't have any
# other methods. They are typically used to store information that will be
# passed between different parts of a program or a system.

# Data classes automatically create the __init__ method (which is called
# a "constructor" and will be discussed in a subsequent totorial).
# This saves a fair bit of coding when a class is designed to just contain
# attributes/variables, and reduces the liklihood of errors.

# A dataclass is created by putting "@dataclass" by itself on the line
# before the class definition statement
@dataclass
class Shape():
    label: str=""
    fill: bool = True

# Dataclasses can inherit from parent classes just like traditional classes.
# Class inheritance and other class details such as methods will be discussed
# in more detail in a subsequent tutorial.
@dataclass
class Circle(Shape):
    center_x: int = 0
    center_y: int = 0
    radius: int = 0

# In the above class definition, all attributes have default values.
# This means that a new object can be instantiated without passing
# any parameters to the class. i.e. my_circle = Circle()
#
# Attributes do not have to have default values provided.
# However, there are two requirements if they do not.
#    1) All parameters without default values must have values
#       provided when instantiating an object.
#       Such as: my_circle = Circle("Tiny")
#    2) Attributes without default values MUST be declared in the
#       class definition BEFORE any parameters with default values.
#       They cannot come after.

# Instantiate a Circle() object with default values
my_circle = Circle()
# Change one of the class variables/attributes
my_circle.label = "Boss"
print(my_circle)
# If values for attributes are passed to the class they must be in the
# same order as the attributes listed in the class definition.
# If instantiating a child class then all parent parameters must be
# specified before those in the child.
my_circle = Circle("B1", True, 40, 100, 40)
print(my_circle)
# Named Parameters: Parameters passed to the class can be named. This
# serves two purposes. The first is that it makes the instantiation
# unambiguous which can be helpful if the class has many attributes.
# The second is that it allows a specific parameter to be assinged
# a value without specifying all of the intervening parameters.
my_circle = Circle("But1", radius=40)
print(my_circle)