rabbitfoot530's diary

読んだ本と、プログラムに関することのメモです。好きな言語は、C++, Python, Golang, TypeScript。数学・物理・学習理論も好きです。

PythonによるLinuxプログラミングインタフェース(4章 copy)

 4章P75のファイルをopenしてread、readした内容をwriteしてファイルをコピーするというプログラム。

pythonで書くと下記。

#/usr/bin/env
#-*- encoding: utf-8 -*-
import sys


def usage_error(filename):
    print("{0} old-file new-file".format(filename))

def error_exit(str):
    print("error: " + str)
    exit()

def unix_like():
    import os
    import stat

    BUF_SIZE = 1024

    argc = len(sys.argv)
    if argc != 3 or sys.argv[1] == "--help":
        usage_error(sys.argv[0])

    input_fd = os.open(sys.argv[1], os.O_RDONLY)
    if input_fd == -1:
        os.close(input_fd)
    open_flags = os.O_CREAT | os.O_WRONLY | os.O_TRUNC;
    file_perms = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH | stat.S_IWOTH;

    output_fd = os.open(sys.argv[2], open_flags, file_perms)
    if output_fd == -1:
        os.close(output_fd)

    while True:
        buffer = os.read(input_fd, BUF_SIZE)
        if not buffer:
            break
        os.write(output_fd, buffer)

    if os.close(input_fd) == -1:
        error_exit("close input")

    if os.close(output_fd) == -1:
        error_exit("close output")


def pythonic():
    argc = len(sys.argv)
    if argc != 3 or sys.argv[1] == "--help":
        usage_error(sys.argv[0])

    # Open input and output files
    try:
        file = open(sys.argv[1], encoding='utf-8')
    except IOError as e:
        print("opening file {0}".format(e.strerror))
        exit()
    else:
        try:
            lines = file.readlines()
        finally:
            file.close()

    try:
        out_file = open(sys.argv[2], "w")
    except IOError as e:
        print("opening file {0}".format(e.strerror))
        quit()
    else:
        [out_file.write(line) for line in lines]
    finally:
        out_file.close()

       # [Using python “with” statement with try-except block](http://bit.ly/1cQ3hcK)

# ./p75_copy.py p75_copy.py p75_copy_w.txt
if __name__ == '__main__':
    pythonic()
    unix_like()

Cだとexit()を読んでるけど、pythonだとquitとexitがあって、どうやら中身の実装は同じ模様。

difference between quit and exit in python

あと、Cだと当然、ファイルが開けたかどうかをファイルディスクリプタを見て判定するけど、pythonでも同じようにファイルが開けたかどうかを判定するには、1回tryでopenをして判定するのがよさそう。

けど、pythonだと下記のwithを使った構文がある。。。

with open(path) as file:

けど、withを使った構文では、ファイルが開けたかどうかをキャッチする方法が用意されてない。 なので、下記のようにtryで囲むのかと思ったが...

try:
    with open(path) as file:

どうやら、このwithをtryで囲む方法は、newbieがやりがちだが良くないと書かれている。。。

となると、先にpathlibでファイルの有りかを調べてから、withでopenすれば良いのかという案が下記。

def pythonic2():
    import pathlib

    argc = len(sys.argv)
    if argc != 3 or sys.argv[1] == "--help":
        usage_error(sys.argv[0])

    # Open input and output files
    input_file = sys.argv[1]
    output_file = sys.argv[2]
    if pathlib.Path(input_file).is_file():
        with open(input_file, encoding='utf-8') as rfile, open(output_file, 'w', encoding='utf-8') as wfile:
            try:
                lines = rfile.readlines()
                [wfile.write(line) for line in lines]
            except Exception as e:
                print("err: {0}".format(e))

# ./p75_copy.py p75_copy.py p75_copy_w.txt
if __name__ == '__main__':
    pythonic2()

PythonによるLinuxプログラミングインタフェース(3章 stderror)

 3章のstderrorに対するコード。

 pythonだとエラーをキャッチしてから、e.strerrorで文字列としてエラーメッセージを取得できる。  

#include <string.h>
char *strerror(int errnum);
#/usr/bin/env
#-*- encoding: utf-8 -*-


def my_open(path):
    """
    os.strerror() is translate number to string
    """
    try:
        f = open(path, encoding='utf-8')
    except IOError as e:
        print("err: {0}".format(e.strerror))
    else:
        print("Success")


if __name__ == '__main__':
    path = "./nothing"
    my_open(path)
    path = "p52_strerror.py"
    my_open(path)

アジャイル開発とスクラム 顧客・技術・経営をつなぐ協調的ソフトウェア開発マネジメント

 アジャイルの特にスクラムについて書かれた本。スクラムとはどういう風に取り組むべきなのか。  従来のウォーターフォール型の開発スタイルと、どのように違うのかについて書かれています。

 縦書のビジネス書という感じ。あまり内容は濃くないので、さらりと2時間もあれば読めてしまいます。  実際にスクラムを導入したプロジェクトの事例のインタビューが多いです。

 スクラムって?実際導入した人たちは、どう感じたの?というのが知りたい人は、一読するといいかも。

 スクラムの詳しい手順とか、やり方とか、方法論を知りたい人は別の本を読んだほうがよさそう。

$resourceによるデータ送信(POST)

 前回は、$resourceによるGETの実装を紹介したが、今回はPOSTの実装の紹介。

angular.module('mockServices', ['ngResource'])
  .factory('mockData', ['$resource',
    function($resource) {
      return $resource("http://example.com:8888/:userid", {
        userid: 99
      }, {
        getMock: {
          method: 'JSONP',
          params: {
            uid: '1',
            callback: 'JSON_CALLBACK'
          },
          isArray: false
        },
        postMock: {
          method: 'POST',
          params: {},
          headers: {
            'Content-Type': 'application/json'
          },
          isArray: false,
        }
      });
    }
  ])

 headerにcontent-typeを指定して、methodにPOSTを指定する。 さてPOSTの場合、どうやってデータを送信するのか気になるところ。GETの場合は、データがサーバ側からやってくるが、POSTの場合は、クライアント側からデータを送信しないといけいない。

 データの送信方法は、下記。

var data = {
  "test": "OKOKOK"
};
mockData.postMock(JSON.stringify(data));

 これでサーバ側には、dataをjson形式で送信できる。

$resourceによるデータ取得(GET)

 AngularJSでデータを取得する方法は、$httpのようなローレベルのAPIを使ってもいいんですが、$resourceを使うのが楽みたいです。$httpをラップしてあるのが$resource。

 今回は、$resourceをサービスとして作って、実際に呼び出す方法の紹介。

angular.module('mockServices', ['ngResource'])
  .factory('mockData', ['$resource',
    function($resource) {
      return $resource("http://example.com:8888/:userid", {
        userid: 99
      }, {
        getMock: {
          method: 'JSONP',
          params: {
            uid: '1',
            callback: 'JSON_CALLBACK'
          },
          isArray: false
        }
      });
    }
  ])

 上記を呼び出したら、実際にurlに対してGETをして、データを取得できます。:useridには、userid:99で指定している99という数値が入って、サーバ側にはリクエストされます。

呼び出し方は下記。

mockData.getMock()

$httpによるデータ取得方法

 AngularJSで、データを送信する方法には、いくつかあると思うんですが、よく紹介されてるのが$httpの方法。

 JSONPを使ってサーバからデータの取得を行います。

function fetchFlowData($scope, $http) {
  var url = "http://example.com:8888/99?callback=JSON_CALLBACK";
  $http.jsonp(url)
    .success(function(data) {
      console.log(data);
    }).
    error(function(response, status, headers, config) {
      console.log(status);
    });
  return data;
}

 ここで重要なのがcallbackに指定するのをJSON_CALLBACKにするということ。JSON_CALLBACKに指定するとよしなに計らってくれるみたい。

PythonによるLinuxプログラミングインタフェース(3章 perror)

the linux programming interfaceというバイブルに載ってるコードをpythonで書くとどうなるのか、個人的なメモ。

ただ、同じコードをos.xxxとかで書くのは面白くなさそうなので、pythonならどうやるのかを調べながら書いていこうと思う。

というわけで、早速p51のperrorに関するコードから。

fd = open(pathname, flags, mode);

if (fd == -1) {

perror("open");

    exit(EXIT_FAILURE);

}
#/usr/bin/env
# -*- coding: utf-8 -*-

pathname = "./nothing"
#pathname = "p51_perror.py"

# openのエラーを補足。おそらく、この書き方がCのエラー補足の書き方に近いのかな?
try:
    f = open(pathname, encoding='utf-8')
    print("open")
except IOError as err:
    print("err1: ", err)

 
# けど、普通pythonでopenするときって、with 〜 asでopenしてcloseはwithにお願いしちゃうと思う。
# けど、withをtryで囲むやり方はpythonicじゃないって書いてあって、良くないと書かれているものもある。

try:
    with open(pathname, encoding='utf-8') as file:
        print("with stmt open")
except IOError as err:
    print("err2: ", err)

 
# そこででてくるのがcontextlibのcontextmanager。
#これを使うと、my_openのような関数も書けるみたい。openの前後でやりたいことを入れ込める。
# 前処理、後処理とかに使えるのかな。

from contextlib import contextmanager
@contextmanager
def my_open(*args, **kw):
    try:
        fp = open(*args, **kw)
    except Exception as err:
        print("err3: ", err)
    else:
        yield fp
        print("in else stmt")
        fp.close()
    finally:
        print("end")

with my_open(pathname) as fp:
    print("my_open")

#classを作って、__enter__が前処理、__exit__が後処理にしてopenの処理をさせることもできる。

class MyOpen2(object):
    def __enter__(self):
        print("__ENTER__")

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("__EXIT__")

with MyOpen2():
    print("middle")