Python’s Member Definitions and Access

But first, let’s take a moment to appreciate how far we’ve come since the days when you had to manually write out every single line of code for your programs.

Back then, if you wanted to create an object with some properties and methods, you would have to define each one individually like this:

# Define a class called MyObject, inheriting from the object class
class MyObject(object):
    # Define a constructor method that takes in a parameter x and assigns it to the instance variable self.x
    def __init__(self, x):
        self.x = x
    
    # Define a method called do_something that prints a message and uses the instance variable self.x
    def do_something(self):
        print("Doing something with", self.x)
        
    # Define a method called get_x that returns the instance variable self.x
    def get_x(self):
        return self.x

But nowadays, we have the luxury of using member definitions and access to simplify our code!

So what exactly are these magical concepts? Well, let’s start with member definitions. These allow us to define properties or methods for an object in a more concise way:



# First, we define a class called MyObject, which is a blueprint for creating objects with certain properties and methods.
class MyObject(object):
    # The __init__ method is a special method that is automatically called when an object is created from this class.
    # It initializes the object with a private property called __x, which is set to the value passed in as an argument.
    def __init__(self, x):
        self.__x = x  # Private property
    
    # The @property decorator allows us to define a getter method for the private property __x.
    # This method can be accessed like a regular property, without the need for parentheses.
    @property
    def x(self):
        return self.__x   # Public getter method for the private property
        
    # The @setter decorator allows us to define a setter method for the private property __x.
    # This method can be used to set the value of __x, but with some validation logic.
    @x.setter
    def x(self, value):
        # The isinstance() function checks if the value passed in is an instance of the specified data type.
        # In this case, we are checking if the value is an integer.
        # The and keyword allows us to add another condition to the if statement.
        # Here, we are also checking if the value is greater than or equal to 0.
        if isinstance(value, int) and value >= 0:
            self.__x = value   # Setter method with validation logic
    
    # This method simply prints a message with the value of the property __x.
    def do_something(self):
        print("Doing something with", self.x)

As you can see, we’ve replaced the `get_x()` and `set_x()` methods from before with a property called `x`. This allows us to access or modify the private property using dot notation:

# Creating an instance of MyObject class with initial value of 5
obj = MyObject(5)

# Printing the value of x property using dot notation
print(obj.x)

# Modifying the value of x property using dot notation
obj.x = 10

# The property x is defined using the @property decorator, which allows us to access or modify the private property using dot notation
# The getter method is automatically called when accessing the property, while the setter method is called when modifying the property
# This eliminates the need for separate get_x() and set_x() methods
# The property also allows for validation logic to be implemented in the setter method, ensuring the property is set to a valid value
# In this case, the value of x is set to 10, which is within the valid range for the property
# This makes the code more concise and readable, improving overall functionality and maintainability

But what about access? Well, that’s where things get interesting!In Python, we have two types of member access: public and private. Public members can be accessed from anywhere in our code, while private members are only accessible within their own class or object.

To make a member private, simply prefix it with an underscore (`__`) like this:

# Defining a class named MyObject
class MyObject(object):
    # Defining a constructor method with a parameter x
    def __init__(self, x):
        # Declaring a private property named __x and assigning it the value of x
        self.__x = x   # Private property
    
    # Defining a getter method for the private property named x
    @property
    def x(self):
        # Returning the value of the private property __x
        return self.__x   # Public getter method for the private property
        
    # Defining a setter method for the private property named x
    @x.setter
    def x(self, value):
        # Checking if the value passed is an integer and greater than or equal to 0
        if isinstance(value, int) and value >= 0:
            # Assigning the value to the private property __x
            self.__x = value   # Setter method with validation logic

As you can see, we’ve made the `__x` property private by prefixing it with an underscore. This means that it cannot be accessed directly from outside of its class or object:

# Creating an instance of MyObject class with argument 5
obj = MyObject(5)

# Trying to print the private property __x, which raises an AttributeError
# because private properties cannot be accessed directly from outside the class or object
print(obj.__x)

But we can still access the `__x` property through its public getter method:

# Accessing the `__x` property through its public getter method
print(obj.x) # Accessing the x property through its getter method

And with private members, we can also ensure that certain properties or methods are only accessible within their own class or object, which helps to prevent errors and improve the overall quality of our code.

Later!

SICORPS