作った、というか作り始めた。とりあえず基本的な機能として、新規追加と編集はできるようになった。削除はまだ。Flask で DELETE メソッドってどうやって発行するんだ?
メインの画面はこんな感じ。
デザインもまだなんにもしてない。スタイルシートはこれからだな。
書籍の詳細画面。
参考にしたのは、先週のエントリで挙げたサイトのほかにこのあたり。
cf. http://a2c.bitbucket.org/flask/quickstart.html
cf. FlaskSQLAlchemy
takatoh's blog – Learning programming languages.
作った、というか作り始めた。とりあえず基本的な機能として、新規追加と編集はできるようになった。削除はまだ。Flask で DELETE メソッドってどうやって発行するんだ?
メインの画面はこんな感じ。
デザインもまだなんにもしてない。スタイルシートはこれからだな。
書籍の詳細画面。
参考にしたのは、先週のエントリで挙げたサイトのほかにこのあたり。
cf. http://a2c.bitbucket.org/flask/quickstart.html
cf. FlaskSQLAlchemy
Flask は Python の軽量 Web ワークフレーム。Ruby の Sinatra に影響を受けてるらしい。
さわった、といってもほんのちょっとだけ。↓のページの 1 〜 4 をやってみた。
cf. Pythonで学ぶwebアプリケーションの作り方by Flask
結果出来たのがこの Flaskr という小さなブログみたいなアプリケーション。login 機能がついてて、記事をポストできる。
基本的に、上のページのチュートリアルのとおりにやればできたんだけど、ひとつだけ、アプリケーションを起動するときに Warning が発生する(アプリケーション自体は動く)。
(env)takatoh@nightschool $ python manage.py runserver
/home/takatoh/w/handson/env/local/lib/python2.7/site-packages/flask_sqlalchemy/__init__.py:800: UserWarning: SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future. Set it to True to suppress this warning.
warnings.warn('SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future. Set it to True to suppress this warning.')
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
メッセージにあるとおり、この警告を抑制するには config.py の中で SQLALCHEMY_TRACK_MODIFICATIONS に True をセットしてやればいい。
SQLALCHEMY_DATABASE_URI = 'sqlite:///flaskr.db' SECRET_KEY = '\xce\xa3/\x97\xf60\xc1\x9c\x10J\xa2)t\r\xfd\xa9.\xdf\x8d\xe3\xfc\xfd\xb4\x9a' SQLALCHEMY_TRACK_MODIFICATIONS = True
というわけで、今日はここまで。もう少しさわってみたらなにか作ってみるかな。
今日は Windows マシンから更新。
cf. ruby 文字列を指定数で分割する – それマグで!
Haskell でやってみた。
module Main where
slices :: Int -> [a] -> [[a]]
slices _ [] = []
slices n xs = h : slices n d
where
(h, d) = splitAt n xs
main :: IO ()
main = print $ slices 3 "abcdefghijklmnopqrstuvwxyz"
^o^ > runhaskell stringSlices.hs ["abc","def","ghi","jkl","mno","pqr","stu","vwx","yz"]
Scheme だとこう。
(define slices
(lambda (lis n)
(if (< (length lis) n)
(list lis)
(cons (take lis n) (slices (drop lis n) n)))))
(define string-slices
(lambda (str n)
(map list->string (slices (string->list str) n))))
(print (string-slices "abcdefghijklmnopqrstuvwxyz" 3))
^o^ > gosh string-slices.scm (abc def ghi jkl mno pqr stu vwx yz)
最後に JavaScript。
function stringSlices(n, str) {
var l = str.length;
var result = [];
for (var i = 0; i < l; i += n) {
result.push(str.slice(i, i + n));
}
return result;
}
console.log(stringSlices(3, "abcdefghijklmnopqrstuvwxyz"));
^o^ > node stringSlices.js [ 'abc', 'def', 'ghi', 'jkl', 'mno', 'pqr', 'stu', 'vwx', 'yz' ]
これ、もうちょっとスマートにいかないかな。
JavaScript 版、Haskell 版や Scheme 版と同じように考えてみた。少しはスマートになったかな。そうでもないか?
function stringSlices(n, str) {
if (str.length == 0) {
return [];
} else {
var l = stringSlices(n, str.slice(n))
l.unshift(str.slice(0, n))
return l
}
}
console.log(stringSlices(3, "abcdefghijklmnopqrstuvwxyz"));
^o^ > node stringSlices2.js [ 'abc', 'def', 'ghi', 'jkl', 'mno', 'pqr', 'stu', 'vwx', 'yz' ]
ネットを見ていたら、古い記事だけどこんなのを見つけた。
cf. 短縮URLを1行で展開する@Python – shibuya blog
スクリプトにするんなら1行にすることないだろ、とも思ったけどそれはそれとして、わざわざ短縮元の URL にアクセスしなくても、短縮 URL に HEAD メソッドでアクセスしてヘッダーだけ取ってきて Location を見ればいい、というのをどこかで読んだ覚えがある。
というわけで、Python で書いてみた。
import httplib
import urlparse
import sys
url = sys.argv[1]
o = urlparse.urlparse(url)
conn = httplib.HTTPConnection(o.netloc)
conn.request("HEAD", url)
res = conn.getresponse()
print res.getheader("Location")
今回調べたわかったけど、urllib じゃ HEAD メソッド使えないらしい。で、より低レベルの httplib を使ってる。
実行結果:
takatoh@nightschool $ python expandurl.py http://bit.ly/1axxIi4 https://blog.panicblanket.com/
以前作って rubygems.org に登録した gem、filestorage を filestorage と filestorage-s3 に分割してリリースした。どっちもバージョン0.1.0。
機能的には直前のバージョン0.0.6と変わったところはないけど、ローカルファイルシステム用の filestorage と Amazon S3 用の filestorage-s3 に分けた。これでローカルファイルシステムしか使わないのに、aws-sdk とかがインストールされることもなくなった。
良かったら使ってください。
ソースコードはこちら:
前にも Ruby や Python でやったネタだけども。
#include
#include
#include
#include
int main(int argc, char *argv[])
{
int i;
char strpool[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
int lenpool = strlen(strpool);
int l, r;
l = atoi(argv[1]);
char strrand[l + 1];
srand((unsigned) time(NULL));
for (i = 0; i < l; i++) {
r = rand() % lenpool;
strrand[i] = strpool[r];
}
strrand[l] = '\0';
printf("%s\n", strrand); return 0;
}
takatoh@nightschool $ gcc -Wall -o strrand strrand.c takatoh@nightschool $ ./strrand 20 hiVKZhO2rwtlDPUJmdo7
タイトルのとおり。
#include
#include
int main(int argc, char *argv[])
{
unsigned long long int a, b, tmp;
int n, i;
n = atoi(argv[1]);
a = 1;
b = 1;
for (i = 1; i <= n; i++) {
printf("%lld\n", a);
tmp = a + b;
a = b;
b = tmp;
}
return 0;
}
実行結果:
takatoh@nightschool $ ./fib 100 1 1 2 3 5 8 13 21 34 (中略) 4660046610375530309 7540113804746346429 12200160415121876738 1293530146158671551 13493690561280548289 14787220707439219840 9834167195010216513 6174643828739884737 16008811023750101250 3736710778780434371
最後のほうで桁が少なくなったり、明らかにおかしな数値になってしまう。
試しに Ruby でやってみた。
def fib(n)
a = b = 1
1.upto(n) do |i|
puts a
a, b = b, a + b
end
end
fib(ARGV[0].to_i)
takatoh@nightschool $ ruby fib.rb 100 1 1 2 3 5 8 13 21 34 (中略) 4660046610375530309 7540113804746346429 12200160415121876738 19740274219868223167 31940434634990099905 51680708854858323072 83621143489848422977 135301852344706746049 218922995834555169026 354224848179261915075
ちゃんと計算できてる! Ruby すげー!
気がつけば1か月もあいだが開いてしまった。
さて、その1か月前のコードを眺めていて気がついたんだけど、スタックから Pop しようとしたとき、スタックが空だったらエラーになってほしい。けど、どうやったら呼び出し側にエラーを伝えられるんだろう?
Pop() の返り値でエラーを伝えることは出来ない。返り値は int 型のどんな値でも有効だから。
調べてみると errno というグローバル変数(?) に値を設定しておく、というやり方があって errno の値(整数値)でどんなエラーかを知らせるようだけど、Pop() のエラーに対応するような errno の値がない。勝手に作ってもいいもんだろうか。
先週書いた連結リストのコードをライブラリにして、スタックを実装してみた。
#include
#include
#include "linkedlist.h"
#define Stack Cell
Stack *Push(Stack *stack, int x);
int Pop(Stack **stack);
int main(void)
{
Stack *stack;
int n;
stack = NULL;
stack = Push(stack, 1);
stack = Push(stack, 3);
stack = Push(stack, 5);
DisplayList(stack);
n = Pop(&stack);
printf("%d <- ", n);
DisplayList(stack);
FreeList(stack);
return 0;
}
Stack *Push(Stack *stack, int x)
{
Stack *list;
list = Cons(x, stack);
return list;
}
int Pop(Stack **stack)
{
int x;
x = Head(stack);
return x;
}
typedef struct cell Cell; Cell *NewCell(int val); Cell *Cons(int val, Cell *list); Cell *Insert(Cell *list, int pos, int val); Cell *Delete(Cell *list, int pos); int Head(Cell **list); void DisplayList(Cell *list); void FreeList(Cell *list);
#include
#include "linkedlist.h"
typedef struct cell {
int value;
struct cell *next;
} Cell;
Cell *NewCell(int val)
{
Cell *data;
data = (Cell *)malloc(sizeof(Cell));
data->value = val;
data->next = NULL;
return data;
}
Cell *Cons(int val, Cell *list)
{
Cell *data;
data = NewCell(val);
data->next = list;
return data;
}
Cell *Insert(Cell *list, int pos, int val)
{
Cell *cell1, *cell2;
int i = 1;
if (pos == 0) {
list = Cons(val, list);
} else {
cell1 = list;
while (i < pos) {
cell1 = cell1->next;
i++;
}
cell2 = NewCell(val);
cell2->next = cell1->next;
cell1->next = cell2;
}
return list;
}
Cell *Delete(Cell *list, int pos)
{
Cell *cell1, *cell2;
int i = 1;
if (pos == 0) {
cell2 = list;
list = cell2->next;
free(cell2);
} else {
cell1 = list;
cell2 = cell1->next;
while (i < pos) {
cell1 = cell2;
cell2 = cell1->next;
i++;
}
cell1->next = cell2->next;
free(cell2);
}
return list;
}
int Head(Cell **list)
{
int val;
val = (*list)->value;
*list = Delete(*list, 0);
return val;
}
void DisplayList(Cell *list)
{
printf("%d", list->value);
if (list->next == NULL) {
printf("\n");
} else {
printf(", ");
DisplayList(list->next);
}
}
void FreeList(Cell *list)
{
Cell *next = list->next;
free(list);
if (next != NULL) {
FreeList(next);
}
}
linkedlist.h で
typedef struct cell Cell;
とあるのは、構造体の中身を隠蔽して、その存在だけを公開する書き方。こうすることで、ライブラリを利用する側からは構造体を直接操作することはできなくなる(操作用の関数を使って操作する)。
実行結果:
takatoh@nightschool $ gcc -Wall main.c -c takatoh@nightschool $ gcc -Wall linkedlist.c -c takatoh@nightschool $ gcc -Wall main.o linkedlist.o -o stack takatoh@nightschool $ ./stack 5, 3, 1 5 <- 3, 1
出力の1行目は値(整数)を3つ push したあとのスタックの状態。2行目の <- の左側は pop して取出した値で、右側がそのあとのスタックの状態。 期待通りに動いてるようだ。
連結リスト(linked list、リンクリスト)とは、構造体のメンバに「次の構造体へのポインタ」を持たせて、数珠つなぎにしたデータ構造。いちばん最後の構造体の持つポインタは NULL。ようするに Scheme のリストと同じ構造だと思って良さそう。
#include
#include
typedef struct cell {
int value;
struct cell *next;
} Cell;
Cell *NewCell(int val);
Cell *Cons(int val, Cell *list);
Cell *Insert(Cell *list, int pos, int val);
Cell *Delete(Cell *list, int pos);
int Head(Cell **list);
void DisplayList(Cell *list);
void FreeList(Cell *list);
int main(void)
{
Cell *list;
int i, head;
list = NewCell(0);
for (i = 1; i < 10; i++) {
list = Cons(i, list);
}
puts("before:");
DisplayList(list);
list = Insert(list, 5, 10);
puts("insert 10 at 5th position:");
DisplayList(list);
list = Delete(list, 0);
puts("delete 0th cell:");
DisplayList(list);
head = Head(&list);
printf("pick up head value (and delete the cell): %d\n", head);
DisplayList(list);
FreeList(list);
return 0;
}
Cell *NewCell(int val)
{
Cell *data;
data = (Cell *)malloc(sizeof(Cell));
data->value = val;
data->next = NULL;
return data;
}
Cell *Cons(int val, Cell *list)
{
Cell *data;
data = NewCell(val);
data->next = list;
return data;
}
Cell *Insert(Cell *list, int pos, int val)
{
Cell *cell1, *cell2;
int i = 1;
if (pos == 0) {
list = Cons(val, list);
} else {
cell1 = list;
while (i < pos) {
cell1 = cell1->next;
i++;
}
cell2 = NewCell(val);
cell2->next = cell1->next;
cell1->next = cell2;
}
return list;
}
Cell *Delete(Cell *list, int pos)
{
Cell *cell1, *cell2;
int i = 1;
if (pos == 0) {
cell2 = list;
list = cell2->next;
free(cell2);
} else {
cell1 = list;
cell2 = cell1->next;
while (i < pos) {
cell1 = cell2;
cell2 = cell1->next;
i++;
}
cell1->next = cell2->next;
free(cell2);
}
return list;
}
int Head(Cell **list)
{
int val;
val = (*list)->value;
*list = Delete(*list, 0);
return val;
}
void DisplayList(Cell *list)
{
printf("%d", list->value);
if (list->next == NULL) {
printf("\n");
} else {
printf(", ");
DisplayList(list->next);
}
}
void FreeList(Cell *list)
{
Cell *next = list->next;
free(list);
if (next != NULL) {
FreeList(next);
}
}
Head() がちょっと難儀したので説明しておこう。
main() の中で list は連結リストの先頭へのポインタだ。Head() の呼び出しは Head(&list) というふうにしている。で、Head() の定義は、Head(Cell **list) となっていて **list はポインタへのポインタを表している。&list というのは list のアドレスを表しているので、この関数の引数は「連結リストの先頭のアドレスを保持する変数のアドレス」を渡していることになる。
なんでこういうことをしているかというと、Head() はリストの先頭の値を返すだけじゃなくて先頭のセルを削除する。ということはリストの先頭のアドレスが変わるってこと。ポインタの値を変更するには、こういうふうにポインタのポインタを渡して、関数内でアドレスを書き換えてやるわけだ。
ちなみに、Delete() もリストの先頭を削除するので、先頭へのポインタの値が変化するけど、こっちは素直に変更されたアドレスを返している(ほかに返す値がないから)。
実行結果:
takatoh@nightschool $ ./linkedlist before: 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 insert 10 at 5th position: 9, 8, 7, 6, 5, 10, 4, 3, 2, 1, 0 delete 0th cell: 8, 7, 6, 5, 10, 4, 3, 2, 1, 0 pick up head value (and delete the cell): 8 7, 6, 5, 10, 4, 3, 2, 1, 0