Goのファイル・ファイルライクオブジェクトもろもろ
ファイルの読み取り
Goでファイルを1行ずつ読み出したい場合はbufio.NewScannerを使うらしい。
そのNewScannerはio.Reader型の引数を取り、ファイルやファイルライクオブジェクトを渡す。
では、Goでファイルやファイルライクオブジェクトを扱う方法を調べてみた(以下3つ)。
Go | Python3 | |
---|---|---|
1 | strings.NewReader/bytes.NewReader | io.StringIO |
2 | ioutil.TempFile | tempfile.NamedTemporaryFile |
3 | os.Open | ビルトインのopen関数 |
1. strings.NewReader/bytes.NewReaderを使う方法 (PythonのStringIOに相当)
文字列をファイルのように扱うファイルライクオブジェクトとして、Goではstrings.NewReaderを使うらしい。
[追記: 2016/12/6]
stringを反復する場合はstrings.NewReader, byteを反復する場合はbytes.NewReaderと、2種類用意されている。
テキストファイルの代わりに使うならstrings.NewReaderが妥当。
x := bufio.NewScanner(strings.NewReader(text)) // または // x := bufio.NewScanner(bytes.NewReader([]byte(text))) for x.Scan() { fmt.Println(x.Text()) }
2. ioutil.TempFileを使う方法 (PythonのNamedTemporaryFileに相当)
Goにも一時ファイルをパァーッっと作ってくれるライブラリがあった。ioutil.TempFileがこれに当たる。
// import "io/ioutil" tmp, _ := ioutil.TempFile("", "_") tmp.Write([]byte("| わたしは\n")) tmp.Write([]byte("| い*がわ\n")) tmp.Write([]byte("| よ**と")) defer os.Remove(tmp.Name()) // PythonのNamedTemporaryFileと違い、ファイルの削除は自分でやる。 tmp.Seek(0, 0) x = bufio.NewScanner(tmp) for x.Scan() { fmt.Println(x.Text()) }
3. os.Openを使う方法 (Pythonのビルトインopen関数に相当)
普通にファイルを開くときは、os.Openを使う。
fp, _ := os.Open(tmp.Name()) defer fp.Close() x = bufio.NewScanner(fp) for x.Scan() { fmt.Println(x.Text()) }
まとめ
当然ながら、これらはすべてio.Reader型の変数に代入できる(以下)。
package main import ( "fmt" "io" "io/ioutil" "bufio" "bytes" "os" ) func main(){ var reader io.Reader var scanner *bufio.Scanner reader = bytes.NewReader([]byte("Hello, world.")) scanner = bufio.NewScanner(reader) fmt.Println(scanner) tmp, _ := ioutil.TempFile("", "_") defer os.Remove(tmp.Name()) tmp.Write([]byte("I have a pen.")) tmp.Seek(0, 0) reader = tmp scanner = bufio.NewScanner(reader) fmt.Println(scanner) fp, _ := os.Open(tmp.Name()) defer fp.Close() reader = fp scanner = bufio.NewScanner(reader) fmt.Println(scanner) }
Goのtype宣言はすごい
Goのtype宣言を使うと、特定の型を元にして別の型を定義できる。
一番単純な例: 基本データ型から別の名前の型を作る
type Foo int var x Foo x = 18 fmt.Printf("%T\n", x) // => main.Foo
これはわかる。intからFooという別の型を作るだけである。
関数に型名を付与する使い方
ところが、このGoのtypeってやつは関数にも利用できることに驚いた。
type NumFunc func(xs []int) int
これは全然okで、構文エラーにはならない。
つまり、
// intのスライスを引数に取って合計値を「文字列で」返す func NumString(xs []int) string { acc := 0 for i := 0; i < len(xs); i++ { acc += xs[i] } return strconv.Itoa(acc) } // intのスライスを引数に取って合計値を返す func Sum(xs []int) int { acc := 0 for i := 0; i < len(xs); i++ { acc += xs[i] } return acc } type NumFunc func(xs []int) int var fn NumFunc fn = Sum // これはok // fn = NumString // これはコンパイルエラー // cannot use NumString (type func([]int) string) as type NumFunc in assignment
このように、関数を任意の型として宣言し、所定のシグネチャを守る関数しか代入できなくさせられる。
動くコードはhttps://play.golang.org/p/Em_52ORgYqこちら
関数のファクトリを簡潔に記述する
そもそもこの話に興味を持ったのは、Pythonのデコレータに相当することをGoでやる方法を考え始めたときだった。
Pythonのデコレータは関数のファクトリだから同じことをすれば良いのだが、最初以下のような安直なやり方でしか書けないと思っていた。
package main import "fmt" func main() { var foo = func(x int) int { return x + 5 } var deco = func(fn func(int) int) func(int) int { return func(x int) int { return fn(x) } } var fn = deco(foo) fmt.Println(fn(100)) // => 105 }
とにかくdecoの定義の部分がひどい。
「func(int) int」という記載が3回も並ぶと実に読みにくい・・
なので、この重複の多い部分をtypeでくくり出す。
package main import "fmt" func main() { type F func(x int) int deco := func(fn F) F { return func(x int) int { return fn(x) } } var fn = deco(func(x int) int { return x + 5 }) fmt.Println(fn(100)) // => 105 }
すると、decoの記載がだいぶスッキリするじゃないか。というところでこのtypeってやつはすごいと思ったのであった。
参考リンク
SQL ServerのIDENTITY値
基本事項
IDENTITY値にはSEED(初期値), INCR(増分)という概念がある。
また、IDENT_????という関数が用意されている(以下)
- IDENT_CURRENT 現在値
- IDENT_SEED 初期値
- IDENT_INCR 増分
CREATE TABLE foo ( [ID] INT IDENTITY(25, 2) PRIMARY KEY, [NAME] NVARCHAR(16) NOT NULL, [AGE] INT ); INSERT INTO foo (NAME) VALUES (N'あ'), (N'い'), (N'う'); SELECT * FROM foo;
ID NAME
25 あ
27 い
29 う
SELECT IDENT_CURRENT('foo') [Current], IDENT_SEED('foo') [Seed], IDENT_INCR('foo') [Incr] ;
Current Seed Incr
29 25 2
IDENTITY列に明示的に値を指定して挿入する
通常、IDENTITYが設定されている列に値を明示的に指定して挿入はできない。
これがやりたいときは SET IDENTITY_INSERT
オートインクリメント列を事前に採番しておきたい場合
テーブルに共有ロック(SELECTは許すがUPDATE, INSERT, DELETEを許さない)をかけてから先述のIDENT_????関数を使って採番。
DECLARE @items TABLE ([ID] INT NOT NULL, NAME NVARCHAR(16) NOT NULL, AGE INT); BEGIN TRANSACTION; WITH X (NAME, AGE) AS ( SELECT N'わ', NULL UNION ALL SELECT N'を', NULL UNION ALL SELECT N'ん', 13 ) INSERT INTO @items ([ID], NAME, AGE) SELECT IDENT_CURRENT('foo') + (IDENT_INCR('foo') * ROW_NUMBER() OVER (ORDER BY [NAME])), X.NAME, X.AGE FROM X WITH (TABLOCK, HOLDLOCK) -- 共有ロック。トランザクション終了まで有効 ; SET IDENTITY_INSERT foo ON; INSERT INTO foo ([ID], NAME, AGE) SELECT [ID], NAME, AGE FROM @items; COMMIT;
名称を指定せずテーブルのIDENTITY列を参照する -- $IDENTITY
MSDNのサンプルの中に $IDENTITY というキーワードがあって、最初何を表すのかわからなかった。
これは対象としたテーブルのIDENTITY列を指すキーワードらしい。
SELECT $IDENTITY FROM foo
ID
25
27
29
31
33
35
requestsを使ってInsecurePlatformWarningが出てしまうときの対処
requestsを使っていたらいつの間にかInsecurePlatformWarningという警告が出るようになってしまった。
/home/echizen/pecan/local/lib/python2.7/site-packages/requests/packages/urllib3/util/ssl_.py:90: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning.
InsecurePlatformWarning
SoftLayer - Python実行時にInsecurePlatformWarningが出る場合の対応方法 - Qiita
この記事を読むと
- requestsパッケージを2.5.3以前に戻す
- Pythonのバージョンを2.7.9以降に上げる
上記ふたつの対処方法が紹介されているが、どちらも採用しがたいと思い見送った。
困ったのでstackoverflowを見たら別の解決方法が書いてあった。
"requests[security]"をインストールすると良いとのこと。
手元の環境がUbuntuだったので
$ sudo apt-get install libffi-dev libssl-dev $ . ./bin/activate $ pip install requests requests[security]
これで確かに警告が消えた。
忙しくて余裕が無くなった自分に宛てて
程度の低い人に流されないように 程度の低い人に腹を立てぬこと
続きを読む