This article is an article on Tuesday, December 24th of DeNA Advent Calendar 2019.
I usually use Perl mainly, but I summarized it for the purpose of learning Go and reviewing Python. The grammar of Python is very simple, so I thought it would be quick to learn Go by the difference. I intend to write as much as possible, but I think there are various shortages. Please note.
First of all, how to write a comment. Python doesn't originally have the ability to comment out multiple lines, but putting a string in your program has no effect, so you can use it to write multi-line comments. Also, multi-line comments can be left as a documentation string.
Python
#1-line comment
'''
Multi-line comment
'''
"""
Multi-line comment
"""
def func():
"""
Program commentary, etc.
"""
help(func)
print(func.__doc__)
Go
//1-line comment
/*
Multi-line comment
*/
Python is a dynamically typed language, so you don't need to declare the type of a variable.
Python
n = 10
name = "hoge"
#Define all together
x, y, z = 1, 2, 3
a = b = c = 1
In the case of Go, you should first pay attention to the first character of the variable name.
This also applies to constants and functions. Go is a statically typed language, but there are explicit and implicit definitions.
Define it as var [variable name] [variable type]
.
Go
var n int
n = 1
//Define all together
var x, y, z int
x, y, z = 1, 2, 3
var (
x, y int
name string
)
x, y, name = 1, 2, "hoge"
//Declare the type and assign the value at the same time
var n int = 1
Define it as [variable name]: = [value]
or var [variable name] = [value]
. Assigning a value implicitly infers the type of the variable.
Go
n := 1
//Type can be omitted even in the definition using var
var n = 1
//Define all together
x, y, name := 1, 2, "hoge"
var (
x = 1
y = 2
name = "hoge"
)
Python has no keywords for defining constants. By convention, only uppercase letters and underscores represent constants.
Python
PI = 3.14
MAX_NUM = 100
Go uses const
to define constants. You can use the identifier ʻiota` to generate a sequence of integers.
Attempting to change the value of a constant will result in an error.
Go
const Pi = 3.14
const MaxNum = 100
// ()Define collectively in
const (
Pi = 3.14
MaxNum = 100
)
const (
X = iota // 0
Y // 1
Z // 2
)
//When specifying the start number
const (
X = iota + 10 // 10
Y // 11
Z // 12
)
Python arrays (lists) are very simple to write. The following is the basic usage.
Python
#Definition
numbers = [1, 2, 3]
#Add element
numbers.append(6)
numbers.insert(3, 5) # numbers: [1, 2, 3, 5, 6]
#Element count
len(numbers)
#Delete element
numbers.remove(3) # numbers: [1, 2, 5, 6]
numbers.pop(1) # numbers: [1, 5, 6]
del numbers[0] # numbers: [5, 6]
#Combine lists
numbers += [3, 4] # numbers: [5, 6, 3, 4]
numbers.extend([1, 2]) # numbers: [5, 6, 3, 4, 1, 2]
#Search for elements
print(6 in numbers) # True
print(numbers.index(6)) # 1
#Sort the list
numbers.sort() # numbers: [1, 2, 3, 4, 5, 6]
numbers.sort(reverse=True) # numbers: [6, 5, 4, 3, 2, 1]
Go's array type cannot be scaled up or down. Data structures like Python's lists are equivalent to slices in Go.
The ʻappendfunction is often used for slicing operations. For **
...`, see [Variadic function arguments](#variadic arguments). ** **
Go
//Array cannot be resized
array := [3]int{1, 2, 3}
fmt.Println(array[0]) // 1
fmt.Println(array[1:3]) // [2 3]
//slice
n1 := []int{} // n1: []
n2 := make([]int, 0) // n2: []
numbers := []int{1, 2, 3}
//Add element
numbers = append(numbers, 6) // numbers: [1 2 3 6]
numbers = append(numbers[0:3], append([]int{5}, numbers[3:]...)...) // numbers: [1 2 3 5 6]
//Element count
len(numbers)
//Delete element
numbers = append(numbers[0:2], numbers[3:]...) // numbers: [1 2 5 6]
numbers = numbers[2:] // numbers: [5 6]
//Combine arrays
numbers = append(numbers, []int{3, 4, 1, 2}...) // numbers: [5 6 3 4 1 2]
//Search for elements
//There is no equivalent to the Python index, so write it yourself
fmt.Println(IndexOf(numbers, 6)) // 1
func IndexOf(s []int, n int) int {
for i, v := range s {
if n == v {
return i
}
}
return -1
}
//Sort array
//use sort package
sort.Ints(numbers)
fmt.Println(numbers) // [1 2 3 4 5 6]
sort.Sort(sort.Reverse(sort.IntSlice(numbers)))
fmt.Println(numbers) // [6 5 4 3 2 1]
Python uses a data structure called a dictionary.
Python
#Definition
dic = {'hoge': 1, 'fuga': 2, 'piyo': 3}
list1 = [('hoge', 1), ('fuga', 2), ('piyo', 3)]
dic2 = dict(list1) #Same as dic value
dic['hoge']
dic.get('hoge')
#Add and remove elements
dic['foo'] = 4
dic.setdefault('bar', 5)
dic.pop('hoge') # {'fuga': 2, 'piyo': 3, 'foo': 4, 'bar': 5}
del dic['fuga'], dic['piyo'] # {'foo': 4, 'bar': 5}
#Element count
len(dic)
#Confirmation of key existence
'foo' in dic
#Retrieving keys and values
list(dic.keys()) # ['foo', 'bar']
list(dic.values()) # [4, 5]
for k, v in dic.items():
print(k, v)
Go's map is equivalent to Python's dictionary. It is defined in the following format.
map [key type] element type
Go
//Definition
dic := map[string]int{"hoge": 1, "fuga": 2, "piyo": 3}
dic2 := make(map[string]int)
fmt.Println(dic) // map[fuga:2 hoge:1 piyo:3]
fmt.Println(dic2) // map[]
//Add and remove elements
dic["foo"] = 4
delete(dic, "hoge")
fmt.Println(dic) // map[foo:4 fuga:2 piyo:3]
//Element count
len(dic)
//Confirmation of key existence
_, exist := dic["foo"]
fmt.Println(exist) // true
if value, exist := dic["foo"]; exist {
fmt.Println(value) // 4
}
//Retrieving keys and values
for k, v := range dic {
fmt.Println(k, v)
}
Python does not have a switch statement. Use ʻif ... elif ... else` instead. There is also a way of writing called a conditional expression (ternary operator).
6.12. Conditional Expressions https://docs.python.org/ja/3/reference/expressions.html#conditional-expressions
Logical operators use ʻand, ʻor
, not
.
Python
x, y = 1, 2
if x > y:
print('x > y')
elif x < y:
print('x < y')
else:
print('x == y')
n = 10
#Conditional expression
result = "positive" if n > 0 else "negative or zero"
There are two types of conditional branches in Go, if and switch, and you can define valid variables only in that block by writing if with a simple statement.
There is no ternary operator, but you can write it like that with map.
Logical operators&&
,||
,!
Use the.
Go
x, y := 1, 2
if x > y {
fmt.Println("x > y")
} else if x < y {
fmt.Println("x < y")
} else {
fmt.Println("x == y")
}
#If with a simple sentence
if x, y := 1, 2; x > y {
fmt.Println("x > y")
} else if x < y {
fmt.Println("x < y")
} else {
fmt.Println("x == y")
}
#switch statement
x, y := 1, 2;
switch {
case x > y:
fmt.Println("x > y")
case x < y:
fmt.Println("x < y")
default:
fmt.Println("x == y")
}
n := 10
#How to write like a ternary operator
result := map[bool]string{true: "positive", false: "negative"}[n > 0]
Python loop processing uses for and while.
Python
sum = 0
for num in range(1, 11):
sum += num
num, sum = 1, 0
while num <= 10:
sum += num
num += 1
#infinite loop
num, sum = 1, 0
while True:
sum += num
num += 1
if num > 10:
break
There is only a for loop in Go, but you can also control it like while.
Go
sum := 0
for num := 0 ; num <= 10 ; num++ {
sum += num
}
// while
num, sum := 1, 0
for num <= 10 {
sum += num
num++
}
//infinite loop
num, sum := 1, 0
for {
sum += num
num++
if num > 10 {
break
}
}
Python functions are defined with def
. The function definition must be written before the function call is executed.
There are the following usages.
Python
def greet(name="World"):
print("Hello, " + name)
greet()
greet("Alice")
greet(name="Alice")
#Variadic variable
def greet(*names):
for name in names:
print("Hello, " + name)
greet("Alice", "Bob", "Carol")
#Multiple return values
def cal(a, b):
add = a + b
mul = a * b
return add, mul
add, mul = cal(10, 5)
Go functions are defined with func
.
func [function name]([argument definition]) [return type] {[function body]}
There are no default or keyword arguments, but they have the following characteristics:
defer
keyword are executed at the end of the function. If multiple definitions are made, they will be called from the end.Variadic arguments for functions are defined as [argument name] ... [argument type]
.
And if you pass a slice as a variadic argument, you need to add ...
after the variable to expand the slice.
Go
func main() {
add, mul := cal(10, 5)
fmt.Println(add, mul) // 15 50
add, mul = calc(10, 5)
fmt.Println(add, mul) // 15 50
greet("Alice", "Bob", "Carol")
names := []string{"Alice", "Bob", "Carol"}
greet(names...) //Pass a slice as a variadic argument
testDefer() // BDCA
}
//Uninflected word
func cal(a int, b int) (int, int) {
add := a + b
mul := a * b
return add, mul
}
//Named return value
//If the argument types are the same, you can write them all together
func calc(a, b int) (add int, mul int) {
add = a + b
mul = a * b
return
}
//Functions with no return value
//Variadic argument
func greet(names ...string) {
for _, name := range names {
fmt.Println("Hello,", name)
}
}
//defer deferred execution
func testDefer() {
defer fmt.Print("A")
fmt.Print("B")
defer fmt.Print("C") //C is output before A
fmt.Print("D")
}
Python uses the try-except
syntax to catch and handle exceptions.
Python
def doDivision(x, y):
try:
result = x / y
except Exception as e:
result = None
print("except:" + e.args[0])
else: #Execute at normal end
print("else")
finally: #Always run on exit
print("finally")
return result
doDivision(10, 2)
# else
# finally
doDivision(10, 0)
# except:test exception
# finally
There is no exception mechanism like try-except
in Go. Instead, it uses the property of being able to return multiple return values of a function to detect an error by returning whether an error has occurred (ʻerror interface) as part of the return value. The ʻerror interface
is defined as follows:
https://golang.org/pkg/builtin/#error
Go error interface
type error interface {
Error() string
}
The following example uses the New
function of the ʻerrors package to generate a ʻerror type
.
You can also use defer
to achieve the same behavior as Python's finally
.
Go
package main
import (
"fmt"
"errors"
)
func main() {
_, err := doDivision(10, 2)
if (err != nil) {
//Error handling
}
// defer
_, err = doDivision(10, 0)
if (err != nil) {
//Error handling
}
// error
// defer
}
func doDivision(i, j int) (result int, err error) {
defer fmt.Println("defer") //Always run on exit
if j == 0 {
fmt.Println("error")
err = errors.New("Divided by Zero")
return
}
result = i / j
return
}
In addition, Go also has an error handling mechanism called panic / recover
, but I will omit it here.
The following is an example of a simple Python class.
Python
class Player:
def __init__(self, id, name):
self.id = id
self.name = name
self.__hp = 100
@property
def hp(self):
return self.__hp
def consume_hp(self, num):
self.__hp -= num
player = Player(10001, "Alice")
print(player.hp) # 100
player.consume_hp(10)
print(player.hp) # 90
Go doesn't have a syntax equivalent to class
in Python, but it uses a struct that handles related variables together in a similar role.
You can define methods for the structure. Unlike functions, methods require a receiver type and its variable name.
The following example defines a method called consumeHp
for a pointer type called * Player
.
Go
//Player type structure
type Player struct{
ID int
Name string
Hp int
}
//constructor
func newPlayer(id int, name string) Player {
return Player{ID: id, Name: name, Hp: 100}
}
// *Player type method
func (p *Player) consumeHp(num int) {
p.Hp -= num
}
func main() {
p := newPlayer(10001, "Alice")
fmt.Println(p.Hp) // 100
p.consumeHp(10)
fmt.Println(p.Hp) // 90
}
At the end, I will write a little about multithreading.
Below is a simple example of using the threading
module to spawn a thread and pass data in a queue.
Python
import threading
import time
from queue import Queue
def worker(a, b, q):
time.sleep(1)
result = a + b
q.put(result) #Put an element in the queue
print("result:", result)
q = Queue()
thread = threading.Thread(target=worker, args=(2, 3, q))
thread.start()
thread.join()
print("main thread")
result = q.get() #Remove elements from the queue
q.task_done()
print("received:", result) # received: 5
Let's do the same with Go.
In Go, a lightweight thread, goroutine, is implemented to run in parallel. Writing go f (x)
starts a new goroutine and executes the function.
It uses a data structure called a channel to pass data between goroutines. The channel type name is written as chan [data type]
.
Go
package main
import (
"fmt"
"time"
)
func newThread(a, b int, ch chan int) {
time.Sleep(1000)
result := a + b
ch <- result //Send data to channel
fmt.Println("result:", result)
}
func main() {
ch := make(chan int) //Generate a channel
go newThread(2, 3, ch) //Run newThread in a new goroutine
fmt.Println("main thread")
result := <-ch //Receive data from channel
close(ch)
fmt.Println("received:", result) // received: 5
}
I've seen the Go language grammar in comparison to Python. Although Go is a statically typed language, it is also as easy to write as a dynamically typed language such as Python. As Go is said to be influenced by various languages, I think that anyone who understands C can immediately understand pointers and structures in Go. I couldn't elaborate on goroutine and channel, which are important for concurrency, but I'd like to write them again.
Recommended Posts