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:
- Limit Scope: Use global variables only when necessary to avoid unintended side effects.
- Use Descriptive Names: Name your global variables clearly to indicate their purpose.
- Document Usage: Comment and document where and why global variables are used.
- 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
- Class Definition:
- class BankAccount: defines the BankAccount class.
- Constructor (__init__ method):
- def __init__(self, account_holder, balance=0): initializes the instance attributes. account_holder is public, while __balance is private.
- Deposit Method:
- def deposit(self, amount): allows adding funds to the account. It checks if the deposit amount is positive before updating the balance.
- Withdraw Method:
- def withdraw(self, amount): allows withdrawing funds if the amount is within the available balance. It prevents invalid or excessive withdrawals.
- Balance Retrieval Method:
- def get_balance(self): returns the current balance. This method provides controlled access to the private __balance attribute.
- 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.