Monday, August 10, 2020

Real Python: Pass by Reference in Python: Background and Best Practices

After gaining some familiarity with Python, you may notice cases in which your functions don’t modify arguments in place as you might expect, especially if you’re familiar with other programming languages. Some languages handle function arguments as references to existing variables, which is known as pass by reference. Other languages handle them as independent values, an approach known as pass by value.

If you’re an intermediate Python programmer who wishes to understand Python’s peculiar way of handling function arguments, then this tutorial is for you. You’ll implement real use cases of pass-by-reference constructs in Python and learn several best practices to avoid pitfalls with your function arguments.

In this tutorial, you’ll learn:

  • What it means to pass by reference and why you’d want to do so
  • How passing by reference differs from both passing by value and Python’s unique approach
  • How function arguments behave in Python
  • How you can use certain mutable types to pass by reference in Python
  • What the best practices are for replicating pass by reference in Python

Free Bonus: 5 Thoughts On Python Mastery, a free course for Python developers that shows you the roadmap and the mindset you'll need to take your Python skills to the next level.

Defining Pass by Reference

Before you dive into the technical details of passing by reference, it’s helpful to take a closer look at the term itself by breaking it down into components:

  • Pass means to provide an argument to a function.
  • By reference means that the argument you’re passing to the function is a reference to a variable that already exists in memory rather than an independent copy of that variable.

Since you’re giving the function a reference to an existing variable, all operations performed on this reference will directly affect the variable to which it refers. Let’s look at some examples of how this works in practice.

Below, you’ll see how to pass variables by reference in C#. Note the use of the ref keyword in the highlighted lines:

using System;

// Source:
// https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/passing-parameters
class Program
{
    static void Main(string[] args)
    {
        int arg;

        // Passing by reference.
        // The value of arg in Main is changed.
        arg = 4;
        squareRef(ref arg);
        Console.WriteLine(arg);
        // Output: 16
    }

    static void squareRef(ref int refParameter)
    {
        refParameter *= refParameter;
    }
}

As you can see, the refParameter of squareRef() must be declared with the ref keyword, and you must also use the keyword when calling the function. Then the argument will be passed in by reference and can be modified in place.

Python has no ref keyword or anything equivalent to it. If you attempt to replicate the above example as closely as possible in Python, then you’ll see different results:

>>>
>>> def main():
...     arg = 4
...     square(arg)
...     print(arg)
...
>>> def square(n):
...     n *= n
...
>>> main()
4

In this case, the arg variable is not altered in place. It seems that Python treats your supplied argument as a standalone value rather than a reference to an existing variable. Does this mean Python passes arguments by value rather than by reference?

Not quite. Python passes arguments neither by reference nor by value, but by assignment. Below, you’ll quickly explore the details of passing by value and passing by reference before looking more closely at Python’s approach. After that, you’ll walk through some best practices for achieving the equivalent of passing by reference in Python.

Contrasting Pass by Reference and Pass by Value

When you pass function arguments by reference, those arguments are only references to existing values. In contrast, when you pass arguments by value, those arguments become independent copies of the original values.

Let’s revisit the C# example, this time without using the ref keyword. This will cause the program to use the default behavior of passing by value:

using System;

// Source:
// https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/passing-parameters
class Program
{
    static void Main(string[] args)
    {
        int arg;

        // Passing by value.
        // The value of arg in Main is not changed.
        arg = 4;
        squareVal(arg);
        Console.WriteLine(arg);
        // Output: 4
    }

    static void squareVal(int valParameter)
    {
        valParameter *= valParameter;
    }
}

Here, you can see that squareVal() doesn’t modify the original variable. Rather, valParameter is an independent copy of the original variable arg. While that matches the behavior you would see in Python, remember that Python doesn’t exactly pass by value. Let’s prove it.

Python’s built-in id() returns an integer representing the memory address of the desired object. Using id(), you can verify the following assertions:

  1. Function arguments initially refer to the same address as their original variables.
  2. Reassigning the argument within the function gives it a new address while the original variable remains unmodified.

In the below example, note that the address of x initially matches that of n but changes after reassignment, while the address of n never changes:

>>>
>>> def main():
...     n = 9001
...     print(f"Initial address of n: {id(n)}")
...     increment(n)
...     print(f"  Final address of n: {id(n)}")
...
>>> def increment(x):
...     print(f"Initial address of x: {id(x)}")
...     x += 1
...     print(f"  Final address of x: {id(x)}")
...
>>> main()
Initial address of n: 140562586057840
Initial address of x: 140562586057840
  Final address of x: 140562586057968
  Final address of n: 140562586057840

Read the full article at https://realpython.com/python-pass-by-reference/ »


[ Improve Your Python With 🐍 Python Tricks πŸ’Œ – Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]



from Planet Python
via read more

No comments:

Post a Comment

TestDriven.io: Working with Static and Media Files in Django

This article looks at how to work with static and media files in a Django project, locally and in production. from Planet Python via read...