関数は、プログラミングの経験がなくても、数学のバックグラウンドが十分にある人にとっても簡単に理解できます。一方、クラスは把握するのが難しいようです。
誕生日と現在の年を与えられた人の年齢を計算するクラス/関数を作りたいとしましょう。このためのクラス、または関数を作成する必要がありますか?または、選択はシナリオに依存していますか?
追伸私はPythonに取り組んでいますが、質問は一般的なものだと思います。
関数を作成します。関数do特定のもの、クラスare特定のもの。
クラスには多くの場合、特定のクラスに関連付けられた関数であるメソッドがあり、そのクラスに関連付けられていることを実行します。
本質的に、クラスとは、関数(メソッドとして)とデータ(プロパティとして)を特定の種類の物を中心に論理的な単位にグループ化する方法です。そのグループ化が必要ない場合は、クラスを作成する必要はありません。
アンバーは答えで言う :関数を作成します。実際、次のようなものがある場合、クラスを作成する必要はありませんしないでください
class Person(object):
def __init__(self, arg1, arg2):
self.arg1 = arg1
self.arg2 = arg2
def compute(other):
""" Example of bad class design, don't care about the result """
return self.arg1 + self.arg2 % other
ここでは、クラスにカプセル化された関数があります。これにより、コードが読みにくくなり、効率が低下します。実際、関数compute
は次のように書くことができます。
def compute(arg1, arg2, other):
return arg1 + arg2 % other
クラスを使用するのは、そのクラスに複数の関数があり、内部状態(属性付き)を維持することが理にかなっている場合のみにしてください。それ以外の場合、関数を再グループ化する場合は、新しい.py
ファイル。
このビデオ(Youtube、約30分)を見るかもしれません 、これは私のポイントを説明しています。 Jack Diederichは、そのような場合にクラスが悪である理由と、特にAPIのようなものにおいて、なぜそれが悪い設計であるのかを示しています。
かなり長いですが、必見です
クラス(またはそのインスタンス)は、物を表すためのものです。クラスは、オブジェクトの特定のクラス(そのインスタンス)によってサポートされる操作を定義するために使用されます。アプリケーションで人を追跡する必要がある場合、Person
はおそらくクラスです。このクラスのインスタンスは、追跡している特定の人々を表します。
関数は物事を計算するためのものです。それらは入力を受け取り、出力を生成し、そして/または効果を持ちます。
クラスと関数は同じものではないため、実際には代替ではありません。 「誕生日と現在の年を与えられた人の年齢を計算する」クラスを作成することを検討することは、実際には意味をなしません。 Person
、Age
、Year
、および/またはBirthday
の概念のいずれかを表すクラスがある場合とない場合があります。しかし、Age
がクラスであっても、人の年齢を計算するものと考えるべきではありません。むしろ、Age
クラスのインスタンスでの人の年齢の計算結果。
アプリケーションで人をモデル化し、Person
クラスがある場合、年齢の計算をPerson
クラスのmethodにするのが理にかなっているかもしれません。メソッドは基本的に、クラスの一部として定義される関数です。これが、前述の「特定のクラスのオブジェクトでサポートされる操作を定義する」方法です。
そのため、個人の年齢を計算するために、個人クラスにメソッドを作成できます(おそらく、誕生日オブジェクトを個人オブジェクトから取得し、現在の年をパラメーターとして受け取ります)。ただし、計算は関数(クラスのメソッドである関数)によって行われます。
または、引数(誕生年を取得する人物オブジェクト、または単に誕生年そのもの)を受け取るスタンドアロン関数を作成することもできます。ご指摘のとおり、このメソッドが自然に属するクラスをまだ持っていない場合、これははるかに簡単です!操作を保持するためだけにクラスを作成しないでください。それがallである場合、操作はスタンドアロン関数である必要があります。
シナリオによって異なります。 only人の年齢を計算する場合は、single特定の動作を実装するために関数を使用します。
しかし、人の生年月日(および他のデータ)を含むオブジェクトを作成し、それを変更することを許可する場合、年齢の計算はその人に関連する多くの操作の1つであり、代わりにクラスを使用してください。
クラスは、いくつかのデータと関連する操作をマージする方法を提供します。データに対して1つの操作しかない場合、関数を使用してデータを引数として渡すと、同等の動作が得られ、コードはそれほど複雑ではありません。
種類のクラスに注意してください:
class A(object):
def __init__(self, ...):
#initialize
def a_single_method(self, ...):
#do stuff
実際にはクラスではなく、(複雑な)関数にすぎません。正当なクラスには常に少なくとも2つのメソッドが必要です(__init__
)。
私はそれが物議を醸すトピックであることを知っており、おそらく今やけどするでしょう。しかし、ここに私の考えがあります。
私自身は、できるだけクラスを避けるのが最善だと考えました。複雑なデータ型が必要な場合は、単純な構造体(C/C++)、dict(python)、JSON(js)などを使用します。つまり、コンストラクター、クラスメソッド、演算子のオーバーロード、継承などは使用しません。 OOP自体(どのデザインパターン、プライベートにする必要がある、bla bla))に夢中になり、最初にコーディングしたい基本的なものにゆるやかに焦点を当てることができます。
プロジェクトが大きくなり乱雑になると、何らかのヘリコプタービューシステムアーキテクチャが必要になるため、OOPが意味を成し始めます。「関数vsクラス」も前のタスクに依存します。
質問に答える前に:
Person
クラスがない場合は、最初にPerson
クラスを作成するかどうかを検討する必要があります。 Person
の概念を頻繁に再利用する予定はありますか?その場合、Person
クラスを作成する必要があります。 (渡された変数の形式でこのデータにアクセスできます。面倒でずさんなことは気にしません。)
質問に答えるには:
あなたは彼らの生年月日にアクセスできるので、その場合は、おそらくsomeperson.birthdate
フィールドを持つPerson
クラスがあります。その場合、someperson.age
は再利用可能な値ですか?
答えはイエスです。生年月日よりも年齢を重視することが多いため、生年月日がフィールドの場合、年齢は必ず派生フィールドである必要があります。 (これを行わない場合:someperson.chanceIsFemale
やsomeperson.positionToDisplayInGrid
などの値、または他の無関係な値を計算する場合、Person
クラスを拡張しません。その質問に対する答えは、元のクラスを拡張するか、関数(またはPersonAnalysisData
などの独自のクラス)を作成するかを決定します。 )
クラスを作成しないでください。少なくともOOPクラスの種類Python議論中。
この単純なクラスを考えてみましょう。
class Person(object):
def __init__(self, id, name, city, account_balance):
self.id = id
self.name = name
self.city = city
self.account_balance = account_balance
def adjust_balance(self, offset):
self.account_balance += offset
if __== "__main__":
p = Person(123, "bob", "boston", 100.0)
p.adjust_balance(50.0)
print("done!: {}".format(p.__dict__))
対このnamedtupleバージョン:
from collections import namedtuple
Person = namedtuple("Person", ["id", "name", "city", "account_balance"])
def adjust_balance(person, offset):
return person._replace(account_balance=person.account_balance + offset)
if __== "__main__":
p = Person(123, "bob", "boston", 100.0)
p = adjust_balance(p, 50.0)
print("done!: {}".format(p))
Namedtupleアプローチは、次の理由により優れています。
inheritance
は複雑さを追加し、複雑さを隠します。OOPクラス。
ところで、他のほとんどの言語には、namedtuplesのようなレコードタイプ機能があります。たとえば、Scalaにはケースクラスがあります。このロジックは同じように適用されます。
これについては群れから脱却し、別の視点を提供します。
クラスを作成しないでください。
クラスへの依存は、コーダーに肥大化した遅いコードを作成させる傾向があります。渡されるクラス(オブジェクトであるため)は、関数を呼び出して1つまたは2つの文字列を渡すよりもはるかに多くの計算能力を必要とします。関数の適切な命名規則は、クラスの作成でできることのほとんどすべてを、オーバーヘッドのほんの一部とコードの読みやすさで実行できます。
ただし、クラスを理解することを学ぶべきではないという意味ではありません。他の人とコーディングしている場合、人々は常にそれらを使用するため、それらのクラスをジャグリングする方法を知る必要があります。関数に依存するようにコードを記述することは、コードがより小さく、より速く、より読みやすくなることを意味します。きびきびした迅速な機能のみを使用して書かれた巨大なサイトを見てきました。また、クラスに大きく依存し、絶えず壊れる最小限の機能を備えた小さなサイトを見てきました。 (クラスの一部としてクラスを含むクラスを拡張するクラスがある場合、簡単な保守性のすべての見た目を失ったことがわかります。)
結局のところ、渡そうとしているすべてのデータは、既存のデータ型で簡単に処理できます。
クラスは精神的な松葉杖として作成され、実際の余分な機能を提供しません。クラスが作成する傾向がある過度に複雑なコードは、長期的には松葉杖のポイントを打ち負かします。