【Python】flaskのsessionについて…
session内に「key」というキーと「value」(string)という値を作りたい場合
session['key'] = value
session内「key」というキーから値を取り出したい場合
以下のどちらでもよいが…
variable = session['key']
variable = session.get('key')
session.get('key')のほうがいいみたい。
session['key']だとpytestの時、よくわからんエラー吐いたので…
【雑記】MySQL8.0のmy.iniを更新したらmysqlサービスが動かなくなったらしい
こんばんは、葛の葉です。
先日、友達に電話越しでMySQLについてを教えていたところ、my.iniをいじる必要が出てきました。そのmy.iniの一部を変更したらサービスを開始できませんでしたと動かなくなりました。これは想定内だったのですが、変更した値を元に戻して保存をかけたら、これまたサービスを開始できませんでしたと表示され動かなくなりました。
OS
原因はmy.iniファイルの文字コード
my.iniはANSIという文字コードで保存されている必要があるみたい。ただ、メモ帳を使って一度設定を変更して保存した時、文字コードがutf-8になったようだ。そこでANSIに変更してしてから起動してみたが失敗した。今度はutf-8で保存されたmy.iniを一度Unicodeに変更して保存し、それから再びANSIで保存をしたところ、mysqlは動いた。
ANSIってそもそもなん?
よくわからんが、アメリカの基準らしい。
だが、次の記事をみると…ナンノコッチャ
こちらのページを拝見すると…
Microsoftコードページ932だとか、その辺りというざっくばらんな謎の文字コードという認識をもつこととなった。
一度Unicodeにするという過程
どうしてUnicodeにするという過程を得る必要があるのか、コレガワカラナイ。
教えると勉強になるねってお話でした
みんなも誰かに教える立場になってみましょう〜
【Python】pandasを使ってみる
こんばんは、葛の葉です。
ここ最近はPyQというサービスを使ってPythonの勉強をしています。環境構築とかがなくても、Webブラウザ上ですぐに学べるのがいいところだと思います。月3000円とネットフリックスと言った娯楽サービスの月額料金と比べるとお高い感じがしますが、参考書1冊分だと思えば安い方だと思います。私はどちらかというと手を動かして覚えたい方ですので、こういったコードを書きながら学べるサービスは非常に良いと思いました。
さて、私は現在、データ分析のコースをプレイしております。そのうち、Pandasを使った勉強をしております。勉強したことを少し載せます。
こういうCSVを作る
kattakiroku.csv
kiroku_id,date 1,20180101 2,20190208 3,20190515 4,20190623 5,20191111
sale.csv
shohin_id,name,price 1,カレールー,100 2,にんじん,210 3,じゃがいも,100 4,メンマ,580 5,牛肉,90 6,玉ねぎ,130
nanikatta.csv
kiroku_id,shohin_id 1,1 1,3 1,5 2,2 2,4 2,5 2,6 3,1 3,2 4,3 4,4 4,4 5,1 5,6
pandas.read_csvでcsvからデータを取得する
pandasを使って上記のCSVを読み込むと以下のようになります。
import pandas as pd
sale = pd.read_csv('sale.csv')
kattakiroku = pd.read_csv('kattakiroku.csv')
nanikatta = pd.read_csv('nanikatta.csv')
import pandas as pdについて、pdとはpandasが推奨する省略形式のようです。
pd.read_csv(CSV_FILE)とすることでCSVの中身をpandasのDataFrameというオブジェクトとして読み込むことが出来ます。
DataFrameは2次元データを管理するオブジェクトです。1次元データの場合はSeriesというオブジェクトで管理されます。
pandas.mergeで結合する
keyを使ってデータを結合することができます。結合の対象となるものは同じカラム名があるときの場合のようです。on引数でkeyを設定することも出来ます。
merged_df = pd.merge(nanitabeta, sale)
print(merged_df)
=>
kiroku_id shohin_id name price
0 1 1 カレールー 100
1 3 1 カレールー 100
2 5 1 カレールー 100
3 1 3 じゃがいも 100
4 4 3 じゃがいも 100
5 1 5 牛肉 90
6 2 5 牛肉 90
7 2 2 にんじん 210
8 3 2 にんじん 210
9 2 4 メンマ 580
10 4 4 メンマ 580
11 4 4 メンマ 580
12 2 6 玉ねぎ 130
13 5 6 玉ねぎ 130
カラムに対し1レコードがもっている要素の数が多いように見受けられます。これはPandasがもっているindexというものになります。下記のレコードの一番左の0がindexです。indexは好きに設定することも出来ます。
kiroku_id shohin_id name price 0 1 1 カレールー 100
DataFrame.queryでフィルタリング
kiroku_idが1のデータを取り出すようにフィルタリングします。pandas.queryを使うことで、直感的に操作できます。
merged_df_1 = merged_df.query('kiroku_id == 1')
merged_df_1_price = merged_df_1.sum()['price']
print(merged_df_1_price)
=>
290
<class 'int'>
merged_df.query('kiroku_id == 1')のようにDataFrame.query('QUERY文')を書くとフィルタリングした結果が返されます。
print(merged_df.query('price >= 200'))
=>
kiroku_id shohin_id name price
7 2 2 にんじん 210
8 3 2 にんじん 210
9 2 4 メンマ 580
10 4 4 メンマ 580
11 4 4 メンマ 580
print(merged_df.query('price >= 580 | price <= 100'))
=>
kiroku_id shohin_id name price
0 1 1 カレールー 100
1 3 1 カレールー 100
2 5 1 カレールー 100
3 1 3 じゃがいも 100
4 4 3 じゃがいも 100
5 1 5 牛肉 90
6 2 5 牛肉 90
9 2 4 メンマ 580
10 4 4 メンマ 580
11 4 4 メンマ 580
print(merged_df.query('name == "牛肉"'))
=>
kiroku_id shohin_id name price
5 1 5 牛肉 90
6 2 5 牛肉 90
もっと出来ることありそう
pandasを触っててやりやすいと思うのは直感的に操作できることだと思いました。mergeもqueryも直感的でわかりやすいです。
【Python】1年近くプログラマーやってFizzBuzzの作り方が変わったのさ
こんばんは、葛の葉です。
以前までの作り方
def fizuubuzz(num):
if num % 15 == 0:
return 'FizzBuzz!'
elif num % 3 == 0:
return 'Fizz!'
elif num % 5 == 0:
return 'Buzz!'
else:
return str(num)
これからの作り方
ディレクトリを作成する。
├── /app └── /test
このようにテストと本番を別ける。
testアプリケーションを作成する。
pytestで初期実行するconftest.pyを以下のように作成する。
# conftest.py
import os
import sys
sys.path.append(os.path.abspath(os.path.dirname(
os.path.abspath(__file__)) + '/../app/'))
これは、テストを実行するときのディレクトリの目線をappにするものです。
import等、ディレクトリを読み込むときはappディレクトリがスタートになります。
カレントディレクトリがappになるといった感じです。
├── /app
└── /test
└── conftest.py
列挙型で定数を作る
pythonには列挙型であるenumというものがあります。これの整数列挙型であるIntEnumというものを使用します。
app/Numbers.pyというpythonプログラム作成し、以下のようにします。
# Numbers.py
from enum import IntEnum
class Numbers(IntEnum):
FIZZ = 3
BUZZ = 5
FIZZBUZZ = FIZZ * BUZZ
これの説明はtest_Numbers.pyというテストプログラムを作成します。
# test_Numbers.py
from Numbers import Numbers
def test_Numbers():
assert 3 == Numbers.FIZZ
assert 5 == Numbers.BUZZ
assert 15 == Numbers.FIZZBUZZ
testディレクトリをカレントディレクトリにしてから、pytestと実行すれば1 passed in 0.** secondsと表示されるはずです。
======================== test session starts ========================= platform linux -- Python 3.6.6, pytest-3.8.1, py-1.6.0, pluggy-0.7.1 rootdir: /home/kuzunoha/sand_box/test, inifile: plugins: pylama-7.6.6 collected 1 item test/test_Numbers.py . [100%] ====================== 1 passed in 0.02 seconds ======================
Numbers.FIZZは整数3とアサート出来ます。
Numbers.BUZZは整数5とアサート出来ます。
Numbers.FIZZBUZZは整数15とアサート出来ます。
これらNumbersは定数のように扱うようにします。
├── /app
│ └── Numbers.py
└── /test
├── conftest.py
└── test_Numbers.py
FizzBuzzを作る。
まずは空のapp/FizzBuzz.pyと空のtest/test_FizzBuzz.pyを作成します。
├── /app
│ ├── FizzBuzz.py
│ └── Numbers.py
└── /test
├── conftest.py
├── test_FizzBuzz.py
└── test_Numbers.py
そうしてFizzBuzz.pyを作成します。
# FizzBuzz.py
from Numbers import Numbers
class FizzBuzz(object):
def checker(self, insert_number):
return 'Fizz!'
test_FizzBuzz.pyを作成します。
# test_FizzBuzz.py
import pytest
from FizzBuzz import FizzBuzz
@pytest.fixture()
def fizz_buzz():
# インスタンスを作成
fizz_buzz = FizzBuzz()
return fizz_buzz
def test_checker(fizz_buzz):
assert 'Fizz!' == fizz_buzz.checker(3)
pytest test_checker.pyと実行してパスすればしっかりインポートが成功しています。さて、ここまで作ってようやく、FizzBuzz.pyの実装をいろいろ考えられます。今回はFizzBuzzクラスのcheckerという関数から文字列を返してもらえばいいように考えます。
def test_checker(fizz_buzz):
assert 'Fizz!' == fizz_buzz.checker(3)
assert '2' == fizz_buzz.checker(2) # 追加
今の状態ではテストは通りません。テストを通すようにします。
# FizzBuzz.py
from Numbers import Numbers
class FizzBuzz(object):
def checker(self, insert_number: int) -> str:
if insert_number % Numbers.FIZZBUZZ == 0:
return 'FizzBuzz!'
elif insert_number % Numbers.FIZZ == 0:
return 'Fizz!'
elif insert_number % Numbers.BUZZ == 0:
return 'Buzz!'
else:
return str(insert_number)
pytestを行う
===================== test session starts ====================== platform linux -- Python 3.6.6, pytest-3.8.1, py-1.6.0, pluggy-0.7.1 rootdir: /home/kuzunoha/sand_box/test, inifile: plugins: pylama-7.6.6 collected 2 items test/test_FizzBuzz.py . [ 50%] test/test_Numbers.py . [100%] =================== 2 passed in 0.03 seconds ===================
テストする項目を増やしてみる。
# test_FizzBuzz.py
import pytest
from FizzBuzz import FizzBuzz
@pytest.fixture()
def fizz_buzz():
# インスタンスを作成
fizz_buzz = FizzBuzz()
return fizz_buzz
def test_checker(fizz_buzz):
assert 'Fizz!' == fizz_buzz.checker(3)
assert '2' == fizz_buzz.checker(2)
assert 'Buzz!' == fizz_buzz.checker(5)
assert 'FizzBuzz!' == fizz_buzz.checker(15)
assert 'FizzBuzz!' == fizz_buzz.checker(30)
======================== test session starts ========================= platform linux -- Python 3.6.6, pytest-3.8.1, py-1.6.0, pluggy-0.7.1 rootdir: /home/kuzunoha/sand_box/test, inifile: plugins: pylama-7.6.6 collected 2 items test/test_FizzBuzz.py . [ 50%] test/test_Numbers.py . [100%] ====================== 2 passed in 0.03 seconds ======================
もっともっと勉強が必要
がんばらないと
【Python】pycryptomodexのインストール
環境
Windows 10 home Python3.6.5
Build Tools for Visual Studio 2017インストール
画面下部にいってTools for Visual Studio 2017を押下してBuild Tools for Visual Studio 2017をダウンロード + インストール
pycryptoのpipインストール
pycrypto
pip install pycryptoでインストールに失敗する
import Cryptoで出来ない
pycryptomode
pip install pycryptomodeでインストールできる
import Cryptoで出来ない
pycryptomodex
pip install pycryptomodexでインストールできる
import Cryptoで出来ない
import Cryptodomeで動いた!
pycryptoは死んでいる
tl;dr: PyCrypto is dead. Switch to PyCryptodome (GitHub: https://github.com/Legrandin/pycryptodome PyPi: https://pypi.python.org/pypi/pycryptodome). Do not report any new bugs here!
【DockerCompose】Volumesをうまく扱う
こんばんは、葛の葉です。
前略、MySQLのデータを永続化しようと、DockerComposeのvolumesの箇所で"自分のディレクトリ:/var/lib/mysql"と記述したらMySQLがOSがどったらこったらとエラーを吐いて動きませんでした。
PCはWindows10Homeです。Docker上でMySQLを動かすと、動かしているときはLinuxだけど、保存先がwinになってる。MySQLコンテナは困惑して轟沈した、というわけのようです。
そもそもデータを永続化出来ればいいのであって、windowsにマウントする必要はないです。コンテナを落としても、新たにコンテナが立ち上がった時に同じデータを引き継いでくれればそれで良いです。
というわけで、コンテナのデータをDocker内のvolumeにマウントさせるということをやっていこうかなぁと思います。
とても参考になったサイト
Version
Docker Toolboxを使用しています。
# docker version Client: Version: 18.03.0-ce API version: 1.37 Go version: go1.9.4 Git commit: 0520e24302 Built: Fri Mar 23 08:31:36 2018 OS/Arch: windows/amd64 Experimental: false Orchestrator: swarm Server: Docker Engine - Community Engine: Version: 18.09.2 API version: 1.39 (minimum version 1.12) Go version: go1.10.6 Git commit: 6247962 Built: Sun Feb 10 04:20:28 2019 OS/Arch: linux/amd64 Experimental: false # docker-compose version docker-compose version 1.20.1, build 5d8c71b2 docker-py version: 3.1.4 CPython version: 3.6.4 OpenSSL version: OpenSSL 1.0.2k 26 Jan 2017
docker-compose.ymlではこんな感じ。
今回はMySQLとRedisもやってみた。
version: "3"
services:
mysql-svc:
image: mysql:5.7.25
environment:
MYSQL_DATABASE: db
MYSQL_ROOT_PASSWORD: secret
TZ: "Asia/Tokyo"
volumes:
- "mysql_data:/var/lib/mysql"
redis-svc:
image: redis:5.0.3
environment:
TZ: "Asia/Tokyo"
volumes:
- "redis_data:/data"
volumes:
mysql_data:
redis_data:
servicesと同じレベルにvolumesというものが書かれています。これはDockerComposeを通じてvolumeというものを作成します。
volumeの機能自体はDockerComposeのものではなくDockerの機能です。また、複数のオプションが存在しています。色々と調べてみてくださいな。
docker-compose up -dとすれば以下のようになります。
$ docker-compose up -d Creating network "docker_test_default" with the default driver Creating volume "docker_test_mysql_data" with default driver Creating volume "docker_test_redis_data" with default driver Creating docker_test_mysql-svc_1 ... done Creating docker_test_redis-svc_1 ... done
docker_testっていうディレクトリ上で起動しているのでプレフィックスがこうなってます。
MySQLにデータを入れる
mysql-svcサービスでmysqlクライアントを起動してみます。
docker-compose exec mysql-svc mysql -p
パスワードはsecretです。
Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 2 Server version: 5.7.25 MySQL Community Server (GPL) Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>
use db;としてdbを移動し、適当にhogehogeテーブルでもつくり、適当に値を入れます。ちなみになんでdbっていうデータベースが存在しているかというと、Dockerのmysqlイメージがコンテナを生成するときに、そのコンテナがMYSQL_DATABASEという環境変数の値の名前のデータベースを作成するからです。
CREATE TABLE hogehoge (id int, name varchar(40), price int); INSERT INTO hogehoge VALUES(1, "LION", 200); INSERT INTO hogehoge VALUES(2, "BAER", 180);
SELECT * FROM hogehoge;とすればテーブルが表示されます。
+------+------+-------+ | id | name | price | +------+------+-------+ | 1 | LION | 200 | | 2 | BAER | 180 | +------+------+-------+ 2 rows in set (0.00 sec)
次回コンテナ起動時にこのデータを見ることが出来ればよいわけですね。
MySQLのコンテナを再起動してデータを確認する
docker-compose downとして、コンテナが落ちることを確認します。
$ docker-compose down Stopping docker_test_mysql-svc_1 ... done Stopping docker_test_redis-svc_1 ... done Removing docker_test_mysql-svc_1 ... done Removing docker_test_redis-svc_1 ... done Removing network docker_test_default
volumeが削除されていないという点をよくみておきましょう。そうしましたらもう一度立ち上げます。
$ docker-compose up -d Creating network "docker_test_default" with the default driver Creating docker_test_mysql-svc_1 ... done Creating docker_test_redis-svc_1 ... done
前回と比べてvolumeが作成されていない点をよくみておきましょう。
$ docker-compose exec mysql-svc mysql -p Enter password: mysql> use db; Database changed mysql> select * from hogehoge; +------+------+-------+ | id | name | price | +------+------+-------+ | 1 | LION | 200 | | 2 | BAER | 180 | +------+------+-------+ 2 rows in set (0.00 sec)
出ましたね。ちなみにRedisでも同じように確認することが出来ました。
お片付け
docker-compose downしてもvolumeが消えませんでした。実は次のコマンドを打つことでvolumeも一緒に削除することが出来ます。
docker-compose down -v
$ docker-compose down -v Stopping docker_test_mysql-svc_1 ... done Stopping docker_test_redis-svc_1 ... done Removing docker_test_mysql-svc_1 ... done Removing docker_test_redis-svc_1 ... done Removing network docker_test_default Removing volume docker_test_mysql_data Removing volume docker_test_redis_data
【Python】configparserを使って.iniファイルから設定を呼び出そう
公式ドキュメントはこちら
環境
python 3.6.6
iniファイルを書こう
config.ini
[load_type] type = csv [setting] csv_file_path = test.csv
pythonの準備
import configparser
標準モジュールのconfigparserをimportする
config_file = configparser.ConfigParser()
インスタンスを作成する
config_file.read('./config.ini')
iniファイルはこのようにパスを指定してあげる。
iniファイルを読み込む
print(config_file.get('load_type', 'type'))
とすると
'csv'
が返ってきます。
これはconfig.iniの
[load_type] type = csv
を読み込んでいるからです。
なお、config_file['load_type']['type']として取得するケースも見受けられるけど、python3.7以上からみたいです。
iniファイルに環境変数を入れる
[load_type] type = mysql [setting] host = %(MYSQL_IPADDR)s
環境変数を使うなら%(環境変数名)sとする必要がある。
%(環境変数名)s "sまで必要"
python側ではconfigparserのインスタンス作成時にos.environを引数に入れる。
import configparser import os config_file = configparser.ConfigParser(os.environ)
そうして、以下のように呼ぶ
config_file.read('./config.ini')
print(config_file.get('setting', 'host'))
実行してみると
root@:/var/sandbox# export MYSQL_IPADDR=127.0.0.1 root@:/var/sandbox# echo $MYSQL_IPADDR 127.0.0.1 root@:/var/sandbox# python conf_test.py 127.0.0.1