Python Classes

#Python supports the object-oriented programming paradigm through classes
#class is like the blueprint for a house
#create several houses and even a complete neighborhood. Each concrete house is an object or instance that’s derived from the blueprint

#Each instance can have its own properties, such as color, owner, and interior design
#properties carry what’s commonly known as the object’s state
#Instances can also have different behaviors, such as locking the doors

# In Python, attributes are variables defined inside a class with the purpose of storing all the required data for the class to work.

#Methods are functions that you define within a class
#Attributes and methods are collectively referred to as members of a class or object

#Finally, you can use classes to build class hierarchies. This way, you’ll promote code reuse and remove repetition throughout your codebase.


  class ClassName: #classbody pass
  #As an example of how to define attributes and methods, say that you need a Circle class to model different circles in a drawing application. #Initially, your class will have a single attribute to hold the radius. It’ll also have a method to calculate the circle’s area: #In Python, the first argument of most methods is self #This argument holds a reference to the current object so that you can use it inside the class import math class Circle: def __init__(self, radius): #This method is known as the object initializer because it defines and sets the initial values for your attributes self.radius = radius def calculate_area(self): return round(math.pi * self.radius **2, 2) #this is a method
#The action of creating concrete objects from an existing class is known as instantiation.
# In Python, the class constructor accepts the same arguments as the .__init__() method. In this example, the Circle class expects the radius argument
  circle_1 = Circle(42) circle_2 = Circle(7)
  circle_1
#Accessing Attributes and Methods
#obj.attribute_name
#obj.method_name()
  circle_1.radius
  circle_1.calculate_area()
  circle_1.radius = 100
  circle_1.radius
#Public vs Non-Public Members
#In Python, all attributes are accessible in one way or another.

Â

#Public Use the normal naming pattern. radius, calculate_area()
#Non-public Include a leading underscore in names. _radius, _calculate_area()
#https://realpython.com/python-classes/
#Name Mangling

#add two leading underscores to attribute and method names. This naming convention triggers what’s known as name mangling.
#In other words, mangled names aren’t available for direct access. They’re not part of a class’s public API.
  class SampleClass: def __init__(self, value): self.__value = value def __method(self): print(self.__value)
  sample_instance = SampleClass("Hello!")
  vars(sample_instance)
  vars(SampleClass)
  #both of these error out: sample_instance.__value sample_instance.__method() #In this class, .__value and .__method() have two leading underscores, so their names are mangled to ._SampleClass__value and ._SampleClass__method() #Because of this internal renaming, you can’t access the attributes from outside the class
  #correct way to do it sample_instance._SampleClass__value sample_instance._SampleClass__method()

#Classes are the building blocks of object-oriented programming in Python.

#In short, Python classes can help you write more organized, structured, maintainable, reusable, flexible, and user-friendly code.
#Class attributes: A class attribute is a variable that you define in the class body directly.
#All the objects that you create from a particular class share the same class attributes with the same original values.
#f you change a class attribute, then that change affects all the derived objects.


  class ObjectCounter: num_instances = 0 def __init__(self): ObjectCounter.num_instances += 1 #type(self).num_instances += 1
  ObjectCounter()
  ObjectCounter.num_instances
#Instance attributes: An instance is a variable that you define inside a method. Instance attributes belong to a concrete instance of a given class
  class Car: def __init__(self, make, model, year, color): self.make = make self.model = model self.year = year self.color = color self.started = False self.speed = 0 self.max_speed = 200
  toyota_camry = Car("Toyota", "Camry", 2022, "Red")
  toyota_camry.make
  toyota_camry.speed
  ford_mustang = Car("Ford", "Mustang", 2022, "Black")
  ford_mustang.make
#dict attribute
#In Python, both classes and instances have a special attribute called .__dict__. This attribute holds a dictionary containing the writable members of the underlying class or instance.
  class SampleClass: class_attr = 100 def __init__(self, instance_attr): self.instance_attr = instance_attr def method(self): print(f"Class attribute: {self.class_attr}") print(f"Instance attribute: {self.instance_attr}")
  SampleClass.class_attr
  SampleClass.__dict__
  SampleClass.__dict__["class_attr"]
  instance = SampleClass("Hello!") instance.instance_attr instance.method() instance.__dict__ instance.__dict__["instance_attr"] instance.__dict__["instance_attr"] = "Hello, Pythonista!" instance.instance_attr

#Dynamic Class and Instance Attributes

  class Record: """Hold a record of data."""
  john = { "name": "John Doe", "position": "Python Developer", "department": "Engineering", "salary": 80000, "hire_date": "2020-01-01", "is_manager": False, }
  john_record = Record() for field, value in john.items(): setattr(john_record, field, value) john_record.name 'John Doe' john_record.department 'Engineering' john_record.__dict__ { 'name': 'John Doe', 'position': 'Python Developer', 'department': 'Engineering', 'salary': 80000, 'hire_date': '2020-01-01', 'is_manager': False }
  class User: pass # Add instance attributes dynamically jane = User() jane.name = "Jane Doe" jane.job = "Data Engineer" jane.__dict__ {'name': 'Jane Doe', 'job': 'Data Engineer'} # Add methods dynamically def __init__(self, name, job): self.name = name self.job = job User.__init__ = __init__ User.__dict__ linda = User("Linda Smith", "Team Lead") linda.__dict__
#you’ve just used a pass statement as a placeholder, which is Python’s way of doing nothing.
#Even though this capability of Python may seem neat, you must use it carefully because it can make your code difficult to understand and reason about.
  #validate the radius to ensure that it only stores positive numbers. How would you do that without changing your class interface? #The quickest approach to this problem is to use a property and implement the validation logic in the setter method. import math class Circle: def __init__(self, radius): self.radius = radius #To turn an existing attribute like .radius into a property, you typically use the @property decorator to write the getter method # The getter method must return the value of the attribute. In this example, the getter returns the circle’s radius, which is stored in the non-public ._radius attribute. @property def radius(self): return self._radius @radius.setter def radius(self, value): if not isinstance(value, int | float) or value <= 0: raise ValueError("positive number expected") self._radius = value def calculate_area(self): return round(math.pi * self._radius**2, 2)
  circle_1 = Circle(100) circle_1.radius
  circle_1.radius = 0
  circle_2 = Circle(-100)
  class Square: def __init__(self, side): self.side = side @property def side(self): return self._side @side.setter def side(self, value): if not isinstance(value, int | float) or value <= 0: raise ValueError("positive number expected") self._side = value def calculate_area(self): return round(self._side**2, 2)
   class PositiveNumber: def __set_name__(self, owner, name): self._name = name def __get__(self, instance, owner): return instance.__dict__[self._name] def __set__(self, instance, value): if not isinstance(value, int | float) or value <= 0: raise ValueError("positive number expected") instance.__dict__[self._name] = value class Circle: radius = PositiveNumber() def __init__(self, radius): self.radius = radius def calculate_area(self): return round(math.pi * self.radius**2, 2) class Square: side = PositiveNumber() def __init__(self, side): self.side = side def calculate_area(self): return round(self.side**2, 2)
  circle = Circle(100)
  circle.radius = 0
#https://realpython.com/python-classes/
#time to watch youtube videos

Ryan is a Data Scientist at a fintech company, where he focuses on fraud prevention in underwriting and risk. Before that, he worked as a Data Analyst at a tax software company. He holds a degree in Electrical Engineering from UCF.

Leave a Reply

Your email address will not be published. Required fields are marked *