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

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

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

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

4回答

11014閲覧

pythonでメソッドを連続で呼び出すには?→【メソッドチェーン(&アトリビュートを書き換えない方法)】

退会済みユーザー

退会済みユーザー

総合スコア0

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

2グッド

0クリップ

投稿2018/02/17 23:14

編集2018/02/18 06:29

やりたいこと

python3で自作のクラスを作っているのですが、メソッドを連続で呼び出すということができないかと思って悩んでいます。
追記→「メソッドチェーン」です。

やりたいのは、
・データ加工1→データ加工2
を、
objX.methodA().methodB()
みたいに連続しておこなうことです。

下のコードは簡単なサンプルとして2パターン作ったものですが、両方エラーとなっています。期待するのは <p><b>text</b></p>といった出力です。

初心者のため、そもそもクラスの理解がきちんとできていないような気がします・・・
どうすればよいのか、あるいはそもそもできないのか。
ご指導くださればありがたいです。

サンプルとエラー

【パターン1(アトリビュートを書き換える)】

python

1class HtmlTag(): 2 value="" 3 def __init__(self,text): 4 self.value = text 5 def p(self): 6 self.value = "<p>{}</p>".format(self.value) 7 def b(self): 8 self.value = "<b>{}</b>".format(self.value) 9 10H=HtmlTag("hello") 11H.b().p() 12H.value 13 14

###【パターン1:エラー】

AttributeError Traceback (most recent call last) <ipython-input-44-a148c13084d1> in <module>() 10 H=HtmlTag("hello") 11 H.p() ---> 12 H.b().p() 13 H.value AttributeError: 'NoneType' object has no attribute 'p'

###【パターン2(リターンさせる)】

python

1class HtmlTag(): 2 value="" 3 def __init__(self,text): 4 self.value = text 5 def p(self): 6 return "<p>{}</p>".format(self.value) 7 def b(self): 8 return "<b>{}</b>".format(self.value) 9 10H=HtmlTag("hello") 11H.b().p() 12

###【パターン2:エラー】

AttributeError Traceback (most recent call last) <ipython-input-1-f8bbaaa72279> in <module>() 9 10 H=HtmlTag("hello") ---> 11 H.b().p() 12 H.value AttributeError: 'str' object has no attribute 'p'

##回答をいただいて追加の疑問【追記→自分自身のアトリビュートを書き換えないで、メソッドチェーンを実現する】

たとえばstr型ですと、

test=" abc " print(test.strip().title()) #Abc print(test) # abc

という風になり、自分自身のアトリビュートを書き換えないで、
メソッドチェーンが可能になっていると思います。
これはどのようにしたら実現できるでしょうか。

自分なりに考えたところでは、

class HtmlTag(): def __init__(self,text): self._value = text self._temp= text def p(self): self._temp = "<p>{}</p>".format(self._temp) return self def b(self): self._temp = "<b>{}</b>".format(self._temp) return self def __str__(self): return self._value H=HtmlTag("hello") print(H.b().p()._temp) #<p><b>hello</b></p> print(H._value) #hello

という具合にできないわけではないのですが、
前記のstr型の例だと、_tempみたいな変な指定はありません。

この点もう少しスマートなやり方があるような気がして、よければお教えください。

SatoshiMashino👍を押しています

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2018/02/18 04:40

次回以降、もし質問する機会があればでいいのですが、最初に聞いた質問が解決されたら一度その質問を閉じるようにしてください。
退会済みユーザー

退会済みユーザー

2018/02/18 04:41

追加の質問の時にこのスレッドへに引用をつけてくださるとなおありがたいです。
退会済みユーザー

退会済みユーザー

2018/02/18 06:21 編集

了解いたしました! 勝手が分からずすみません 。 丁寧に教えていただきありがとうございました。
退会済みユーザー

退会済みユーザー

2018/02/18 06:32

いえいえ、無事目的とする回答にたどり着けてよかったです(^^)
guest

回答4

0

メソッドチェーンを使いたいなら、自分自身を返せばいいかと思います。

Python

1class HtmlTag: 2 def __init__(self, text): 3 self._value = text 4 5 def p(self): 6 self._value = "<p>{}</p>".format(self._value) 7 return self 8 9 def b(self): 10 self._value = "<b>{}</b>".format(self._value) 11 return self 12 13 def __str__(self): 14 return self._value 15 16 17h = HtmlTag("hello") 18h.b().p() 19print(h) # <p><b>hello</b></p>

投稿2018/02/18 00:25

編集2018/02/18 00:36
LouiS0616

総合スコア35658

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

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

退会済みユーザー

退会済みユーザー

2018/02/18 03:59 編集

ありがとうございます! selfをリターンするとのこと、よくわかりました。 また、書いていただいた__str__を知り、Customizing Objectsというものも調べてみて、なんとなくは理解できました。 (_value というのはプライベート変数を作るということですね) 更によければ教えていただきたいのですが、 →(同じ内容を質問本文に追記しました) たとえばstr型ですと、 test=" abc " print(test.strip().title()) #Abc print(test) # abc という風になり、自分自身のアトリビュートを書き換えないで、 メソッドチェーンが可能になっていると思います。 これはどのようにしたら実現できるでしょうか。 自分なりに考えたところでは、 class HtmlTag(): def __init__(self,text): self._value = text self._temp= text def p(self): self._temp = "<p>{}</p>".format(self._temp) return self def b(self): self._temp = "<b>{}</b>".format(self._temp) return self def __str__(self): return self._value H=HtmlTag("hello") print(H.b().p()._temp) #<p><b>hello</b></p> print(H._value) #hello という具合にできないわけではないのですが、 前記のstr型の例だと、_tempみたいな変な指定はありません。 この点もう少しスマートなやり方があるような気がして、よければお教えください。
guest

0

各methodでselfを返せばやりたいことはできそうですよ。

python

1class HtmlTag(): 2 value="" 3 def __init__(self,text): 4 self.value = text 5 def p(self): 6 self.value = "<p>{}</p>".format(self.value) 7 return self 8 def b(self): 9 self.value = "<b>{}</b>".format(self.value) 10 return self

投稿2018/02/18 00:26

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

退会済みユーザー

退会済みユーザー

2018/02/18 00:27

一分遅かったorz
退会済みユーザー

退会済みユーザー

2018/02/18 03:52 編集

ありがとうございます! ひとことで書いていただいてよく分かりました。
guest

0

ベストアンサー

自分自身のアトリビュートを書き換えないで、

メソッドチェーンが可能になっていると思います。
これはどのようにしたら実現できるでしょうか。

メソッドにて自身の値を変更するのではなく、新しいインスタンスを返せばいいです。

class HtmlTag(): def __init__(self,text): self.value = text def p(self): return HtmlTag("<p>{}</p>".format(self.value)) def b(self): return HtmlTag("<b>{}</b>".format(self.value)) H=HtmlTag("hello") print(H.b().p().value) # => <p><b>hello</b></p> print(H.value) # => hello

投稿2018/02/18 04:18

編集2018/02/18 04:32
karamarimo

総合スコア2551

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

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

退会済みユーザー

退会済みユーザー

2018/02/18 04:23 編集

return HtmlTag(self.value)とするのに何か問題ありましたっけ?
karamarimo

2018/02/18 04:31

あ...今やったら普通にできました。何か勘違いしていたようです。 ご指摘ありがとうございます。
karamarimo

2018/02/18 04:44

自身を参照できないのはクラス定義内のトップレベルでの話でした。 確かに関数内での変数の名前解決は実行時に行われるので大丈夫ですね。 class C: ____def __init__(self): ________self.value = 123 ____c = C() NameError: name 'C' is not defined
退会済みユーザー

退会済みユーザー

2018/02/18 06:34

実は質問する前に以下のように書いてエラーを出していました。 ここはselfではないのですね。 class HtmlTag(): value="" def __init__(self,text): self.value = text def p(self): return self("<p>{}</p>".format(self.value)) def b(self): return self("<b>{}</b>".format(self.value))
karamarimo

2018/02/18 06:46

selfはインスタンスであってHtmlTagクラス自体ではないので関数(コンストラクタ)として呼ぶことはできません。
退会済みユーザー

退会済みユーザー

2018/02/18 08:17

なるほど。インスタンスをあらわすわけですね。ようやくロジックが見えてきました。
guest

0

試しにこうしてみました。
パターン1の最後の二行だけ変えてみました。
クラスのメソッドを呼び出す際は、作成したクラスのインスタンスを入れた「H」をよびだし、そのあとに「.」を加えてメソッドを呼び出します。
書かれていたコードだと、bメソッドを呼び出し、さらにその中にpメソッドがあるような感じになってしまっていたので、エラーになります。

Python

1class HtmlTag(): 2 value="" 3 def __init__(self,text): 4 self.value = text 5 def p(self): 6 self.value = "<p>{}</p>".format(self.value) 7 def b(self): 8 self.value = "<b>{}</b>".format(self.value) 9 10H=HtmlTag("hello") 11H.b() 12H.p() 13print(H.value)

投稿2018/02/18 00:17

SatoshiMashino

総合スコア210

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

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

SatoshiMashino

2018/02/18 00:26 編集

失敬、「1行にできないか」ということでしたね、先走りました。 申し訳ありません、当方そのような方法があるかは判りかねます。 ただ、可読性を考えるとあまりトリッキーな方法はとらないほうがよろしいかと……。
退会済みユーザー

退会済みユーザー

2018/02/18 03:51

どうもありがとうございました!
SatoshiMashino

2018/02/18 05:18

凄いな、メソッドチェーンっていうのか、初めて知りました。 勉強不足で申し訳ないです、出直してきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問