web-dev-qa-db-ja.com

なぜPythonクラスで__init__を使用するのですか?

クラスの初期化を理解できません。

それらのポイントは何ですか?また、それらに何を含めるべきかをどのように知るのですか?クラスでの記述には、関数の作成と関数の作成とでは異なる考え方が必要ですか(関数を作成し、クラスにラップして再利用できると考えました。それは機能しますか?)

以下に例を示します。

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__のクラスは非常に多く、他の人のコードを読み取ろうとすると出くわしますが、それらを作成する際のロジックがわかりません。

110
Lostsoul

あなたが書いたことによって、あなたは重要な理解の一部、つまりクラスとオブジェクトの違いを見逃しています。 __init__はクラスを初期化せず、クラスまたはオブジェクトのインスタンスを初期化します。各犬には色がありますが、クラスの犬にはありません。各犬は4足以下ですが、犬のクラスにはありません。クラスはオブジェクトの概念です。 FidoとSpotを見ると、それらの類似点、つまり犬のように見えます。それがクラスです。

あなたが言う時

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は常に1であるため、Fidoを数えることは意味がありません。犬を数えるのは理にかなっています。世界に2億匹の犬がいるとしましょう。これはDogクラスのプロパティです。 Fidoは2億という数字とは関係がなく、Spotも関係ありません。上記のcolourまたはlegsである「インスタンス属性」とは対照的に、「クラス属性」と呼ばれます。

今、より少ない犬とより多くのプログラミング関連のものに。以下に書いているように、物事を追加するクラスは賢明ではありません-それは何のクラスですか? Pythonのクラスは、異なるデータのコレクションで構成され、同様に動作します。犬のクラスは、FidoとSpot、およびそれらに類似した199999999998の他の動物で構成され、それらはすべて街灯でおしっこしています。物事を追加するためのクラスは何で構成されていますか?それらに固有のデータによって違いはありますか?そして、彼らはどんな行動を共有しますか?

しかし、数字...これらはより興味深いテーマです。言う、整数。それらの多くは、犬よりもはるかに多くあります。 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になると想定しています)が、今は無視します。実際のコードでは、そうしません。確認するためにテストし、おそらく強制することもあります(「あなたは整数ではありませんか?

分数を定義することもできます。分数も自分自身を追加する方法を知っています。

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

ここでは実際には何も宣言していません。属性は、新しい種類の変数のようなものです。通常の変数には1つの値しかありません。 colour = "grey"と書いてみましょう。 colourという名前の別の変数を"Fuchsia"にすることはできません-コード内の同じ場所にはありません。

配列はそれをある程度解決します。 colour = ["grey", "Fuchsia"]と言うと、変数に2色を重ねていますが、それらの位置(この場合は0または1)で区別します。

属性は、オブジェクトにバインドされる変数です。配列と同様に、多くのcolour変数、異なる犬でを使用できます。したがって、fido.colourは1つの変数ですが、spot.colourは別の変数です。最初のものは変数fido内のオブジェクトにバインドされます。 2番目のspot。これで、Dog(4, "brown")またはthree.add(five)を呼び出すと、常に不可視のパラメーターが存在し、パラメーターリストの先頭にあるぶら下がり余分なパラメーターに割り当てられます。従来はselfと呼ばれ、ドットの前にあるオブジェクトの値を取得します。したがって、Dogの__init__(コンストラクター)内では、selfは新しいDogになります。 MyIntegeradd内で、selfは変数threeのオブジェクトにバインドされます。したがって、three.valueは、add内のself.valueと同じように、addの外部と同じ変数になります。

the_mangy_one = fidoと言うと、fidoというオブジェクトを別の名前で参照し始めます。これ以降、fido.colourthe_mangy_one.colourとまったく同じ変数です。

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

より明確な?

EDIT:以下のコメントを展開:

objectsのリストを意味しますよね?

まず、fidoは実際にはオブジェクトではありません。これは変数であり、現在x = 5と言っているように、xは現在5番を含む変数です。後で気が変わったら、(クラスCatを作成している限り)fido = Cat(4, "pleasing")を実行でき、fidoはその後catオブジェクトを「含む」ことになります。 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__のようなクラスバインド関数)の目的は、オブジェクトを印刷するときのように、オブジェクトを文字列に変換する方法を記述することです。

267
Amadan

アマダンからの完全な説明 に私の5セントを寄付する。

ここで、クラスは抽象的な方法での「タイプの」記述です。オブジェクトは彼らの認識です:生きている呼吸物。オブジェクト指向の世界では、ほとんどすべてのものの本質と呼ぶことができる主要なアイデアがあります。彼らです:

  1. カプセル化(これについては詳しく説明しません)
  2. 継承
  3. 多型

オブジェクトには、1つ以上の特性(=属性)と動作(=メソッド)があります。動作は主に特性に依存します。クラスは、振る舞いが一般的な方法で何を達成すべきかを定義しますが、クラスがオブジェクトとして実現(インスタンス化)されない限り、可能性の抽象的な概念のままです。 「継承」と「ポリモーフィズム」の助けを借りて説明しましょう。

    class Human:
        gender
        nationality
        favorite_drink
        core_characteristic
        favorite_beverage
        name
        age

        def love    
        def drink
        def laugh
        def do_your_special_thing                

    class Americans(Humans)
        def drink(beverage):
            if beverage != favorite_drink: print "You call that a drink?"
            else: print "Great!" 

    class French(Humans)
        def drink(beverage, cheese):
            if beverage == favourite_drink and cheese == None: print "No cheese?" 
            Elif beverage != favourite_drink and cheese == None: print "Révolution!"

    class Brazilian(Humans)
        def do_your_special_thing
            win_every_football_world_cup()

    class Germans(Humans)
        def drink(beverage):
            if favorite_drink != beverage: print "I need more beer"
            else: print "Lecker!" 

    class HighSchoolStudent(Americans):
        def __init__(self, name, age):
             self.name = name
             self.age = age

jeff = HighSchoolStudent(name, age):
hans = Germans()
ronaldo = Brazilian()
amelie = French()

for friends in [jeff, hans, ronaldo]:
    friends.laugh()
    friends.drink("cola")
    friends.do_your_special_thing()

print amelie.love(jeff)
>>> True
print ronaldo.love(hans)
>>> False

いくつかの特性は人間を定義します。しかし、国籍は多少異なります。ですから、「国民型」はちょっと余分な人間です。 「アメリカ人」は「人間」の一種であり、人間のタイプ(基本クラス)からいくつかの抽象的な特性と動作を継承します。それは継承です。それで、すべての人間は笑って飲むことができます、したがって、すべての子供クラスもそうすることができます!継承(2)。

しかし、それらはすべて同じ種類(Type/base-class:Humans)であるため、時々交換することができます:最後にforループを参照してください。しかし、それらは個々の特性を公開し、それが多態性(3)です。

そのため、各人はfavourite_drinkを持っていますが、すべての国籍は特別な種類の飲み物を好みます。ヒューマンのタイプから国籍をサブクラス化すると、drink()メソッドを使用して上記で示したように、継承された動作を上書きできます。しかし、それはまだクラスレベルであり、このため、まだ一般化されています。

hans = German(favorite_drink = "Cola")

クラスGermanをインスタンス化し、最初にデフォルトの特性を「変更」しました。 (しかし、hans.drink( 'Milk')を呼び出すと、彼はまだ「もっとビールが必要」と表示します-明らかなバグ...または多分それが私がより大きな会社の従業員である場合、機能と呼ぶものです。 ;-)! )

タイプの特性(例:ドイツ語(hans)は通常、インスタンス化の瞬間にコンストラクター(python:__init__)で定義されます。これが、オブジェクトになるクラスを定義するポイントです。個々の特性を満たし、オブジェクトになることで、抽象的な概念(クラス)に息吹を吹き込むことができます。

しかし、すべてのオブジェクトはクラスのインスタンスであるため、いくつかの基本的な特性タイプと動作をすべて共有しています。これは、オブジェクト指向の概念の大きな利点です。

各オブジェクトの特性を保護するには、それらをカプセル化します。つまり、動作と特性を組み合わせて、オブジェクトの外部から操作しにくくすることを意味します。それはカプセル化です(1)

23
Don Question

インスタンスの変数を初期化するだけです。

例えば。特定のデータベース名でcrawlerインスタンスを作成します(上記の例から)。

5
jldupont

インスタンスの可変属性を正しく初期化する場合は、Pythonで__init__を使用する必要があるようです。

次の例を参照してください。

>>> class EvilTest(object):
...     attr = []
... 
>>> evil_test1 = EvilTest()
>>> evil_test2 = EvilTest()
>>> evil_test1.attr.append('strange')
>>> 
>>> print "This is evil:", evil_test1.attr, evil_test2.attr
This is evil: ['strange'] ['strange']
>>> 
>>> 
>>> class GoodTest(object):
...     def __init__(self):
...         self.attr = []
... 
>>> good_test1 = GoodTest()
>>> good_test2 = GoodTest()
>>> good_test1.attr.append('strange')
>>> 
>>> print "This is good:", good_test1.attr, good_test2.attr
This is good: ['strange'] []

これは、各属性が新しい値で自動的に初期化されるJavaではまったく異なります。

import Java.util.ArrayList;
import Java.lang.String;

class SimpleTest
{
    public ArrayList<String> attr = new ArrayList<String>();
}

class Main
{
    public static void main(String [] args)
    {
        SimpleTest t1 = new SimpleTest();
        SimpleTest t2 = new SimpleTest();

        t1.attr.add("strange");

        System.out.println(t1.attr + " " + t2.attr);
    }
}

直感的に期待する出力を生成します:

[strange] []

ただし、attrstaticとして宣言すると、Pythonのように動作します。

[strange] [strange]
3
alexpirine

あなたのcarに従ってください:あなたが車を取得するとき、あなたはただランダムな車を取得しない、つまり、あなたは色、ブランドを選ぶ、座席の数など。また、ホイールの数や登録番号など、ユーザーが選択せずに「初期化」するものもあります。

class Car:
    def __init__(self, color, brand, number_of_seats):
        self.color = color
        self.brand = brand
        self.number_of_seats = number_of_seats
        self.number_of_wheels = 4
        self.registration_number = GenerateRegistrationNumber()

したがって、__init__メソッドでは、作成するインスタンスの属性を定義します。したがって、2人用の青いルノー車が必要な場合は、次のようにCarのインスタンスを初期化します。

my_car = Car('blue', 'Renault', 2)

このようにして、Carクラスのインスタンスを作成しています。 __init__は、特定の属性(colorbrandなど)を処理し、registration_numberなどの他の属性を生成するものです。

3
juliomalegria

クラスは、そのオブジェクトに固有の属性(状態、特性)およびメソッド(機能、容量)を持つオブジェクトです(それぞれ、アヒルの白色および飛行力など)。

クラスのインスタンスを作成するときに、初期の性格(名前や新生児のドレスの色などの状態またはキャラクター)を与えることができます。これは__init__で行います。

基本的に__init__は、instance = MyClass(some_individual_traits)を呼び出すときにインスタンスの特性を自動的に設定します。

3
joaquin

__init__関数は、クラス内のすべてのメンバー変数を設定しています。したがって、バイクラスターが作成されると、メンバーにアクセスして値を取得できます。

mycluster = bicluster(...actual values go here...)
mycluster.left # returns the value passed in as 'left'

Python Docs をご覧ください。学習を続けるには、OOの概念に関する本を選んでください。

2
AlG
class Dog(object):

    # Class Object Attribute
    species = 'mammal'

    def __init__(self,breed,name):
        self.breed = breed
        self.name = name

上の例では、種は常に同じなので、種をグローバルとして使用します(定数の種類は言うことができます)。 __init__メソッドを呼び出すと、__init__内のすべての変数が開始されます(例:breed、name)。

class Dog(object):
    a = '12'

    def __init__(self,breed,name,a):
        self.breed = breed
        self.name = name
        self.a= a

以下のように呼び出して上記の例を印刷すると

Dog.a
12

Dog('Lab','Sam','10')
Dog.a
10

つまり、オブジェクトの作成時にのみ初期化されます。そのため、定数として宣言するものはすべてグローバルとして変更し、変更するものはすべて__init__を使用します

1
vedavyasa