【デザインパターン勉強】adapterメソッド
ざっくり概要
adapterメソッドとはざっくり言うと既に 提供されているclassと既に必要な抽象classを結びつけてプログラムを作成する方法です。 ポイントは、仲介役classを設定(提供されているclassと必要な抽象class)することです。
登場メソッド
必要な抽象メソッド(抽象classに存在)
提供されているメソッド(提供されているclass)
本来であれば・・・
抽象classと提供されているclassのメソッドを同一化すれば問題ないです が、 今回は 所々の事情で 修正出来ないケースを想定しています。
コード
#python3.5.2 import abc import os import csv class Format: def __init__(self,content): self.__content = content def make_file_csv(self,file_name): f = open('{}.csv'.format(file_name),'w') f.write(self.__content) def make_file_txt(self,file_name): f = open('{}.txt'.format(file_name),'w') f.write(self.__content) class TextMake(metaclass=abc.ABCMeta): @abc.abstractmethod def make_csv(self): pass @abc.abstractmethod def make_txt(self): pass class TextMakeFormat(TextMake,Format): def __init__(self,content): super().__init__(content) def make_csv(self,file_name): self.make_file_csv(file_name) def make_txt(self,file_name): self.make_file_txt(file_name) if __name__ == '__main__': textobj = TextMakeFormat('おはようございます。\n今日も元気で頑張りましょう。') textobj.make_csv("csv_file") #TextMakeFormatを経由してcsvファイル作成 textobj.make_txt("txt_file") #TextMakeFormatを経由してtxtファイル作成
各クラスの概要
Format(提供されているclass)
具体的処理メソッド(csv txtファイル作成)が記述されています。
TextMake(必要な抽象クラス)
既に必要とされているケースであり、メソッド(≠Formatのメソッド)が記述されています。
TextMakeFormat(仲介役)
FormatとTextMakeクラスの仲介役をします。 具体的には以下の手順となります。
- TextMake(必要な抽象クラス)をオーバーライドしてメソッドを宣言
- オーバーライドしたメソッドにFormat(提供されているclass)のメソッドを記述 これにより、必要な抽象class→提供されているClassの仲介を果たします。
感想
理解不足もあるかもしれませんが、利用シーンがあまり思い浮かびませんでした。。
参考文献
【デザインパターン勉強】builderメソッド
ざっくり概要
builderメソッドを自分の言葉でいうと、
作成するメソッドの役割は同じだが、異なる結果を得るプログラムを何個も 作る際、有用なプログラム(パターン) といった感じです。
ここで重要な点は 作成するメソッドの役割は同じ ということです。
本記事で記載したコードは税計算を表示するプログラムです。
登場メソッド
- set_total(金額インプット)
- set_tax(税率インプット)
- message_tax(消費税を計算、出力)
コード
# python3.5.2 import abc class TaxCalcDirector(): def __init__(self, builder): self.__builder = builder def construct(self,total,tax): self.__builder.set_total(self,total) self.__builder.set_tax(self,tax) self.__builder.message_tax(self) class AbstractTaxCalcBuilder(metaclass=abc.ABCMeta): @abc.abstractmethod def set_total(self,total): pass @abc.abstractmethod def set_tax(self,rate): pass @abc.abstractmethod def message_tax(self,message): pass class ConsumptionTaxBuilder(AbstractTaxCalcBuilder): def __init__(self): self.rate = 0 self.total = 0 def set_total(self,total): self.total = total def set_tax(self,rate): self.rate = rate def message_tax(self): tax = self.total * self.rate message = " ".join(["あなたの払う税金は",str(tax),"円です"]) print(message) class DeductionTaxBuilder(AbstractTaxCalcBuilder): def __init__(self): self.rate = 0 self.total = 0 def set_total(self,total): self.total = total def set_tax(self,rate): self.rate = -1 * rate def message_tax(self): tax = self.total * self.rate message = " ".join(["あなたが還付される税金は",str(tax),"円です"]) print(message) def main(): # 支払う税金 tax = TaxCalcDirector(ConsumptionTaxBuilder) tax.construct(1000,0.3) #あなたの払う税金は 300.0 円です # 還付 tax = TaxCalcDirector(DeductionTaxBuilder) tax.construct(200,0.1) #あなたが還付される税金は -20.0 円です if __name__ == '__main__': main()
main()メソッドでは、行いたい作業(クラス名)をインスタンス化しています。
作業に応じて、
tax = TaxCalcDirector(クラス) #クラス→ ConsumptionTaxBuilderやDeductionTaxBuilder
とすることで、クラスの継承を変えて、税の還付金計算に変更することが出来ます。
つまり、具体的な作業を認識せずに処理を変えられます。
今回は消費税計算、税の還付金計算と処理を変えています。
各クラスの役割
AbstractTaxCalcBuilder(Builder)
インスタンスを作成する際に必要な作業(メソッド)を規定しています。 つまり、以下のメソッドとなります。
- 金額インプット set_total
- 税率インプット set_tax
- 消費税を計算、出力 message_tax
メソッドをオーバーライドし忘れを防ぐために抽象クラスとしています。 教科書では Builder と呼ばれますが、「現場監督」といったほうがイメージしやすい気がします。
ConsumptionTaxBuilder(ConcreteBuilder)
AbstractTaxCalcBuilderで定義されたメソッドを具体化しています。
教科書では ConcreteBuilder と呼ばれますが「現場作業員」といったほうがイメージしやすい気がします。
TaxCalcDirector(Director)
AbstractTaxCalcBuilderのメソッドを用いてインスタンスを生成しています。 また、インスタンス作成の際、ConsumptionTaxBuilder継承してインスタンス化しています。
必要な情報は builderのメソッドとConsumptionTaxBuilderというConcreteBuilder のクラス名のみです。
ここで、重要なのは以下の2点です。
- AbstractTaxCalcBuilder(Builder)のメソッドのみを使っていること
- 具体的なアウトプットを得る際はConcreteBuilderのクラス名を継承して実行
教科書では Directorと呼ばれて説明されています。監督する立場なのでイメージしやすいですね。
ここでわかることは アウトプットを変更する際、ConcreteBuilderクラス名を修正して実行すればいい
→つまり、クラス名だけで柔軟にアウトプットを変えることが出来るということです。
参考文献
【Pythonメモ】collectionsモジュール
# collectionsモジュール勉強 import collections #counterメソッドはカウント系メソッド c = collections.Counter() c['spam'] += 1 c[100] += 1 c[200] += 2 c[200] += 3 # Counter({200: 5, 'spam': 1, 100: 1}) print(type(c)) c2 = collections.Counter() c2['spam'] = 1 c2[200] = 1 print(c & c2) #Counter({200: 1, 'spam': 1}) print(c + c2) #Counter({200: 6, 'spam': 2, 100: 1}) # ChainMapはdict d1 ={'spam':1} d2 ={'ham':2} d = collections.ChainMap(d1,d2) print(d)
エクセルコピペ作業自動化(xls、xlsx)
エクセルをpythonで扱う
仕事していると、エクセルで延々と だるい コピペ作業とかってありませんか。
先日、pythonを使ってコピペ作業を自動化しました。
その時、用いたpython用ライブラリ、使用方法を紹介します。
※今回は読み込みにしぼって説明
ライブラリ
調査したところ、それぞれ対応しているライブラリは以下の通りのようです。
※ xlsと xlsx 両方読み込みを行なうライブラリ、見当たりませんでした。
※ 諸事情によりxls形式を扱う人は多いのではないでしょうか。xlsxはexcel2007以降
読み込み方法
xlsとxlsx形式を扱うライブラリですが、 手順は以下に記載したとおりほとんど同じです。
- 1.ワークシートを指定
- 2.指定したワークシートからブック名一覧を取得
- 3.ブックを指定
- 4.指定したブックの値や入力された範囲を取得
あとはメソッド名を変えてあげれば対応OKです。
読み込んだファイル
今回は以下のファイル(xlsとxlsx形式)を読み込みました。 ファイル名:xls_test.xls
プログラム例
実行環境:python 3.5.2
from abc import ABCMeta, abstractmethod import re import glob import openpyxl import xlrd class ExcelTemplate(metaclass=ABCMeta): # デコレータ(abstractmethod)をつけると、サブクラスが抽象メソッドをオーバーライドしないとエラーとなる @abstractmethod def read_sheet(): pass def get_filename(self,file): print(file + "の読み取りを行います。") class XlsRead(ExcelTemplate): # xlsファイル読み込み def read_sheet(self,worksheet): # ワークシートを指定 book = xlrd.open_workbook(worksheet) # シート名を取得 戻り値はリスト print(book.sheet_names()) sheet_name = book.sheet_names()[0] # 一番目のシートを指定 sheet_1 = book.sheet_by_name(sheet_name) print("値が入力されている 行列数:",sheet_1.ncols,sheet_1.nrows) print("1行目:1列目の値は:",sheet_1.cell(0, 0).value) class XxlsRead(ExcelTemplate): # xlsxファイル読み込み def read_sheet(self,worksheet): # ワークシートを指定 book = openpyxl.load_workbook(worksheet) # シート名表示 戻り値はリスト print(book.get_sheet_names()) # 一番初めのシート名を取得 sheet_name = book.get_sheet_names()[0] # 一番目のシートを指定 sheet_1 = book[sheet_name] print("値が入力されている 行列数:",sheet_1.max_column,sheet_1.max_row) print("2行目:1列目の値は:",sheet_1.cell(row=2,column=1).value) def main(): xls_instance = XlsRead() xxls_instance = XxlsRead() worksheets = glob.glob(パスを指定) # 取得したエクセルリストに対して # xlsファイル、xlsmファイルに応じて切り替え for worksheet in worksheets: if re.match(r".+\.xls$",worksheet): xls_instance.get_filename(worksheet) xls_instance.read_sheet(worksheet) print("------------") elif re.match(r".+\.xlsx$",worksheet): xxls_instance.get_filename(worksheet) xxls_instance.read_sheet(worksheet) print("------------") else: pass if __name__ == '__main__': main()
$ python template_xls.py xls_test.xlsの読み取りを行います。 ['Sheet1'] 値が入力されている 行列数: 1 10 1行目:1列目の値は: xls_test1 ------------ xlsx_test.xlsxの読み取りを行います。 ['Sheet1'] 値が入力されている 行列数: 1 10 2行目:1列目の値は: xlsx_test2 ------------
参考文献
【Pythonメモ】 後置 if
後置 if
最近、rubyみたいに後置if無いかなと ぐぐってみました。
以下はメモ
# testはtrueの際の出力 if True なら test = "true" test = "true" if True else "false" print(test) #true # Falseになった際、elseの式 test2 = "false" if False else "false" print(test2) #false # rubyみたいにかけない。 elseはつけないといけない test3 = "true" if True print(test3) #error になる
Slack BOT + Backlog APIでタスク管理する。
仕事の管理ツール
現在、仕事でプロジェクト管理は backlog をコミュニケーションツールは slack を使っています。 会議はあまりないので、仕事の打ち合わせはslack上が多いです!
slackとbacklogを使う際の問題点・・・
最近になってようやく(汗)、slackとbacklogに慣れてきたのですが、 両方使ってきて自分なりの不満点も見えてきました。
- backlogにあがった課題URLのリンクをSLACKにいちいちコピペするのがだるい。
- backlogページにログインしたくない (仕事で用いるページ、アプリは少なくしたい→slack、エディタに集中)
上記の課題点を克服すべく、Slack Botを作成してみました!
SLACK BOT環境
python version 主に使用したモジュール
モジュール slackbotについて
slackbotを作成する場合、RealTimeMessaging APIを 用いる必要があります。(APIはWebSocketベース)
こちらのモジュールを用いると
Websocket周りの通信をうまいことラップしてくれます。
モジュールインストールは pip install slackbot
で大丈夫です。
setup(hello world的なヤツ)
最低限の実行に必要な手順は以下
1. SLACBOT API KEYの取得
2. 実行ファイル、環境設定ファイルの指定となります。
※ 1についてはググると色々とあるので、割愛します!
実行ファイル、環境設定ファイルの指定
実行フォルダ直下に
API_TOKEN = <slack_api_key> # デフォルトの返信 default_reply = "hello!" #カスタマイズプログラム読み込み指定 PLUGINS = ['plugins.reply_backlog_task']
from slackbot.bot import Bot def main(): bot = Bot() bot.run() if __name__ == "__main__": main()
と記述し、run.pyを実行すると、botが起動します。
カスタマイズ
次に特定のフレーズに反応した際の処理を作成します。
slackbot_settings.py
に PLUGINSというで指定したファイル(./plugins/reply_backlog_task.py)
に独自の処理を追加することが出来ます。
今回は、以下の処理をプログラムすることにしました。
処理手順
1. pj:プロジェクト名とスラックでメンション(slack)
2. pj:に続くプロジェクト名をキャプチャする。(python)
3. キャプチャした単語をtrelloAPIでを呼び出して未完了タスクを呼び出す。(python)
4. backlog担当PJ未完了タスクを表示(slack)
プログラム
from slackbot.bot import respond_to from slackbot.bot import listen_to import json import re import requests # backlogクエリパラメータ dict返し def issue_data(projectId): issue_data = { 'parentChild':0, 'count':100, #取得上限数 'projectId[]':projectId, 'statusId[]': [1,2],#1→未対応、2→処理中 } return issue_data # backlog api convert pj_name → pj_id def convert_project_num(project_name): dict = { "pj1":11111, "pj2":22222 } return dict[project_name] # backlog api request def backlog_get_issues(projectId): url = HOST + '/api/v2/issues?apiKey=' + <backlog_api_key> r = requests.get(url,issue_data(projectId)) return r.json() # デコレータの引数にマッチするキーワードを指定し、マッチした後続の関数を実行 # デコレータの引数は正規表現も可能 # 正規表現パターンでマッチした、キャプチャは第二引数に引き渡される @respond_to(r'pj:(.+)[\s ]?$') def mention_func(message,project): texts = backlog_get_issues(convert_project_num(project)) for t in texts: text = "【未対応案件リスト】" text += "\n" text += "担当者:" text += str(t['assignee']['name']) text += "\n" text += str(t['description']) message.reply(text) # slackに返信 time.sleep(1)
ごちゃごちゃしてダサいですが、動きました(^^)
これからもカスタマイズしていって、便利なslack仕事アシスタントbotを作っていきたいです!