Pythonその他もろもろ

1.日付関数 time、datetime

datetimeモジュールを整理

名前 datetimeモジュールの場合
モジュール datetime
オブジェクト date , datetime
メソッド today() ,now()

具体例でみていこう。
・以下では、datetimeモジュールをインポートしている。
・datetimeには日付と時刻の情報を持つdatetimeと、日付の情報を持つdateがあり、どちらも利用できる。
・またdatetimeというモジュールの表記を省略してもいい。
❶datetimeを使う

import datetime
print(datetime.date.today())         # => 2019-01-01
print(date.today())           # => 2019-01-01
print(datetime.datetime.today())  # => 2019-01-01 02:54:52.192751
print(datetime.datetime.now())   #==> 2019-01-01 02:54:52.192751

・ただし、タイムゾーンがUTCなのでnow()を使っても、時刻が9時間ズレてしまう。そこで、以下のようにする

import datetime
import pytz
#JSTで表現
jst = pytz.timezone('Asia/Tokyo')
print(datetime.datetime.now(tz=jst)) #==> 2020-12-15 20:43:01.243716+09:00  ※today()では使えない

❷以下のような書き方もできる。
こちらは、dateやdatetimeというオブジェクトを指定してインポートしている。

from datetime import date
print(date.today()) #==> 2020-01-03
from datetime import datetime
print(datetime.today()) #==> 2020-01-03 09:03:21.724293

❸time.sleep関数
処理を一時停止させることができる。構文は以下。

time.sleep(停止させる秒数)

2.format

文字のフォーマットを指定するのであるが、文字と変数を組み合わせてprintするときなどにも便利である。
以下をみてみよう。
❶基本の使い方
・{}で変数や文字などの番号を指定する。変数だけじゃなく、文字列でも対応可能。.formatでつないで、変数や文字列を指定する。
・{1}{2}{3}のように連続して表記も問題がない。{1},{2},{3}などとカンマで区切る必要なく、カンマを入れた場合は、カンマが出力される。

name="伊藤";age=153
x = "{0}さんの身長は{1}cm{2}。".format(name, age,"です")
print(x) #==>伊藤さんの身長は153cmです。

・formatの中で、順番に並べるのであれば、インデックス番号である数字を入れずに{}だけでも可能。

name="伊藤";age=153
x = "{}さんの身長は{}cm{}。".format(name, age,"です")
print(x) #==>伊藤さんの身長は153cmです。

❷フォーマットを細かく指定する
書式を指定するには、以下のようにコロン(:)でつなぐ。
{インデックス番号:書式}
{0:.3f} #==> 3は、小数点以下の桁数、fはfloat(浮動小数点数)
{0:,.3f} #==> ,をつけることで、3桁ずつでカンマをつける
{0:12.3f} #==>12の数字は、総文字数と考えればいいだろう。今回は15文字の枠に12文字しかないから、スペースが埋められて「高さは 1530.123m」なる。

tall=1530.1234
x = "高さは{0:,.3f}m".format(tall)
print(x)  #==>高さは1,530.123m

3.lambda(無名関数)

・通常、関数を定義する場合はdefを使う。でも、わざわざ関数で定義するまでもないこともあるだろう。
そんなとき、lambdaを使う。
・構文は
lambda 引数:処理(返り値)
❶通常の関数との比較
・1を加える関数func1を定義

def func1(x):
  return x*2
print(func1(3)) #==>6

・lambdaを使う

a = lambda x : x*2
print(a(3)) #==>6

❷少し複雑にしてみよう
さきと同じ関数にて、[1,2,3]のリストをmapによって、それぞれの値に1を足す。

def func1(x):
    return x+1
print(list(map(func1,[1,2,3])))

・同じ処理をlambdaを使うと以下のようになる。func1と代わりに、lambdaで引数とそれに対する処理(返り値)を書くことができる。

print(list(map(lambda x:x+1,[1,2,3])))

※[1,2,3]は、lambdaの構文ではなく、mapの構文と考えた方がいいだろう。
❸配列の並べ替え
key=lambda として、並べ替えるキーを設定すると、その順にSortができる。

data = [(2, 'b'),(1, 'c'),(3, 'a')]
data.sort(key =lambda x : x[1])
print(data) #==>[(3, 'a'), (2, 'b'), (1, 'c')]

4.構文エラーと例外処理

Pythonのエラーには「構文エラー」と、構文は合っているが、0で割るなどの処理をした「例外」の2つがある。たとえば、入力中にCtrl+Cで途中終了するのは、KeyboardInterruptの例外。辞書型において、キーが存在しない場合などに出るのが「KeyError例外」

(1)構文エラー

SyntaxError: invalid syntax と表示されることであろう。
字句解析、構文解析を行うパーサ(構文解釈器)が、エラーの行や内容などを出力する。

❶エラー1
SyntaxError: Non-UTF-8 code starting with '\x82' in file

こんなエラーが出るときは、UTF-8でファイルを保存する。
エディタで保存する際に、Shift-JISなど選べます。

(2)例外処理

・構文としては、try: except: を記載する。
・tryには、エラーが起こるかもしれないが、実行させたいプログラムを普通に書く。
・exceptに、エラーが発生したときの処理を書く。何もさせずに終わらせたいのであればpassを書けばいい。
・exceptに続いて、エラーの内容を指定できる。たとえば、ゼロでの割り算を実行した場合の処理を確認は以下。
except ZeroDivisionError:
・これにより、例外発生(0で割る)などが発生したときの対処ができます。
たとえば、以下をみてみよう。

def func1(a):
    try: 
        print(10/a) #aで割るので、aが0だと例外処理にしたい
    except:
        print('ダメよーダメダメ')
func1(1) # ==> 10.0
func1(2) # ==> 5.0
func1(0) # ==> ダメよーダメダメ

また、基本構文は以下になっていて、最後に、finallyをつけると、例外処理に関係なく処理を実行できる

def func(a):
    try:      #通常の処理
           ・・・  
    except:   #例外発生時の処理
           ・・・  
    else:   #例外が発生しなかった場合の追加処理
           ・・・  
    finally:  #最後に、例外の有無にかかわらず、どちらでも必ず実行  
           ・・・  
(3)raiseによる意図的な例外

システムが自動で出す例外以外に、別の処理であっても例外としたい場合がある。
自分で例外を作成できる。
たとえば、以下の場合は、0で割っているので例外になり、「error= division by zero」と表示される。

a=0
try:    
    x = 10 / a
except ZeroDivisionError as abc:
    print('error=', abc) #==>error= division by zero
else:
  print('No error')

ここで、割る数(今回はa)が0.1以下でもZeroDivisionErrorを出したいとする。以下のように、raiseを使う。ただし、出力は本当のエラーとは異なり、変数に値が入らない。出力がNo errorになっていないので、elseの処理をしているのではなく、ZeroDivisionErrorの処理がなされている。

a=0.001
try:    
    x = 10 / a
    if a <0.1:
      raise ZeroDivisionError 
except ZeroDivisionError as abc:
    print('error=', abc) #==>error= 
else:
  print('No error') #==> error= 
(4)ユーザ定義例外クラス

・自分で例外(というかエラー)を作りたいというニーズもあるだろう。その場合は、raiseによってエラーの処理をさせればいい。
エラーも処理をさせるという関数(やクラス)なので、例外のクラスを作る。
・作り方というか、書き方は以下。()の中にExceptionと入れる

class Error(Exception):
    pass

または、こんな感じ

class Error(Exception):
    def __init__(self):
        pass
    def __str__(self):
        return "Error happened!"

5.JSON形式

(1)JSONについて

❶概要
json(JavaScript Object Notation)は、JavaScriptのオブジェクト表記であるが、Pythonなどでも広く使われている。
AWSの情報を参考にすると、例えば以下。
キーと値を、"とコロンで区切って表記する。

{"VpcId": "vpc-casxxx","InstanceTenancy": "default","State": "available"}

ただし、長くなると見づらいので、以下のように改行することが多い。

{
    "VpcId":"vpc-casxxx",
    "InstanceTenancy": "default",
    "State": "available"
}

❷少し複雑な事例
オブジェクトの中にさらにオブジェクトを入れる場合は → { }で入れる
配列を入れる場合は  → [ ]で入れる
AWSで見てみよう。

# aws ec2 describe-vpcs
{
    "Vpcs": [
        {
            "VpcId": "vpc-casxxx",
            "InstanceTenancy": "default",
            "CidrBlockAssociationSet": [
                {
                    "AssociationId": "vpc-cidr-asxxxx",
                    "CidrBlock": "172.31.0.0/16",
                    "CidrBlockState": {
                        "State": "associated"
                    }
                }
            ],
            "State": "available",
              ・・・・
        },
        {
            "VpcId": "vpc-0csxxx",
            "InstanceTenancy": "default",
            "Tags": [
(2)pythonでJSON

・import json でインポートする。
・JSON形式に変換することをエンコード、逆をデコードという。
・エンコードする場合とデコードする場合で以下の関数(メソッド)を使う。

方法 関数
エンコード json.dumps()
デコード json.loads()

dumps関数は、(といっても、よくわかっていないが)、単純な例は、'で囲っているのをjsonフォーマットの"に変換すること。とはいえ、数字やリスト[1,2,3]はそのままで、”で囲われることはない。

import json
x = {'name':'suzuki','age':23}
print(x) #==>{'name': 'suzuki', 'age': 23}
print(json.dumps(x)) #==> {"name": "suzuki", "age": 23}

6.正規表現

・re(regular expression:正規表現)を使う。たとえば、以下は、ZIPのフォーマットに該当するものを抜き出す。
・re.match(パターン, 文字列)とすることで、文字列の中からパターンと一致するものを探す。
・re.IGNORECASE:大文字小文字を区別しない
・re.compileで、正規表現のオブジェクトを事前に作成できる。

構文 解説
A|B AかBのどちらか
文字列などの後ろに付け、0または1回
() グループ化する
import re
address = "大阪市北区123-4567"
zip = re.search('[0-9]{3}-[0-9]{4}' , address)
print(zip) #==> <_sre.SRE_Match object; span=(5, 13), match='123-4567'>
print(zip.group()) #==> 123-4567

re.compile は、正規表現を事前に書いておける。↑のを書きなおすと、以下になる。

import re
address = "大阪市北区123-4567"
x=re.compile('[0-9]{3}-[0-9]{4}')
zip = x.search(address)
print(zip.group()) #==> 123-4567

7.Webページの処理

requestsを使うことで、Webページとの接続が簡単に行える。
❶やってみよう

import requests
url = 'https://example.com/'

x = requests.get(url)
print(x) #==> <Response [200]>
print(x.text) #==>ソースコードを取得して表示

以下に詳細な解説がある。
https://note.nkmk.me/python-requests-usage/

❷API連携
国立国会図書館のDBを利用する。
※Dos攻撃にならないか、著作権違反にならないかなど、法律に注意して利用する必要がある。

import requests
import urllib.parse

book = urllib.parse.quote('title="ネスぺの基礎力" AND from="2015"') # titleと、発行年度(指定した年以降)を指定
url = 'https://iss.ndl.go.jp/api/sru?operation=searchRetrieve&maximumRecords=10&query='+book
x = requests.get(url)
print(x.text) #結果を表示

■メモリ空間
Pythonでまメモリの領域を表示するにはidを使う。

>>> a=123
>>> id(a)
140709562806928

■副作用
副作用というと、薬の副作用のように、多少悪いイメージがある。
Pythonを含むプログラムの場合、副作用があるものとないものがある。
副作用がある場合、メソッドの副作用により、インスタンス変数の値が変化する。
以下に具体例がある。
https://python.ms/side-effect/#_1-%E5%89%AF%E4%BD%9C%E7%94%A8%E3%81%A8%E3%81%AF

■pycは、pythonのファイルでコンパイル済のもの

■対話環境
.python_history に履歴が入っている。

■pythonで仮想環境を作成
venvモジュールを使う

pytyon3 -m venv 名前

pyvenvを使う。またはvirtualenv?
pipなどをインストールするのが、その仮想環境内に限定されると思う。あとは、Pythonのバージョンを変えたりとか。
deactivateで環境を終わらせる

・reprlib
reprlib モジュールのreprによって、出力する文字を簡略化できる。

import reprlib
x=reprlib.repr('abdedf11111111111111111111ghijklm') ==> 'abdedf111111...111111ghijklm'

■docstring(ドックストリング)
・モジュールなどの冒頭に付与する解説文。「ドキュメント文字列」ともいわれる。
def func1()
""" ここに解説 """
・コメントと同じ使い方ができるが、pyhonプログラム的には、コメントは無視する。docstringはその関数などの説明文として意識するので、help(関数名)とすると、ドックストリングが表示される。
・空行も効果的に使う。

■ログ
・import logging で開始し、logging.basicConfigを用いて、ログレベルの変更や、ログフォーマットの変換を行う。
たとえば、以下

import logging
logging.basicConfig(filename='maillog.log', level=logging.DEBUG)

・Pythonのログレベル
優先度が高いものから順に以下。
CRITICAL、ERROR、WARNING、INFO、DEBUG

■IPython
対話型のシェルで、より優れたインタプリンタを提供する。タブ補完などが高機能。%によるマジックコマンドも実行できる。
IPytonは、Windowsのコマンドプロンプトからipythonコマンドで実行できる。
Jupyter NotebookもIPythonと呼んでもいいだろうし、イコールのように書いてあるサイトもある。
「pip install ipython」でインストール
対話モードはipythonコマンド
bpythonとして、ipythonの進化版?もある。
https://qiita.com/YumaInaura/items/1707b708c608e9f9a488

■アノテーション は
「 __annotations__ 」に辞書型で登録される。コメントと同じ役割。

■pip
・パッケージのアップデートは、pip install --upgrade
・アンインストールは、pip uninstall 複数パッケージを指定することも可能。 
・pip list でインストールされたパッケージの全リストを表示
・== でバージョンを指定
たとえば、以下のガントチャートを使う場合には、バージョンを4.9にする必要がある。
!pip install plotly==4.9.0

plotly.com

10.ショートカットキーなど

・コメントを一気に付与(または削除)するには、ctl + /
・インデントを一気にするには、選択してTab 戻すにはShift + Tab
・特定の文字を一気に選択する場合は、ctrl + shift + 右→
・同じ文字を一気に変換する場合、文字を選択してctrl+d で同じ文字を一気に選択

10.演習問題

(1)Pythonを使って、音声のサンプリング定理(標本化定理)を証明というか、やってみる。

省略というか、別のところに書いたはず。

(2)文章を分割し、登場した単語の数を調べるプログラムを作ろう
#文章をsentenceに入れる
sentence='I am a boy. My name is Jhoney. Because I am a boy, I like baseball.'
#空白単位でsentenceを区切り、wordに入れる→splitを使うとリストに入る。
word=sentence.split(' ')
print(word) #==>['I', 'am', 'a', 'boy.', 'My', 'name', 'is', 'Jhoney.', 'Because', 'I', 'am', 'a', 'boy,', 'I', 'like', 'baseball.']
#求めたい辞書をword_dicとして作成。辞書型で、キーが単語、値がその出現回数
word_dic = {}
for i in word:
    #すべて 小文字にする
    i=i.lower()
    #ドットを消す(置き換える)
    j=i.replace('.','') 
    #word_dicに単語がなかったら、valueを1として登録
    if j not in word_dic:
        word_dic[j]=1
    #word_dicに単語がある場合、valueを+1して更新
    else:
        word_dic[j] += 1
#結果の出力
print(word_dic) #==>{'i': 3, 'am': 2, 'a': 2, 'boy': 1, 'my': 1, 'name': 1, 'is': 1, 'jhoney': 1, 'because': 1, 'boy,': 1, 'like': 1, 'baseball': 1}
(3)素数を見つける

エラトステネスのふるい という方法で、素数を見つける。
まず、N+1の項目をもつリストsosuを作り、すべてTrue(素数)を入れる。
その後、j=2とし、2の倍数を素数から除外(=False)する。jを一つずつ増やし、j=3、j=4、・・・Nの平方根+1まで実施する。

import math
#N=100として、100までの素数を求める
N=100
#101個のTrueが入ったリストであるsosuを作る
sosu=[True]*(N+1)
#2の倍数、3の倍数、を素数から除外する。
for j in range(2,int(math.sqrt(N)+1)):
  【★if文を記載】
    for s in range(j*2,N+1,j): #最初がj*2というのが、イマイチだと思う。
        #sを素数から除外する
        sosu[s]=False
#ここはもっといい方法があると思うが、最後に素数のリストを作成する。
list=[]
for k in range(N+1):
  if sosu[k]==True:
    list.append(k)
print(list) #==>[0, 1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
(4)平均点からどれくらい離れているかを表示

100点満点の10人のスコアがある。平均点からどれくらい離れているかを表示する。

import numpy as np
#0~100点の間で、10人の点数の乱数を作る
x=np.random.randint(0,100,10)
print('10人の点数をnumpy.arrayで表現',x)
#平均を求める
avg=np.average(x)
print('平均点=',avg)
for i in x:
  print(i,':',end="")
  if i < avg:
    #intにしているのは、空欄を個数分だけ記載しているが、小数点ではダメなので、整数にしている
    print(' '*int(50-(avg-i)),end="")
    print('*'*int(avg-i),end="")
    print('|')
  else:
    print(' '*50,end="")
    print('|',end="")
    print('*'*int(i-avg))

結果は、こんな感じ

10人の点数をnumpy.arrayで表現 [70 50 97 28 32 13 34 61 62 26]
平均点= 47.3
70 :                                                  |**********************
50 :                                                  |**
97 :                                                  |*************************************************
28 :                              *******************|
32 :                                  ***************|
13 :               **********************************|
34 :                                    *************|
61 :                                                  |*************
62 :                                                  |**************
26 :                            *********************|