[PYTHON] Passing by value, passing by reference, passing by reference,

2017/3/1 postscript: I wrote an additional article because the explanation of Python was a little inaccurate → [A little more about reference ~ Using Python and Java as an example ~](http://qiita.com/ur_kinsk/items / 7055ec8b50622289eeb2)

It's a trivial topic, but I decided to summarize the behavior when passing variables to functions, such as passing by value or by reference.

First, about primitive types

In most languages, ** primitive types ** and others behave differently. Primitive types are generally like this, although they differ slightly depending on the language.

  1. Integer
  2. Floating point number
  3. Letters
  4. Boolean
  5. Reference or pointer

Other arrays, classes, structs, etc. are called ** objects ** here.

Pass by value

A new variable is created that copies the value when passed to the function, and that becomes a formal argument. Changing the formal argument in the function does not change the calling variable. Examples of C ++, Java and Python.

//C++
#include <iostream>

void foo(int x){
	x = 42;
}

int main(){
	int x = 334;
	std::cout << x << "\n";
	foo(x);
	std::cout << x << "\n";
	return 0;
}
//Java
public class Val{
	public static void foo(int x){
		x = 42;
	}
	
	public static void main(String[] args){	
		int x = 334;
		System.out.println(x);
		foo(x);
		System.out.println(x);		
	}
}
#Python
def foo(x):
	x = 42
	
x = 334
print(x)
foo(x)
print(x)

The results are as follows.

334
334

Primitive types are passed by value in most languages like this. Also, in languages where there is a distinction between structs and classes, structures are passed by value, such as C # and Swift, and classes are defined as passing by reference or passing by reference.

Pass by reference

The actual and formal arguments passed to the function will now point to the same location in memory. So to speak, it feels like creating an "alias" for the same thing. If you change the formal argument in the function, it will be reflected in the caller. C ++, C #, Swift examples.

//C++
#include <iostream>

class Box{
public:
	int value;
	
	Box(int value) : value(value){}
};

//When defining a function&If you add, it will be passed by reference
void foo(Box& box){
	box.value = 42;
}

void bar(Box& box){
	box = Box(42);	
}

int main(){
	Box box1(334);
	std::cout << "foo: \n";
	std::cout << box1.value << "\n";
	foo(box1);
	std::cout << box1.value << "\n";
	
	Box box2(334);
	std::cout << "bar: \n";
	std::cout << box2.value << "\n";
	bar(box2);
	std::cout << box2.value << "\n";
	return 0;	
}
//C#
using System;

class Ref{
	public class Box{
		public int value;
		
		public Box(int value){
			this.value = value;
		}	
	}
	
	//If ref is added at the time of function definition and call, it will be passed by reference.
	public static void Foo(ref Box box){
		box.value = 42;	
	}

	public static void Bar(ref Box box){
		box = new Box(42);
	}
	
	public static void Main(string[] args){
		Box box1 = new Box(334);
		Console.WriteLine("foo: ");
		Console.WriteLine(box1.value);
		Foo(ref box1);	
		Console.WriteLine(box1.value);

		Box box2 = new Box(334);
		Console.WriteLine("bar: ");
		Console.WriteLine(box2.value);
		Bar(ref box2);
		Console.WriteLine(box2.value);
	}
}
//Swift
class Box{
	public var value:Int
	
	init(_ value:Int){
		self.value = value
	}
}

func foo(_ box:Box){
	box.value = 42
}

//When newly assigning to a formal argument inout at the time of function definition, at the time of calling&Put on
func bar(_ box:inout Box){
	box = Box(42)
}

var box1 = Box(334)
print("foo: ")
print(box1.value)
foo(box1)
print(box1.value)

var box2 = Box(334)
print("bar: ")
print(box2.value)
bar(&box2)
print(box2.value)

The result looks like this.

foo: 
334
42
bar: 
334
42

Pass by reference

Also shared delivery. Most languages take this form when passing an object. This is sometimes called passing by reference, but it is actually a little different as shown below. Java, C #, Python examples.

//Java
class Ptr{
	public static class Box{
		public int value;
		
		public Box(int value){
			this.value = value;
		}
	}
	
	public static void foo(Box box){
		box.value = 42;
	}
	
	public static void bar(Box box){
		box = new Box(42);
	}
	
	public static void main(String[] args){
		Box box1 = new Box(334);
		System.out.println("foo: ");
		System.out.println(box1.value);
		foo(box1);
		System.out.println(box1.value);
		
		Box box2 = new Box(334);
		System.out.println("bar: ");
		System.out.println(box2.value);
		bar(box2);
		System.out.println(box2.value);
	}
}
//C#
using System;

class Ptr{
	public class Box{
		public int value;
		
		public Box(int value){
			this.value = value;
		}	
	}
	
	//Without ref, the class will be passed by reference
	public static void Foo(Box box){
		box.value = 42;	
	}

	public static void Bar(Box box){
		box = new Box(42);
	}
	
	public static void Main(string[] args){
		Box box1 = new Box(334);
		Console.WriteLine("foo: ");
		Console.WriteLine(box1.value);
		Foo(box1);	
		Console.WriteLine(box1.value);

		Box box2 = new Box(334);
		Console.WriteLine("bar: ");
		Console.WriteLine(box2.value);
		Bar(box2);
		Console.WriteLine(box2.value);
	}
}
#Python
class Box:
	def __init__(self, value):
		self.value = value

def foo(box):
	box.value = 42
	
def bar(box):
	box = Box(42)
	
box1 = Box(334)
print("foo: ")
print(box1.value)
foo(box1)
print(box1.value)

box2 = Box(334)
print("bar: ")
print(box2.value)
bar(box2)
print(box2.value)

The result is this.

foo: 
334
42
bar: 
334
334

In this way, the behavior when a new object is assigned to a formal argument is different from passing by reference. In C ++, if you pass a pointer as shown below, the behavior will be the same as above.

//C++
#include <iostream>

class Box{
public:
	int value;
	
	Box(int value) : value(value){}
};

void foo(Box *box){
	box->value = 42;
}

void bar(Box *box){
	box = new Box(42);
	delete box;
}

int main(){
	Box *box1 = new Box(334);
	std::cout << "foo: \n";
	std::cout << box1->value << "\n";
	foo(box1);
	std::cout << box1->value << "\n";
	
	Box *box2 = new Box(334);
	std::cout << "bar: \n";
	std::cout << box2->value << "\n";
	bar(box2);
	std::cout << box2->value << "\n";
	delete box1;
	delete box2;
	return 0;
}

~~ In practice, you should use std :: shared_ptr instead of raw pointers, but this time I dare to use this for comparison. ~~ It may be confusing to say "pass by reference", but in short, "** reference " here means " pointer **". That is, passing the pointer by value. With that in mind, the processing done by bar is

・ When passing by reference

  1. Create a formal argument box that points to the same object as the actual argument passed to bar
  2. Replace the object at the location pointed to by box withBox (42)
  3. box and the caller box2 point to the same location, so the latter also changes

・ When passing by reference

  1. Create a formal argument box that points to the same object as the actual argument passed to bar
  2. Change the location pointed to by box to the newly created objectBox (42)
  3. The object pointed to by the calling box2 remains the same

It turns out that. It looks like this when drawn in the figure.

ref_ptr.png

If you want to reproduce the behavior of passing by reference in code that uses pointers,

void bar(Box *box){
	box = new Box(42);
	delete box;
}

Part is

void bar(Box *box){
	*box = Box(42);
}

become. By the way, in Objective-C code, it becomes clearer that this "object is treated as a pointer".

//Objective-C
#import <Foundation/Foundation.h>

@interface Box : NSObject
@property(nonatomic) int value;

- (id)initWithValue:(int)value;

@end

@implementation Box
- (id)initWithValue:(int)value{
	if(self = [super init]){
		_value = value;
	}
	return self;
}
@end

void foo(Box *box){
	box.value = 42;
}

void bar(Box *box){
	box = [[Box alloc] initWithValue:42];
}

int main(){
	Box *box1 = [[Box alloc] initWithValue:334];
	printf("foo:\n");
	printf("%d\n", box1.value);
	foo(box1);
	printf("%d\n", box1.value);

	Box *box2 = [[Box alloc] initWithValue:334];
	printf("bar:\n");
	printf("%d\n", box2.value);
	bar(box2);
	printf("%d\n", box2.value);
	return 0;
}

Summary

・ By value A new variable is created with the value of the actual argument copied. This is when you pass a primitive type. Changing the formal argument does not affect the caller. Depending on the language, structures etc. may also be passed by value.

・ Pass by reference The actual and formal arguments now point to the same location in memory. If you change the formal argument, it will be reflected in the caller. Many languages do not support this form.

-Passing by reference Passing pointers in C or C ++. By giving a location in memory to a formal argument, you can manipulate the same object as the actual argument through that location. It is similar to passing by reference, but be careful of the behavior when the formal parameter value itself is rewritten. Many languages take this form when passing an object.

Recommended Posts

Passing by value, passing by reference, passing by reference,
Sort by dict type value value
All Python arguments are passed by reference
Pandas: groupby () to complete value by group
[Refactoring Catalog] Change from reference to value