How Global Variables and Class Encapsulation work in Python

winstonmhango23

8 min read

Views: 186

In Python programming, understanding the concepts of global variables and class encapsulation is crucial for writing clean, maintainable, and efficient code.

Global variables are variables that are declared outside of any function or class and can be accessed throughout the entire program. They have a global scope, meaning they can be read and modified from any function or method within the program. Global variables are useful as they make it

  • Easy access from anywhere in the program.
  • Easy to store configuration settings or constants that need to be available globally.

Declaring and Accessing Global Variables

To declare a global variable, define it outside of any function. You can then access and modify this variable inside any function using the global keyword.

Example of a simple Global Variable

Let's look at a simple example where we use a global variable to store the interest rate for a bank account.

# Global variable
interest_rate = 0.05

def calculate_interest(balance):
    global interest_rate
    return balance * interest_rate

account_balance = 1000
print(f"Interest on account balance: {calculate_interest(account_balance)}")

In this example, the interest_rate variable is defined globally and accessed within the calculate_interest function to compute the interest on an account balance.

Real-Life Example: Banking Application

Let's consider a simple banking application where we track the total balance and perform transactions like deposit and withdrawal using global variables.

# Global variable for bank balance
bank_balance = 1000  # Initial balance

def deposit(amount):
    global bank_balance
    if amount > 0:
        bank_balance += amount
        print(f"Deposited {amount}. New balance: {bank_balance}")
    else:
        print("Deposit amount must be positive!")

def withdraw(amount):
    global bank_balance
    if 0 < amount <= bank_balance:
        bank_balance -= amount
        print(f"Withdrew {amount}. New balance: {bank_balance}")
    else:
        print("Invalid withdrawal amount!")

# Accessing global variable
print(f"Initial bank balance: {bank_balance}")
deposit(500)
withdraw(200)
print(f"Final bank balance: {bank_balance}")

Best Practices for Using Global Variables

While global variables can be useful, they should be used sparingly and with caution. Here are some best practices:

  1. Limit Scope: Use global variables only when necessary to avoid unintended side effects.
  2. Use Descriptive Names: Name your global variables clearly to indicate their purpose.
  3. Document Usage: Comment and document where and why global variables are used.
  4. Encapsulation: Consider using classes to encapsulate state and behavior, reducing the need for global variables.

Enhancing with Class Encapsulation

Encapsulation is one of the fundamental principles of object-oriented programming (OOP). It involves bundling the data (attributes) and methods (functions) that operate on the data into a single unit or class. Encapsulation helps to restrict direct access to some of an object's components, which can prevent the accidental modification of data and improve code modularity and maintenance.

Encapsulation in Python

Python achieves encapsulation through class definitions and by using access modifiers such as private and protected members.

Public Members: Accessible from anywhere. Protected Members: Indicated by a single underscore prefix (e.g., _balance), should not be accessed directly outside the class but can be accessed in subclasses. Private Members: Indicated by a double underscore prefix (e.g., __balance), inaccessible from outside the class and not accessible in subclasses.

To demonstrate a better approach, let's encapsulate the bank balance within a class:

class BankAccount:
    def __init__(self, account_holder, balance=0):
        self.account_holder = account_holder  # Public attribute
        self.__balance = balance  # Private attribute

    def deposit(self, amount):
        if amount > 0:
            self.__balance += amount
            print(f"Deposited {amount}. New balance is {self.__balance}.")
        else:
            print("Deposit amount must be positive!")

    def withdraw(self, amount):
        if 0 < amount <= self.__balance:
            self.__balance -= amount
            print(f"Withdrew {amount}. New balance is {self.__balance}.")
        else:
            print("Insufficient funds or invalid withdrawal amount!")

    def get_balance(self):
        return self.__balance

# Example usage
account = BankAccount("Alice")
account.deposit(500)
account.withdraw(150)
print(f"Account balance: {account.get_balance()}")

This is what is Happening in the code

  1. Class Definition:
    • class BankAccount: defines the BankAccount class.
  1. Constructor (__init__ method):
    • def __init__(self, account_holder, balance=0): initializes the instance attributes. account_holder is public, while __balance is private.
  1. Deposit Method:
    • def deposit(self, amount): allows adding funds to the account. It checks if the deposit amount is positive before updating the balance.
  1. Withdraw Method:
    • def withdraw(self, amount): allows withdrawing funds if the amount is within the available balance. It prevents invalid or excessive withdrawals.
  1. Balance Retrieval Method:
    • def get_balance(self): returns the current balance. This method provides controlled access to the private __balance attribute.
  1. Usage Example:
    • An instance of BankAccount is created with the account holder's name "Alice."
    • account.deposit(500) deposits $500 into Alice's account.
    • account.withdraw(150) withdraws $150 from Alice's account.
    • The current balance is printed using account.get_balance().

Combining Global Variables and Class Encapsulation

In some cases, you might need to use global variables in conjunction with class encapsulation. For instance, consider a scenario where the bank has a global interest rate that applies to all accounts, but each account is managed using encapsulation.

# Global variable
interest_rate = 0.05

class BankAccount:
    def __init__(self, account_holder, balance=0):
        self.account_holder = account_holder  # Public attribute
        self.__balance = balance  # Private attribute

    def deposit(self, amount):
        if amount > 0:
            self.__balance += amount
            print(f"Deposited {amount}. New balance is {self.__balance}.")
        else:
            print("Deposit amount must be positive!")

    def withdraw(self, amount):
        if 0 < amount <= self.__balance:
            self.__balance -= amount
            print(f"Withdrew {amount}. New balance is {self.__balance}.")
        else:
            print("Insufficient funds or invalid withdrawal amount!")

    def get_balance(self):
        return self.__balance

    def add_interest(self):
        global interest_rate
        interest = self.__balance * interest_rate
        self.__balance += interest
        print(f"Added interest: {interest}. New balance is {self.__balance}.")

# Example usage
account = BankAccount("Bob")
account.deposit(1000)
account.add_interest()
print(f"Account balance: {account.get_balance()}")

Here is an explanation of what is happening in the code above

  • Global Interest Rate:
    • The interest_rate global variable is used to apply a uniform interest rate across all accounts.
  • Add Interest Method:
    • def add_interest(self): calculates and adds interest to the account balance using the global interest_rate.
  • Usage Example:
    • An instance of BankAccount is created for "Bob."
    • $1000 is deposited into Bob's account.
    • Interest is added to Bob's account balance using the add_interest method.
    • The current balance, including the added interest, is printed.

Conclusion

Global variables and class encapsulation are powerful tools in Python that, when used correctly, can greatly enhance the functionality and maintainability of your code. Global variables provide easy access to values across the entire program, while encapsulation ensures that your data is protected and manipulated only in intended ways. By combining these concepts thoughtfully, as demonstrated in the bank account examples, you can build robust and reliable applications.

Recent Related Posts

Related Posts

Creating and uploading a Python package to the PyPi: Part 3 Creating The package and uploading to pypi.org

In this part of the series, we will walk you through the final steps of creating a Python package and uploading it to PyPi. We will use the example package bank_creator that we discussed in Part 2. The full code for this package can be found on GitHub.

Read More

Creating and uploading a Python package to the PyPi: Part 2 Creating Git repository and uploading to github

Read More

Creating and uploading a Python package to the PyPi: Part 1 Basics

Read More

© 2024 .