質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Slack

Slackは、Tiny Speckという企業からリリースされたコミュニケーションツールです。GoogleDriveやGitHubなど、さまざまな外部サービスと連携することができます。

Q&A

解決済

3回答

1069閲覧

python classをテンプレートとして他のクラスを作成する方法

nudesudesu

総合スコア8

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Slack

Slackは、Tiny Speckという企業からリリースされたコミュニケーションツールです。GoogleDriveやGitHubなど、さまざまな外部サービスと連携することができます。

0グッド

1クリップ

投稿2021/07/20 06:53

編集2021/07/20 06:54

python初学者の大学生です。
Slack APIを利用してSlackBotを作成しています。
下のようなテンプレートクラスに、引数を渡して新しいクラスを作成させることはできますか?
(関数にしたほうがいいよ、などその他に良い方法があったら教えてください。)

class Template: WELCOME_BLOCK = { "type": "section", "text": { "type": "mrkdwn", "text": ( "こんにちは" # <- ここに生成クラス特有のメッセージを入れたい。 ), } } DIVIDER_BLOCK = {"type": "divider"} def __init__(self, channel=None): self.channel = channel def get_message_payload(self): return { "blocks": [ self.WELCOME_BLOCK, self.DIVIDER_BLOCK, ], }

Template().get_message_payload()とすることで、
下のような簡単なJSONを出力することができました。

json

1{'blocks': [{'type': 'section', 'text': {'type': 'mrkdwn', 'text': 'こんにちは'}}, {'type': 'divider'}]}

これを新しいHelloClassを作って、Helloという文字列を引き渡すことで、上記こんにちはの部分をHelloに変えた新しいメッセージクラスを作りたいと思っています。
(Templateにmessageという引数を渡して、クラスではなく文字列で出力するべきという声が聞こえて来そうですが、実際に、各作成クラスごとに新しいBlockが追加されたり、並び順を変えたいので、これらは別でクラス出力したいと思っています。(よりよい方法があったら教えてください!)

どのようにしたら実現できますか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

実装を共有するという目的で継承を使うべきではないでしょう。(使ってはいけない、ぐらいまで言ってもいいかも)
継承は、インタフェースを共通にする目的で使うべきです。

質問のコードは「メッセージを組み立てる」という機能と「チャンネルを保有する」という機能が混じっています。
「メッセージを組み立てる」部分も、「メッセージの部品を定義する」という機能と、「部品となるメッセージを組み合わせる」という機能が混じっています。

このあたりを機能でクラスを分離すると、

python

1class Fragment: 2 def get_message(self): 3 raise NotImplemented 4 5 6class Greeting(Fragment): 7 def __init__(self): 8 self.message = { 9 "type": "section", 10 "text": { 11 "type": "mrkdwn", 12 "text": ( 13 "こんにちは" # <- ここに生成クラス特有のメッセージを入れたい。 14 ), 15 } 16 } 17 18 def get_message(self): 19 return self.message 20 21 22class Divider(Fragment): 23 def get_message(self): 24 return {"type": "divider"} 25 26 27class Template: 28 def __init__(self, contents, channel=None): 29 self.contents = contents # contents must be list of Fragment 30 self.channel = channel 31 32 def get_message_payload(self): 33 return { 34 "blocks": [c.get_message() for c in self.contents], 35 } 36 37 38greeting = Template([Greeting(), Divider()]) 39print(greeting.get_message_payload())

みたいになるかなと思います。


これだとGreetingDividerが抽象度が合ってません。

python

1class Fragment: 2 def get_message(self): 3 raise NotImplemented 4 5 6class Markdown(Fragment): 7 def __init__(self, text): 8 self.message = { 9 "type": "section", 10 "text": { 11 "type": "mrkdwn", 12 "text": text, 13 } 14 } 15 16 def get_message(self): 17 return self.message 18 19 20class Divider(Fragment): 21 def get_message(self): 22 return {"type": "divider"} 23 24 25class Template: 26 def __init__(self, contents, channel=None): 27 self.contents = contents # contents must be list of Fragment 28 self.channel = channel 29 30 def get_message_payload(self): 31 return { 32 "blocks": [c.get_message() for c in self.contents], 33 } 34 35 36greeting_markdown = Markdown('こんにちは') 37divider = Divider() 38 39greeting = Template([greeting_markdown, divider]) 40print(greeting.get_message_payload())

と変えていくでしょう。

基本1つのクラスが1つの部品になるようにしていきます。正解があるわけではないので一例として。

投稿2021/07/21 01:07

quickquip

総合スコア11038

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

quickquip

2021/07/21 01:10

組み立てるテンプレートとチャンネルを別にしたくなったら(同じテンプレートを別々のチャンネルで使い回したくなったら)Templateをまた分離していきます。
guest

0

クラスを作るのでなく、インスタンスを作るという話に聞こえます。

python

1class Greeting: 2 WELCOME_BLOCK = { 3 "type": "section", 4 "text": { 5 "type": "mrkdwn", 6 } 7 } 8 DIVIDER_BLOCK = {"type": "divider"} 9 10 def __init__(self, message="", channel=None): 11 self.message = message 12 self.channel = channel 13 14 def get_message_payload(self): 15 self.WELCOME_BLOCK["text"]["text"] = self.message 16 return { 17 "blocks": [ 18 self.WELCOME_BLOCK, 19 self.DIVIDER_BLOCK, 20 ], 21 } 22 23prit(Greeting("hello").get_message_payload())

投稿2021/07/20 09:50

TakaiY

総合スコア12765

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nudesudesu

2021/07/20 13:17

すみません、こちら、今回の取得内容としては問題ないかと思いますが、 例えば WELCOME_BLOCK DIVIDER_BLOCK WELCOME_BLOCK の順に組み合わせる場合に対応できないかと思います。 部品とメインのメソッドだけ継承するにはどうしたらよいでしょうか?
TakaiY

2021/07/20 14:32

新しいクラスにしたいのであれば、継承すればいいのでは? また、それらのブロックを固有の名前を持つ変数に入れるのでなく、リストに格納して、あるだけblocksの中に詰め込むようにすれば、動的に変更することもできますよ。
guest

0

init_subclassを使うと、こんな感じです。

python

1class Template: 2 WELCOME_BLOCK = { 3 "type": "section", 4 "text": { 5 "type": "mrkdwn", 6 "text": ( 7 "こんにちは" # <- ここに生成クラス特有のメッセージを入れたい。 8 ), 9 } 10 } 11 DIVIDER_BLOCK = {"type": "divider"} 12 def __init__(self, channel=None): 13 self.channel = channel 14 def get_message_payload(self): 15 return { 16 "blocks": [ 17 self.WELCOME_BLOCK, 18 self.DIVIDER_BLOCK, 19 ], 20 } 21 def __init_subclass__(cls, /, msg, **kwargs): 22 import copy 23 super().__init_subclass__(**kwargs) 24 cls.WELCOME_BLOCK = copy.deepcopy(cls.WELCOME_BLOCK) 25 cls.WELCOME_BLOCK['text']['text'] = msg 26 27class Hello(Template, msg='Hello'): 28 pass

実行結果

python

1>>> print(Template().get_message_payload()) 2{'blocks': [{'type': 'section', 'text': {'type': 'mrkdwn', 'text': 'こんにちは'}}, {'type': 'divider'}]} 3>>> print(Hello().get_message_payload()) 4{'blocks': [{'type': 'section', 'text': {'type': 'mrkdwn', 'text': 'Hello'}}, {'type': 'divider'}]}

投稿2021/07/21 00:47

ppaul

総合スコア24666

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問