1. ホーム
  2. python

[解決済み] なぜPythonのクラスでは__init__を使うのですか?

2022-06-13 02:10:42

疑問点

クラスの初期化について、理解するのに苦労しています。

クラスは何のためにあるのでしょうか、また、クラスに何を含めるべきかをどのように判断すればよいのでしょうか。クラスで書くには、関数を作るのとは違ったタイプの考え方が必要なのでしょうか (関数を作って、それを再利用できるようにクラスでラップすればいいと思いました。それはうまくいくでしょうか?)

以下はその例です。

class crawler:
  # Initialize the crawler with the name of database
  def __init__(self,dbname):
    self.con=sqlite.connect(dbname)

  def __del__(self):
    self.con.close()

  def dbcommit(self):
    self.con.commit()

あるいは別のコードサンプル。

class bicluster:
  def __init__(self,vec,left=None,right=None,distance=0.0,id=None):
    self.left=left
    self.right=right
    self.vec=vec
    self.id=id
    self.distance=distance

を持つクラスは非常に多くあります。 __init__ 他の人のコードを読もうとすると出会うのですが、それを作るロジックが理解できません。

どのように解決するのですか?

あなたの書いたものでは、クラスとオブジェクトの違いという重要な理解が欠けています。 __init__ はクラスを初期化するのではなく、クラスやオブジェクトのインスタンスを初期化するのです。それぞれの犬には色がありますが、クラスとしての犬には色はありません。それぞれの犬は4本以下の足を持っているが、犬のクラスは持っていない。クラスはオブジェクトの概念である。ファイドーとスポットを見たとき、あなたは彼らの類似性、犬らしさを認識する。それがクラスです。

というとき

class Dog:
    def __init__(self, legs, colour):
        self.legs = legs
        self.colour = colour

fido = Dog(4, "brown")
spot = Dog(3, "mostly yellow")

ファイドーは4本足の茶色い犬で、スポットはちょっと不自由でほとんど黄色い犬ということですね。その __init__ 関数はコンストラクタ、またはイニシャライザと呼ばれ、クラスの新しいインスタンスを作成するときに自動的に呼び出されます。その関数の中で、新しく生成されたオブジェクトは、パラメータ self . この表記は self.legs という属性は legs というオブジェクトの属性で、変数 self . 属性は変数のようなものですが、オブジェクトの状態や、オブジェクトが利用できる特定のアクション(関数)を記述します。

しかし colour を設定しないことに注意してください。これは抽象的な概念です。クラスに対して意味のある属性もあります。例えば population_size はそのひとつです。Fidoは常にひとつなので、Fidoを数えることは意味をなしません。しかし、犬を数えるのは意味があります。世界に2億匹の犬がいるとしましょう。これはDogクラスのプロパティです。ファイドーは2億という数字には関係ないし、スポットも関係ない。これはクラス属性と呼ばれるもので、インスタンス属性と呼ばれるものは colour とか legs の上にあります。

さて、イヌっぽくない、プログラミングに関連した話です。以下に書くように、物事を追加するクラスは賢明ではありません - それは何のクラスなのでしょうか?Pythonのクラスは、同じような振る舞いをする異なるデータの集まりを構成します。犬のクラスは、FidoとSpotと19999999998匹の似たような動物で構成され、全員が街灯におしっこをしています。モノを追加するクラスは何から構成されているのだろうか?それらは固有のどのようなデータによって異なるのだろうか?また、どのような動作が共通しているのでしょうか?

しかし、数というのは...もっと面白いテーマです。例えば、整数。犬よりずっとたくさんあるんだ。Pythonがすでに整数を持っていることは知っていますが、(Pythonの整数をズルして)もう一度実装して遊んでみましょう。

というわけで、整数はクラスです。いくつかのデータ(値)と、いくつかの動作("私をこの他の数に加える")を持っています。これを示してみましょう。

class MyInteger:
    def __init__(self, newvalue):
        # imagine self as an index card.
        # under the heading of "value", we will write
        # the contents of the variable newvalue.
        self.value = newvalue
    def add(self, other):
        # when an integer wants to add itself to another integer,
        # we'll take their values and add them together,
        # then make a new integer with the result value.
        return MyInteger(self.value + other.value)

three = MyInteger(3)
# three now contains an object of class MyInteger
# three.value is now 3
five = MyInteger(5)
# five now contains an object of class MyInteger
# five.value is now 5
eight = three.add(five)
# here, we invoked the three's behaviour of adding another integer
# now, eight.value is three.value + five.value = 3 + 5 = 8
print eight.value
# ==> 8

これはちょっと壊れやすいですね(仮に other はMyIntegerであると仮定しています)、今は無視しましょう。実際のコードでは、そうしません。念のためにテストして、もしかしたら強制することもあるかもしれません ("you're not an integer? by golly, you have 10 nanoseconds to become one !")。9... 8... ")。

分数を定義することもできます。分数は足し算もできるのです。

class MyFraction:
    def __init__(self, newnumerator, newdenominator):
        self.numerator = newnumerator
        self.denominator = newdenominator
        # because every fraction is described by these two things
    def add(self, other):
        newdenominator = self.denominator * other.denominator
        newnumerator = self.numerator * other.denominator + self.denominator * other.numerator
        return MyFraction(newnumerator, newdenominator)

分数は整数よりさらに多い(実際は違うが、コンピュータはそんなこと知らない)。2つ作ってみましょう。

half = MyFraction(1, 2)
third = MyFraction(1, 3)
five_sixths = half.add(third)
print five_sixths.numerator
# ==> 5
print five_sixths.denominator
# ==> 6

ここでは実際に何かを宣言しているわけではありません。属性は新しい種類の変数のようなものです。通常の変数は一つの値しか持ちません。例えば、あなたが colour = "grey" . という名前の別の変数を持つことはできません。 colour という名前の変数を持つことはできません。 "fuchsia" - がコード内の同じ場所にない

配列はそれをある程度解決してくれます。もしあなたが colour = ["grey", "fuchsia"] とすると、変数に2つの色を積み重ねたことになりますが、その位置(この場合は0か1か)で区別しています。

属性はオブジェクトに束縛される変数です。配列と同じように、たくさんの colour という変数があります。 を持つことができます。 . だから fido.colour は一つの変数ですが spot.colour は別のものです。最初のものは変数内のオブジェクトに束縛されている fido であり、2番目は spot . さて、あなたが Dog(4, "brown") を呼び出したとき、あるいは three.add(five) を使用した場合、常に目に見えないパラメータが存在し、それがパラメータリストの先頭にあるぶら下がった余分なパラメータに割り当てられます。これは慣例的に self と呼ばれ、ドットの前にあるオブジェクトの値を取得します。したがって、Dogの __init__ (コンストラクタ)に self は新しい Dog がどのようなものであっても構いません。 MyInteger 's add , self はオブジェクトにバインドされ、変数 three . このように three.value の外側では同じ変数になります。 add と同じになります。 self.value の中で add .

もし私が the_mangy_one = fido というオブジェクトを参照し始めます。 fido として知られているオブジェクトを、さらに別の名前で呼ぶことにします。これからは fido.colour とは全く同じ変数で the_mangy_one.colour .

ということは __init__ . これらは、Dogの出生証明書にいろいろと書き込んでいると考えてよいでしょう。 colour はそれ自体がランダムな変数で、何でも入れることができます。 fido.colour または self.colour はDogのIDシートのフォームフィールドのようなもので、そして __init__ は、店員が初めてそれを記入するところです。

もっとわかりやすいのは?

EDIT : 下のコメントを展開します。

のリストということですね。 オブジェクトのリストです。 という意味ですよね?

まず最初に fido は実はオブジェクトではありません。これは変数であり、現在オブジェクトを含んでいます。 x = 5 , x は現在数字の5を含む変数です。後で気が変わったら、次のようにします。 fido = Cat(4, "pleasing") とすることができます (ただし、クラス Cat )、そして fido はそれ以降、猫オブジェクトを含むようになります。もし fido = x とすると、数字の5が含まれ、動物のオブジェクトは含まれません。

クラスはそれ自体では、特にインスタンスを追跡するコードを書かない限り、そのインスタンスを知ることはできません。例えば

class Cat:
    census = [] #define census array

    def __init__(self, legs, colour):
        self.colour = colour
        self.legs = legs
        Cat.census.append(self)

ここで census はクラスレベルの属性で Cat クラスのクラスレベル属性です。

fluffy = Cat(4, "white")
spark = Cat(4, "fiery")
Cat.census
# ==> [<__main__.Cat instance at 0x108982cb0>, <__main__.Cat instance at 0x108982e18>]
# or something like that

を得ることができないことに注意してください。 [fluffy, sparky] . これらは単なる変数名である。もし猫自体に名前を付けたいのであれば、名前用の属性を別に作り、その上で __str__ メソッドをオーバーライドしてこの名前を返さなければならない。このメソッドの(つまりクラス結合関数で、ちょうど add または __init__ ) の目的は、印刷するときのように、オブジェクトを文字列に変換する方法を記述することです。