Cloud-oriented Life

Cloud Native Technology Improves Lives

andrewrothstein.vagrant

Installs Vagrant by HashiCorp - https://www.vagrantup.com/.

Vagrant is a tool for building and managing virtual machine environments in a single workflow. With an easy-to-use workflow and focus on automation, Vagrant lowers development environment setup time, increases production parity, and makes the “works on my machine” excuse a relic of the past.

Read more »

andrewrothstein.virtualbox

Installs Oracle Virtualbox.

VirtualBox is a powerful x86 and AMD64/Intel64 virtualization product for enterprise as well as home use. Not only is VirtualBox an extremely feature rich, high performance product for enterprise customers, it is also the only professional solution that is freely available as Open Source Software under the terms of the GNU General Public License (GPL) version 2. See “About VirtualBox” for an introduction.

Read more »

str, repr, str, repr

Sometimes, you will need to implement __str__ or __repr__ methods for your class. Do you know what they do? Is there any difference between them? The answer to this question can be found by searching. If it happens to be the first time you have seen this question, you might as well take a look.

The print statement and str() built-in function uses __str__ to display the string representation of the object while the repr() built-in function uses __repr__ to display the object.

str, repr

Following are differences:

  • __repr__ is used to generate a formal representation. It may be considered as a method of serializing an object, and in principle, it may be able to deserialize back to an object. It is mainly used for debugging and development. It’s goal is to be unambiguous and str’s is to be readable.

__str__ is used to generate informal representations. Format or print will call it to generate a “friendly” display for the user. It is used for creating output for end user.

If you need to implement it yourself, generally implement __str__.

repr for Debug

Executing repr(obj) in Python can get the string representation of obj, and this operation is equivalent to calling obj.__repr__(). And this string means that may be able to deserialize back to obj itself. Look at the following code:

1
2
3
4
5
6
7
x = [1,2,3]
repr(x)
#>'[1, 2, 3]'
eval('[1, 2, 3]')
#> [1, 2, 3]
eval(repr(x)) == x
#> True

We see that’[1, 2, 3]’ (note that there is a space after the comma) is the string representation of the data [1,2,3], the original data can be obtained by deserializing with eval. So what if the variable is a custom class?

1
2
3
4
5
6
7
class MyClass:
def __init__(self, arg):
self.arg = arg

x = MyClass(10)
repr(x)
#>'<__main__.MyClass object at 0x10a40ef98>'

As you can see, repr(x) gives the type of object and the ID (memory address) of the object. But if we try to deserialize with eval(repr(x)), it will fail. So being able to deserialize is actually a convention, not a compulsion. We try to override the default implementation:

1
2
3
4
5
6
7
8
9
10
11
12
class MyClass:
def __init__(self, arg):
self.arg = arg

def __repr__(self):
return'MyClass({})'.format(self.arg)

x = MyClass(10)
repr(x)
#>'MyClass(10)'
eval(repr(x))
#> MyClass(10)

You can see that the coverage of __repr__ has an effect, and it can be deserialized normally.

The above few examples are all to illustrate what is the use of the string generated by repr.

repr does not force the generated string to be deserialized

The string generated by repr is generally used for debugging, so the generally generated string should contain as much information as possible, and the information should be as clear as possible (for example, the ID is used to distinguish two different objects in the default implementation).
Don’t use repr and eval for serialization/deserialization, use pickle or json.
str is used to display

str for Display

The obj.__str__() method will be called during print(obj) or '{}'.format(obj), generally to provide users with a “friendly” display, so __str__ does not return in principle like __repr__ Values ​​are agreed, and you can do whatever you want.

1
2
3
4
5
6
>>> from datetime import datetime
>>> now = datetime.now()
>>> print(str(now))
2017-04-22 15:41:33.012917
>>> print(repr(now))
datetime.datetime(2017, 4, 22, 15, 41, 33, 12917)

In addition, the default implementation of __str__ calls the __repr__ method directly. Therefore, if the __repr__ method is overridden, the result of __str__ will also change.

References

[1] str() vs repr() in Python - GeeksforGeeks - https://www.geeksforgeeks.org/str-vs-repr-in-python/

[2] str() vs repr() in Python? - https://www.tutorialspoint.com/str-vs-repr-in-python

Go Slices: usage and internals

Introduction

Go’s slice type provides a convenient and efficient means of working with sequences of typed data. Slices are analogous to arrays in other languages, but have some unusual properties. This article will look at what slices are and how they are used.

Read more »

Effective Go

Introduction

Go is a new language. Although it borrows ideas from existing languages, it has unusual properties that make effective Go programs different in character from programs written in its relatives. A straightforward translation of a C++ or Java program into Go is unlikely to produce a satisfactory result—Java programs are written in Java, not Go. On the other hand, thinking about the problem from a Go perspective could produce a successful but quite different program. In other words, to write Go well, it’s important to understand its properties and idioms. It’s also important to know the established conventions for programming in Go, such as naming, formatting, program construction, and so on, so that programs you write will be easy for other Go programmers to understand.

This document gives tips for writing clear, idiomatic Go code. It augments the [3] language specification - https://golang.org/doc/go_spec.html, the Tour of Go - https://tour.golang.org/, and How to Write Go Code - https://golang.org/doc/code, all of which you should read first.

# Arrays

Arrays are useful when planning the detailed layout of memory and sometimes can help avoid allocation, but primarily they are a building block for slices, the subject of the next section. To lay the foundation for that topic, here are a few words about arrays.

There are major differences between the ways arrays work in Go and C. In Go,

  • Arrays are values. Assigning one array to another copies all the elements.
    In particular, if you pass an array to a function, it will receive a copy of the array, not a pointer to it.
  • The size of an array is part of its type. The types [10]int and [20]int are distinct.
  • The value property can be useful but also expensive; if you want C-like behavior and efficiency, you can pass a pointer to the array.
1
2
3
4
5
6
7
8
9
func Sum(a *[3]float64) (sum float64) {
for _, v := range *a {
sum += v
}
return
}

array := [...]float64{7.0, 8.5, 9.1}
x := Sum(&array) // Note the explicit address-of operator

But even this style isn’t idiomatic Go. Use slices instead.

Slices

Slices wrap arrays to give a more general, powerful, and convenient interface to sequences of data. Except for items with explicit dimension such as transformation matrices, most array programming in Go is done with slices rather than simple arrays.

Slices hold references to an underlying array, and if you assign one slice to another, both refer to the same array. If a function takes a slice argument, changes it makes to the elements of the slice will be visible to the caller, analogous to passing a pointer to the underlying array. A Read function can therefore accept a slice argument rather than a pointer and a count; the length within the slice sets an upper limit of how much data to read. Here is the signature of the Read method of the File type in package os:

1
func (f *File) Read(buf []byte) (n int, err error)

The method returns the number of bytes read and an error value, if any. To read into the first 32 bytes of a larger buffer buf, slice (here used as a verb) the buffer.

1
n, err := f.Read(buf[0:32])

Such slicing is common and efficient. In fact, leaving efficiency aside for the moment, the following snippet would also read the first 32 bytes of the buffer.

1
2
3
4
5
6
7
8
9
10
var n int
var err error
for i := 0; i < 32; i++ {
nbytes, e := f.Read(buf[i:i+1]) // Read one byte.
n += nbytes
if nbytes == 0 || e != nil {
err = e
break
}
}

The length of a slice may be changed as long as it still fits within the limits of the underlying array; just assign it to a slice of itself. The capacity of a slice, accessible by the built-in function cap, reports the maximum length the slice may assume. Here is a function to append data to a slice. If the data exceeds the capacity, the slice is reallocated. The resulting slice is returned. The function uses the fact that len and cap are legal when applied to the nil slice, and return 0.

1
2
3
4
5
6
7
8
9
10
11
12
13
func Append(slice, data []byte) []byte {
l := len(slice)
if l + len(data) > cap(slice) { // reallocate
// Allocate double what's needed, for future growth.
newSlice := make([]byte, (l+len(data))*2)
// The copy function is predeclared and works for any slice type.
copy(newSlice, slice)
slice = newSlice
}
slice = slice[0:l+len(data)]
copy(slice[l:], data)
return slice
}

We must return the slice afterwards because, although Append can modify the elements of slice, the slice itself (the run-time data structure holding the pointer, length, and capacity) is passed by value.

The idea of appending to a slice is so useful it’s captured by the append built-in function. To understand that function’s design, though, we need a little more information, so we’ll return to it later.

A common operation is to append data to the end of a slice. Go provides a built-in append function that’s good for most purposes; it has the signature

1
func append(s []T, x ...T) []T

The append function appends the elements x to the end of the slice s, and grows the slice if a greater capacity is needed.

1
2
3
4
a := make([]int, 1)
// a == []int{0}
a = append(a, 1, 2, 3)
// a ==

Two-dimensional slices

Go’s arrays and slices are one-dimensional. To create the equivalent of a 2D array or slice, it is necessary to define an array-of-arrays or slice-of-slices, like this:

1
2
type Transform [3][3]float64  // A 3x3 array, really an array of arrays.
type LinesOfText [][]byte // A slice of byte slices.

Because slices are variable-length, it is possible to have each inner slice be a different length. That can be a common situation, as in our LinesOfText example: each line has an independent length.

1
2
3
4
5
text := LinesOfText{
[]byte("Now is the time"),
[]byte("for all good gophers"),
[]byte("to bring some fun to the party."),
}

Sometimes it’s necessary to allocate a 2D slice, a situation that can arise when processing scan lines of pixels, for instance. There are two ways to achieve this. One is to allocate each slice independently; the other is to allocate a single array and point the individual slices into it. Which to use depends on your application. If the slices might grow or shrink, they should be allocated independently to avoid overwriting the next line; if not, it can be more efficient to construct the object with a single allocation. For reference, here are sketches of the two methods. First, a line at a time:

1
2
3
4
5
6
// Allocate the top-level slice.
picture := make([][]uint8, YSize) // One row per unit of y.
// Loop over the rows, allocating the slice for each row.
for i := range picture {
picture[i] = make([]uint8, XSize)
}

And now as one allocation, sliced into lines:

1
2
3
4
5
6
7
8
// Allocate the top-level slice, the same as before.
picture := make([][]uint8, YSize) // One row per unit of y.
// Allocate one large slice to hold all the pixels.
pixels := make([]uint8, XSize*YSize) // Has type []uint8 even though picture is [][]uint8.
// Loop over the rows, slicing each row from the front of the remaining pixels slice.
for i := range picture {
picture[i], pixels = pixels[:XSize], pixels[XSize:]
}

References

[1] Effective Go - The Go Programming Language - https://golang.org/doc/effective_go.html

[2] language specification - https://golang.org/doc/go_spec.html

[3] Tour of Go - https://tour.golang.org/

[4] Go Code - https://golang.org/doc/code

pprint

The pprint module provides a capability to “pretty-print” arbitrary Python data structures in a form which can be used as input to the interpreter. If the formatted structures include objects which are not fundamental Python types, the representation may not be loadable. This may be the case if objects such as files, sockets or classes are included, as well as many other objects which are not representable as Python literals.

Read more »
0%