ばぐばぐわーるど

Pythonなどなど

動く小説投稿サイト、Denkinovelを見た感想

動く小説投稿サイトDenkinovel(デンキノベル)

ブログを派手に書きたいならdenkinovel使えば良いと思う - 文系学生のプログラミング入門
↑を読んで知りました。

すでにこんなものがあったのですか。
実は僕これと似たようなものがあったらいいなって考えてました。といってもついこの前のことですが。
かんたん! スライド小説を作ろう!! - ばぐばぐわーるど


小説って面白いかどうかぱっと見て判断できないので、ネット上だとどうしても読み手が少ないです。逆に読まれてるのは最初からすでに面白そうなやつですよね。
よく小説は最初の数ページで決まるみたいな文句がありますけど、ネット上だと最初の5行くらいで決まってそうな感じです。

勢いで読ませたりする会話主体のssとか、絵でなんとなく読んでもらえる漫画だと、小説より敷居が下がるので、ネットだと小説よりそれらが人気がありますね。

動画なんかはこの手のツールとしてかなり強いと思います。いわゆる紙芝居クリエーターとかで作られている動画のことですが。基本的に流れてるものを受動的に見てるだけなので苦痛にならないです。つまらないところがあっても、音と絵があれば全然見れますしね。

ただ、動画は作るのに敷居が高いので、そこまで技術力が無い人とか、音楽と演出に時間をかけるのが面倒な人たちにはDenkinovelは向いてるんじゃないでしょうか。


そういうわけで、最初のほうが退屈でも音とか画像で何とか面白いところまで留まってもらうという方向は正しいんじゃないかなと思います。


Denkinovelではおしゃれな作品が多いみたいですけど、ネット上のものってたぶんギャグベースのもののほうが人気が出ます。もっと言うと、分かりにくいものより単純なものですかね。

同じ理由ですが、シリアスなもの、硬派なものって面白さが分かるまで時間がかかります。どこぞの知らない人が書いたようなものを面白くなるまで読み続けるってかなり大変なことです。

ギャグだと面白さが伝わりやすいです。全体的に取っ付きやすいので読むのも大変じゃないです(作るほうは大変なんですけどね)。だからギャグとかを書くといいと思います。


はい。単に僕がギャグを読みたいだけです。ただそれが言いたかっただけです。
腹がよじれるような面白い話を誰か書け!

Pythonでワンライナー

シェルスクリプトは、Unix 系 OS のユーザにとって最も身近なプログラミング言語でもあり、その習得は必須の技能であると言えます。ほとんど改変を加えずに、様々なシステムでそのまま利用できるという汎用性の高さは非常に優れたものです。

ShellScript - シェルスクリプトを書くときに気をつける9箇条 - Qiita [キータ]

そうは言ってもシェルスクリプトとか覚えられません。というか末端ユーザーの僕にはシェルスクリプトが必要になる状況ってあんまり無いという・・・。使ってるのWindowsだし。万が一必要なときはググってコピペなのでまったく身につきません。


というわけで、何かあったときのためのPythonワンライナーの練習です。
Pythonなら辛うじてググらずにできるはず・・・たぶん・・・

Pythonは -cオプションをつけると後ろに書いた文字列をPythonのプログラムとして実行できます。文字を囲むのはダブルクォーテーションじゃなきゃ駄目みたいです。


とりあえず思いつくままに。

1 Hello World

python -c "print 'Hello World'"

2 0から99まで出力

 python -c "print '\n'.join([str(i) for i in range(100)])"

3 dir0からdir99までのディレクトリを作成

python -c "import os; [os.mkdir('dir'+str(i)) for i in range(100)]"

4 数値が1行ずつ書き込まれているファイルを読み、num+数値としたファイルを作る

printでリダイレクトとか使うとunicodeで出力されてしまいます。どうしたらいいんだろ。

python -c "print ''.join(['num'+i for i in open('num.txt')])" > newnum.txt

5 ファイルの文字をすべて大文字にして出力

python -c "print open('hoge.txt').read().upper()"


思いつかなくなったのでPerl one liner 集 perl 1行野郎を参考に書いていきます。

6 最初の50行を表示

python -c "print ''.join([line for line,i in zip(open('hoge.txt'),range(50))])"

7 任意の行を表示(2~5行まで)

python -c "print ''.join([line for i,line in enumerate(open('hoge.txt')) if 2<=i<=5 ])

8 commentという文字列が含まれている行を表示

python -c "print ''.join([i for i in open('comment.txt') if i.find('comment') != -1])"

9 commentまたはappleが含まれている行を表示

python -c "print ''.join([i for i in open('comment.txt') if i.find('comment') != -1 or i.find('apple') != -1])"

10 ファイル中にある行単位でのfooをbarに置き換える

1単語ずつ改行されているような場合を想定しています。
3項演算子を使います。だんだん雲行きが怪しくなってまいりました。

python -c "print ''.join(['bar' if i[:-1]=='foo' else i for i in open('okikae.txt') ])"

11 ファイル中のfooをbarに置き換える

11と違い普通の文章の場合を想定しています。
リスト内包で作ったリストをさらにリスト内包で・・・

python -c "print ''.join([i if i[-1]=='\n' else i+' ' for i in ['bar' if j[:-1]=='foo' else j for i in open('okikae.txt') for j in i.split(' ') ]])"

うわああああああ難しいいいいいできないいいいい
これだと改行直前か文字列中かのどちらかがうまく置き換わりません・・・

どうしたらいいの・・・あっ
replaceメソッド忘れてました///

python -c "print open('okikae.txt').read().replace('foo','bar')"

悩むくらいなら改行しろって話ですよね。
ダブルクォーテーションで閉める前に改行すると普通に入力を待ってもらえます。

Pythonで学ぶ数学 集合編

この前の心意気虚しく紹介したページの内容全然分かりませんでした。数学以前にPython力が足りてなかったです。抽象基底クラスとかイミフです。

というわけで、まずは簡単な数学からやってレベルを上げてくことにします。
とりあえず適当に作った問題をPythonで解いていきます。問題は一部、すぐわかる代数(東京図書)を参考に作りました。
今回は基本ということで集合から。


問題1 部分集合

 A = \{n | n = 12m , 0 < m  < 5 \}
 B = \{n | n = 6m , 0 < m < 10 \}
このとき
 A \subseteq B
を証明せよ。

ほんとは  m \in \mathbb{Z} がやりたかったのですが、まあ無理なので有限の集合にしときました。

解答

A = {12*n for n in range(1,5)}
B = {6*n for n in range(1,10)}
print A.issubset(B)

リスト内包表記は集合を表すset型({}のやつ)でも使えます。数学とほとんど表記が一緒なので分かりやすいです。
 B = \{6n | 0 < n < 10 \}
これならもっと近いです。数学的にこういう書き方(左側が素の文字じゃない)していいのか知らないですけど。意味は通じるのでたぶんあり?

3行目は A is subset of B で、AはBの部分集合(subset)だって主張です。真偽値を返します。

実行結果
True

というわけで証明できました。証明・・・?


問題2 直積

 A = \{ 1, 2, 3 \}
 B = \{ 2, 4, 6 \}
のときABの直積 A \times Bを求めよ。

ちなみに直積は数学ではこう書きます。
 A \times B = \{ (a,b) | a \in A \wedge  b \in B \}

解答(3通り)

def tyokuseki(A,B):
    li = []
    for x in A:
        for y in B:
            li.append((x,y))
    return li 

def gentyoku(A,B):
    for x in A:
        for y in B:
            yield (x,y)

A = range(1,4) 
B = range(2,7,2)

print tyokuseki(A,B)
print [x for x in gentyoku(A,B)]
print [(a,b) for a in A for b in B]
実行結果
[(1, 2), (1, 4), (1, 6), (2, 2), (2, 4), (2, 6), (3, 2), (3, 4), (3, 6)]
[(1, 2), (1, 4), (1, 6), (2, 2), (2, 4), (2, 6), (3, 2), (3, 4), (3, 6)]
[(1, 2), (1, 4), (1, 6), (2, 2), (2, 4), (2, 6), (3, 2), (3, 4), (3, 6)]

無駄に3つも載せました。思いついた順です。一つ目は普通に繰り返し、二つ目はジェネレータとリスト内包、三つ目はネストしたリスト内包表記です。
最後のネストしたリスト内包表記は数学の表記に近いですね。おまけに楽だし。


問題3 集合の演算

 X + Y \equiv X \cup Y
とする。
 A = \{ a,b,c \}
 B = \{ c,d,e \}
のとき
 A + B
を求めよ。

+(たす)は今までの意味とか考えずに、新しい演算として定義されていることに注意です。
関数でもできるんでしょうが、ここはせっかくなので演算子のオーバーロードでやりたいところですね。

解答

class Cup(object):
    def __init__(self, a):
        self.a = a

    def __add__(self, other):
        return self.a | other.a

set1 = {"a","b","c"}
set2 = {"c","d","e"}

A = Cup(set1)
B = Cup(set2)

print A+B
実行結果
set(['a', 'c', 'b', 'e', 'd'])

set型は | で和集合を取ります。通常+になってる部分を | に変えました。


補足 演算子のオーバーロードとは何か

上の例で行くとA+Bの定義を変えるのを、__add__という特殊メソッドを上書きしてしまうことで実現することです。
他の簡単な例も考えてみます。

  • 足し算を引き算にする。
class Gyaku:
    def __init__(self, x):
        self.x = x

    def __add__(self, other):
        return self.x - other.x 

go = Gyaku(5)
san = Gyaku(3)

print go + san 
実行結果
2

go + sanと書くとgo.__add__(san)が呼び出されます。
go.x - san.x が返されるわけです。

  • ベクトルの計算(足し算のみ)をする。
class Vector(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, other):
        return Vector(self.x + other.x , self.y + other.y)

v1 = Vector(1,5)
v2 = Vector(2,6)

V = v1+v2
print V.x, V.y 
実行結果
3 11

この場合はベクトル型が返されてるので、V.xとV.yで数値を取り出して表示してます。


なんというか、Pythonで学ぶ数学というより、数学で学ぶPythonですが今回はこんなところで。

PythonでAndroid端末のカメラをリモート操作

良いもの。悪いもの。: Pythonを使ってAndroid端末を5分でリモートカメラにする方法

す、すげえええええ

というわけでやってみました。
できました。たしかに5分でできたけど写真撮った後フリーズする・・・
でもすごいです。

まず普通にPythonAndroidの操作をしていることに驚きました。
前にAndroidのプログラミングしようと思ったときに、開発環境の準備の時点で問題が起きまくってどうでも良くなった思い出があるのですが、SL4Aなら手軽でよさそうです。
SL4A による Android プログラミング


おまけ(本編)

AirDroidというアプリを使うとUSB接続しなくてもPCからファイルを投げ込めるので便利です。
Dropboxとかと違うのはいちいち外部のサーバーとかを経由していないとこです。
USB接続はSDカードのマウント解除をしますが、これならその必要がないです。地味に大きい利点だと思います。
自分のAndroid端末でサーバを立ち上げてるっぽいので、同じ無線LANに接続してたらPCとAndroid端末を直に通信することができます。(アカウント登録すれば3G回線などでも接続が可能)

ってこのアプリもカメラのリモート操作使えますね。すごいです。このアプリ知ってるのと知らないのではAndroidに対する評価がわりと変わるんじゃないでしょうか。

AirDroid - Google Play の Android アプリ

Pythonで代数学?

僕は実は数学ガールを全巻読んでいるくらいには数学好きだったりします。まあ物語を楽しんでるだけで、数式部分はまともに読んでないんですが。(前半のほうは頑張って読んでます)


そんなこんなで、なんとなくPython 代数学でググってみるとこんなページが

Elliptium / Python で書く代数

Pythonによる代数系の表現

まだちゃんと読んでないけれど、ちょっと衝撃的です。
代数にPythonだと? その発想はなかった。


僕はカッコよさそうだからって理由で代数に挑戦してみたことがあるんですがすぐに撃沈しました。

なんか当たり前だなーって思ってたら、いつの間にか理解できなくなってるんですよね。
公理とか証明とか見ても、ふむふむ・・・なるほど、でっていう。

で、つまんなくなってやめてしまいます。

頭を使う面白い部分まで到達できてないんでしょうね。
たぶん僕の代数のレベルって、プログラミングでいうところのif文とかfor文とかの最初の文法を覚えるようなレベルだと思うんですよ。大前提の暗記部分。そんな部分で立ち止まってるから糞面白くないのではないかと。


でも、自分の中で今一番ホットな話題であるPythonが絡めば少しは楽しくなるかも?
というわけで代数をPythonで理解していくという試みをしてみようかと思います。
今日はそんな意気込みだけです。

Pythonで掲示板に自動で書き込み、ぱっと見人が会話しているように見せる

この前作った掲示板ですが、作って終わりなのは寂しいので、よくある自動書き込みっぽいことをして人が居る風な感じを出してみます。

以下コードの説明
requestsを使う書き込み用の関数とurllib2を使う書き込み用の関数を作りました。たぶん同じ動作だと思います。書き込む内容はname_listに入ってる名前とhonbun_listに入ってる内容をランダムに取り出して決めてます。
ランダムに決めた内容を書き込み用の関数に投げ入れ30回繰り返してます。あと一気に書き込むとよくなさそう?なので10秒止めてます。

# coding: utf-8

import urllib
import urllib2
import requests
import random
import time

url = 'http://bgbg.wkeya.com/bbs/bbs.py'
name_list = ['佐藤','鈴木','高橋','田中','伊藤','山本','渡辺','John Smith','名前など無い','ああああ','鳥','イルカ','ぺんぎん','']
honbun_list = ['今日はいい天気ですね','今日は台風ですよ・・・','貴様が憎い!','やれるもんならやってみな','お前はそういうところあるもんな','えっ','いや・・・','別に好かれるためにやってるわけじゃない','もう少しだけ我慢して','でっていう','最高だぜ','忘れた','結構じゃないですか','礼儀ただしい!!','ごめんなさい','礼を言う','懐かしいな(笑)','いやダメだろ','やべえ','財布無くした','まじかよ','あああああああ','どうした','辛い']

# requsetsを使った書き込み (Requests http://jp.python-requests.org)
def kakikomi_requests(name, honbun):
    payload = {"name":name, "text":honbun, "submit":"書き込む"}
    requests.post(url, data=payload)
    print name.decode('utf-8'), honbun.decode('utf-8')

# urllib,urllib2を使った書き込み
def kakikomi_urllib2(name, honbun):
    req = urllib2.Request(url)
    payload = urllib.urlencode({"name":name, "text":honbun, "submit":"書き込む"})
    req.add_data(payload)
    urllib2.urlopen(req)
    print name.decode('utf-8'), honbun.decode('utf-8')

# 30回書き込み
for i in range(30):
    name_num = random.randint(0, len(name_list)-1)
    honbun_num = random.randint(0, len(honbun_list)-1)
    kakikomi_requests(name_list[name_num], honbun_list[honbun_num])
    #kakikomi_urllib2(name_list[name_num], honbun_list[honbun_num])
    time.sleep(10) #10秒停止

以下実行結果(一部)

22 名前:高橋 2013年10月2日23時23分23秒
今日は台風ですよ・・・ 

23 名前:田中 2013年10月2日23時23分33秒
どうした 

24 名前:山本 2013年10月2日23時23分44秒
貴様が憎い! 

25 名前:佐藤 2013年10月2日23時23分54秒
もう少しだけ我慢して 

26 名前:田中 2013年10月2日23時24分5秒
結構じゃないですか 

27 名前:鳥 2013年10月2日23時24分16秒
今日は台風ですよ・・・ 

28 名前:ぺんぎん 2013年10月2日23時24分26秒
やれるもんならやってみな 

29 名前:イルカ 2013年10月2日23時24分37秒
辛い 

どう見ても会話が不自然ですが、まあそれは置いときましょう。

Pythonで掲示板を作り公開する方法 その2

掲示板本体の話をしていきます。
初心者の方で自作の掲示板を作りたい人は、まずは基本のページの表示、次にフォームから送信されたものを表示する機能、それを保存する機能、ある程度書いたら関数にまとめる、クラスにしてみるなどと自分でちょこちょこ作っていくといいと思います。一気に書いたらエラーが出まくって何がなんだか分からなくなります。もしエラーがでたらその1の最後に書いてあるエラー対策を参考にしてください。

僕自身も初心者なのでそうやって書いてできたのが下のbbs.pyです。なので一応動くからといってコピペとかはするべきじゃないです。基本的に初心者が自力で作ったものなので、普通じゃないやり方をしてるかもしれないからです。
解説と困ったとこを下に載せとくので、もし同じ場面で困ってたら参考にしてください。

bbs.py

#!/usr/bin/python
# coding: utf-8

import cgitb; cgitb.enable()
import cgi
import datetime

html = """
<html>
<head>
    <title>BBS</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
    <h1>掲示板</h1>
    <form action="bbs.py" method="post">
        <input type="submit" name="submit" value="書き込む">
        <label for="name">名前</label>
        <input type="text" name="name" >
        <label for="email">mail</label>
        <input type="text" name="email" >
        <p><textarea name="text" rows=8 cols=60 ></textarea>
    </form>
    <hr>
    {thread}
    <br>
    <br>
    <form action="bbs.py" method="post">
        <input type="submit" name="remove" value="remove">
    </form>
</body>
</html>
"""

board = """
<dt>{num} 名前:{name} {time} {email}<dd>
{text}
<br><br>"""

class Keijiban(object):

    def __init__(self):
        #フォームからデータを受け取る
        f = cgi.FieldStorage()
        text = f.getfirst("text","")
        text = cgi.escape(text)
        self.text = "<br>".join(text.split("\n"))
        self.name= f.getfirst("name","名無し")
        self.email = f.getfirst("email","")
        self.rm = f.getfirst("remove","")
        self.submit= f.getfirst("submit","")

    def kakikomi(self,name,email,text):
        #ファイルにフォームのデータと時間等を書き込む
        f = open('bbs.dat',"a+")
        n = open('number.dat',"r+")
        number = str(int(n.readline())+1)
        t = datetime.date.today()
        h = datetime.datetime.now()
        time = "{}年{}月{}日{}時{}分{}秒".format(t.year,t.month,t.day,h.hour,h.minute,h.second)

        save = board.format(num=number,name=name,time=time,email=email,text=text)
        f.write(save)
        n.seek(0)
        n.write(number)
        f.close()
        n.close()

    def output_board(self):
        #内容を出力
        f = open('bbs.dat',"r")
        return f.read()

    def remove(self):
        #全て削除
        f = open('bbs.dat','w')
        n = open('number.dat',"w")
        n.write('0')
        f.close()
        n.close()
        return ""

keiji = Keijiban()

if keiji.submit == "":
    thread = ""
    if keiji.rm == "remove":
        thread = keiji.remove()
 
else:
    keiji.kakikomi(keiji.name, keiji.email, keiji.text)

thread = keiji.output_board()

print "Content-type: text/html"
print ""
print html.format(thread=thread)
解説

フォームから送られた内容はcgi.FieldStorageで受け取ることができます。やってることはフォームから受け取った内容をhtmlに埋め込んでるだけです。
bbs.datとnumber.txt(初期値0を書いとく)をbbs.pyと同じディレクトリに用意しときます。
bbs.datファイルに掲示板の書き込み内容をhtmlごと追記して、最後保存内容を表示する流れです。

困ったとこ
  • フォームから受け取った文字列が改行できない

改行を<br>に変える。Keijibanクラスの__init__にあります。

"<br>".join(text.split("\n"))
  • ファイルへの追記、更新ってどうやるんだっけ

open()のオプションに以下を指定
a+ ・・・追記
r+ ・・・更新(読み取りと書き込み)

w+ は最初にファイルを空にして読み書きなのでr+(空にしない)と混同しないようにしましょう。
r+ はファイルシークを先頭行に戻してから(seek(0)を使う)書き込むことに注意
Keijibanクラスの関数kakikomi参照

  • datetimeのオブジェクト多すぎてどれ使えば現在時刻になるのかわかんね

日月時->datetime.date.today()
時分秒->datetime.datetime.now()

疑問

format(thread=thread)
とかやってますけど、thread=threadみたいなのってマナー的にありなんでしょうか・・・
なんとなくダメな気がしましたが、まあいいや。

あと変数一文字ってエディタで置換させにくくて困りますね。ちゃんと意味わかる長さの名前つけるべきです。