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

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

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

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

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

Python

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

Q&A

解決済

3回答

2897閲覧

クラスを用いる理由がわかりません(Python)

yomogian

総合スコア8

Python 3.x

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

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

Python

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

2グッド

4クリップ

投稿2017/11/09 06:54

編集2017/11/13 09:10

###クラスの有用性
Pythonを触り始めて10日程度の初心者です。
この度ネット上で見つけたプログラム(おそらくこちらのサイトです:https://qiita.com/Kiro02/items/851a6b3f5cad37d77875)
にクラスが用いられていました。
オブジェクト指向がいまだに理解できていないこともあるのですが
このプログラムにおいてクラスが用いられている理由がよくわからないです。
以下がそのプログラムで指定したワードの画像検索結果を保存する、という動作をします。
###プログラム

import os import sys import traceback from mimetypes import guess_extension from time import time, sleep from urllib.request import urlopen, Request from urllib.parse import quote from bs4 import BeautifulSoup MY_EMAIL_ADDR = '' class Fetcher: def __init__(self, ua=''): self.ua = ua def fetch(self, url): req = Request(url, headers={'User-Agent': self.ua}) try: with urlopen(req, timeout=3) as p: b_content = p.read() mime = p.getheader('Content-Type') except: sys.stderr.write('Error in fetching {}\n'.format(url)) sys.stderr.write(traceback.format_exc()) return None, None return b_content, mime fetcher = Fetcher('任意のメールアドレス') def fetch_and_save_img(word): data_dir = 'data/' if not os.path.exists(data_dir): os.makedirs(data_dir) for i, img_url in enumerate(img_url_list(word)): sleep(0.1) img, mime = fetcher.fetch(img_url) if not mime or not img: continue ext = guess_extension(mime.split(';')[0]) if ext in ('.jpe', '.jpeg'): ext = '.jpg' if not ext: continue result_file = os.path.join(data_dir, "ajisai_" + str(i) + ext) with open(result_file, mode='wb') as f: f.write(img) print('fetched', img_url) def img_url_list(word): """ using yahoo (this script can't use at google) """ url = 'http://image.search.yahoo.co.jp/search?n=60&p={}&search.x=1'.format(quote(word)) byte_content, _ = fetcher.fetch(url) structured_page = BeautifulSoup(byte_content.decode('UTF-8'), 'html.parser') img_link_elems = structured_page.find_all('a', attrs={'target': 'imagewin'}) img_urls = [e.get('href') for e in img_link_elems if e.get('href').startswith('http')] img_urls = list(set(img_urls)) return img_urls if __name__ == '__main__': word = sys.argv[1] fetch_and_save_img(word)

###知りたいこと
オブジェクト指向を詳しく知るのは難しいと思うので、このプログラムにおいてなぜクラスを用いるのか、用いらずに関数のみを用いた場合どのような支障をきたすのか、教えていただきたいです。
よろしくお願いします。

LouiS0616, chapin👍を押しています

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

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

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

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

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

ockeghem

2017/11/09 07:02

ネットの記事からの転載であれば、出典のURLを明記したほうがよいと思います。出典があれば、多くの場合引用とみなすことができ著作権的な問題を避けることができやすいこと、また回答者が元記事の前後関係を読んで、より良いアドバイスができる可能性が高いからです。
yomogian

2017/11/09 07:22

コメントありがとうございます。その点については認識しておりましたが、参照したWEBサイトのアドレスがわからず、見つけられないためやむなくこのような形になりました。著作権的問題回避のために一定期間が過ぎたら削除または編集しようと思っています。
yomogian

2017/11/09 07:22

コメントありがとうございます。その点については認識しておりましたが、参照したWEBサイトのアドレスがわからず、見つけられないためやむなくこのような形になりました。著作権的問題回避のために一定期間が過ぎたら削除または編集しようと思っています。
KSwordOfHaste

2017/11/09 09:28 編集

「著作権的問題回避のために一定期間が過ぎたら削除または編集」=>この認識は改めていただきたいと思います。「著作権問題の危険があるなら最初から質問しない」、一旦質問したなら「めったなことでは質問を消さない」のが大事と思います。一旦質問文に書いたことは編集しても残ります(元の内容は全員に見える)し、内容を不用意に変更・削除すると情報共有の意味が失われます。
guest

回答3

0

このスクリプトの出典は以下でしょうか?

Tensorflowを再学習させて「〇〇判別機」を作る - Qiita

このプログラムにおいてなぜクラスを用いるのか、用いらずに関数のみを用いた場合どのような支障をきたすのか

なぜクラスを用いるのかはともかく、クラスを用いなかった場合どうなるかはぜひご自身で試してみることをお勧めします。
このクラスは実質的にメソッド fetch のみからなりますから、関数でもいいじゃんと感じることは自然だと思います。
fetchの引数 url は呼び出すたびに変わるものですから引数にするのが自然ですが、fetchの際の他のパラメータは半固定ですよね。それを一々引数で渡すのはわずらわしいし、かといってグローバル変数にすると、ua 等のパラメータを変えたいときに柔軟性が乏しくなります。なので、uaをインスタンス変数で持つことは、uaが半固定であることを反映して使い勝手のよい設計であると思いました。

また、fetch関数は汎用性の高い機能であるので、uaパラメータが固定であったり、グローバル変数で指定していると、他の環境に持っていくことが難しくなります。

さらに、ua以外のパラメータ(HTTPリクエストヘッダ)を指定したくなった場合も、現在のスクリプトを拡張して自然に、互換性を損なわずに、改良ができます。

以上のような理由から、作者はクラスにしたのではないかと思いますが、作った本人ではないので、意図の部分はあくまで推測です。

投稿2017/11/09 07:25

ockeghem

総合スコア11701

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

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

yomogian

2017/11/13 09:09

おそらくそちらの出店で間違いないです。 わかりやすい解説ありがとうございました。 理解するのには時間がかかると思いますが、これから頑張ってみたいと思います。
guest

0

ベストアンサー

このプログラムにおいてクラスが用いられている理由がよくわからないです

ご質問はごもっともで、自然な疑問です。
そもそも現状では、クラスじゃなく関数だけでも、
「支障をきたす」ほどではないと思います。

じゃあ、オブジェクト指向(OO)を使う意味は何なの、という疑問が残るでしょう。
難しくなりすぎないよう、使い分けの基準だけごく簡単に示します。


###手続き型とオブジェクト指向

小規模であれば、手続き型の方が簡単に早く作れますが、
大規模になると、オブジェクト指向の方が保守が楽です。

多少作成コストが高くなっても、抽象化技法を使って、
変更コストを下げるのがオブジェクト指向の目的です。

これは「うさぎとカメ」の話で、オブジェクト指向は、
後でシステムを変更したいときにこそ真価を発揮します。

じっさい今は、(クラス)ライブラリやフレームワークが、
OOで書かれることが多いことが、長期運用に向くことを実証しています。

なぜ変えやすいかというと、「クラス」が変更しやすい仕組みだからです。
ただし、自動的にはそうならず、変更を意識して組む必要があります。

たとえば、「単一責任の原則」という設計原則があって、
クラスを責務(変更理由)の単位にした設計にすれば、
変更時に変更部分がクラスに局所化されているので、変更しやすいです。


###関数型とオブジェクト指向

Pythonは関数型とOOと両方のパラダイムで書けます。(RubyやJSもそう)
関数型とOOは、どちらも難解なので、やはり要点だけ説明しますね。

この両者は、手続き型よりもコードを抽象化して、宣言性を高める手法で、
処理が中心なのが関数型で、データ(型)が中心なのがOOです。

そして、参照透過によって抽象化するのが関数型、
カプセル化によって抽象化するのがオブジェクト指向、という違いがあります。

具体的にコード上では、(再代入禁止し)引数で受け渡すのが関数型、
インスタンス変数で状態を持つのがOO、という違いが見られます。

さて、どう使い分けるかといえば、処理を多様化したいのか、
データを多様化したいのか、という目的の違いによります。

扱うデータ型が単調で処理を多様化したいなら、関数型の方が向きます。

たとえば文字列処理や言語処理系など記号処理は、
基本的に入出力の連結を繰り返す構造にしやすいので、
関数型の方が簡潔に書けます。WebもHTMLが基本的に文字列なので、
関数型の方がシンプルになる場合が結構あると思います。

Python、Ruby、JavaScriptが、関数型の性格を持つのも、
偶然というよりは、もともとWebに向いてるからでしょう。

逆にデータ型が多様で状態遷移も複雑な場合、OOが向きます。
GUIのソフトやゲームは、たいてい状態の塊なので、OOが向いています。
じっさい、C#やJavaのようなOO中心の言語がよく用いられます。


プログラムで指定したワードの画像検索結果を保存する

さて最後に、最初の話題に戻り、今までの考察を応用してみましょう。

まず、一時的に使うだけで拡張予定がないなら、
手続き型で十分です。小規模なら一番楽で早いです。

拡張予定があり、ワードの文字列処理を多様化する、
たとえば、類似表現も提示する、欠けている語を補完する、
また検索や画像の処理方法を多様化する、たとえば、
検索結果(の文字部分)で再度検索する部分を作る、
画像を縮小したり加工する……、など処理の多様化には関数型が向きます。

あるいは、画像の分類を増やす、複数の検索サービスやAPIを使う、
画像だけでなく文章、動画、音声なども探す、さらに拡張子で変える、
また分類タグなどメタデータを持たせ、それで保存の仕方などを変える、
容量節約重視などの検索モードを付ける、GUIを付ける……、
などデータと状態の多様化をする方向で拡張するなら、OOが向きます。

……もし、したいことに両方の要素があったら?
関数型とOOを併用しても良いのです。とくにPythonやRubyは併用しやすい。

投稿2017/11/09 12:50

LLman

総合スコア5592

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

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

yomogian

2017/11/13 09:09

わかりやすい解説ありがとうございました。 理解するのには時間がかかると思いますが、これから頑張ってみたいと思います。
guest

0

オブジェクト指向を使うことによって、コードを読む人の理解を助けることができます。
今のコードの場合、Fetcherというクラス名はfetchを行うためのメソッドを持つと連想されることができます。
このクラスにはもっといろいろと行うことを付け足すことができるはずです。
例えば、.update_ua(new_ua)というメソッドでどこかでアドレスを変更することなどが考えられます。

プログラミングでは同等の機能をいくつもの方法で実装できます。
素朴に関数として実装された場合と比べると、ockeghemさんが指摘されているようにuaという属性に自由度をもたせつつ、グローバル変数の空間を汚さないことが実現できます。
同じ目的でも、今回のクラスでの実装以外にクロージャ(関数を生成する関数)を用いることもできます。
以下にコードを示します。
この場合、一度与えたuaを今後変更することは自然ではなくなります。
それと引き換えに、fetcher.fetch(url)の代わりにfetch(url)とコードが少しスッキリします。

実装の方法が数多ある中で、適切な実装をすることでコードは読みやすくなり、バグりにくくなります。
プログラミングする際には入力に対して正しい出力を出すことだけが重要というわけではありません。
同じコードが他のところで再利用されたり、長い間変化しながら使用され続ける可能性をも考えることで、オブジェクト指向を用いることの必要性について評価することができるかと思います。

python

1def generate_fetch(ua): 2 def fetch(url): 3 req = Request(url, headers={'User-Agent': ua}) 4 try: 5 with urlopen(req, timeout=3) as p: 6 b_content = p.read() 7 mime = p.getheader('Content-Type') 8 except: 9 sys.stderr.write('Error in fetching {}\n'.format(url)) 10 sys.stderr.write(traceback.format_exc()) 11 return None, None 12 return b_content, mime 13 return fetch 14 15fetch = generate_fetch('任意のメールアドレス') 16byte_content, _ = fetch(url)

投稿2017/11/09 08:20

mkgrei

総合スコア8560

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

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

yomogian

2017/11/13 09:09

わかりやすい解説ありがとうございました。 理解するのには時間がかかると思いますが、これから頑張ってみたいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問