【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