Pythonクラスで__init__を使用する理由


124

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

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

次に例を示します。

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__他の人のコードを読み込もうとしたときに遭遇するクラスはたくさんありますが、それらを作成するロジックがわかりません。


1
initのストーリーは...何とか何とか何とか...コンストラクター-デストラクターですが、ガベージコレクションが利用可能なため、デストラクターはありません。
MisterGeeky

回答:


289

あなたが書いたものによって、あなたは重要な理解の欠落、つまりクラスとオブジェクトの違いを見逃しています。__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")

あなたが言っているのは、Fidoは4本足の茶色の犬であり、Spotは少し不自由でほとんど黄色です。この__init__関数はコンストラクターまたは初期化子と呼ばれ、クラスの新しいインスタンスを作成すると自動的に呼び出されます。その関数内で、新しく作成されたオブジェクトがパラメーターに割り当てられますself。表記self.legslegs、変数内のオブジェクトの属性と呼ばれます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

これは少し壊れやすい(otherMyIntegerになると想定している)が、ここでは無視する。実際のコードでは、そうしません。私たちはそれを確かめるためにテストし、おそらくそれを強制することさえします(「あなたは整数ではないのですか?ゴーリーによって、あなたは1になるまでに10ナノ秒があります!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

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

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

属性は、オブジェクトにバインドされている変数です。配列の場合と同様colour、さまざまな犬にさまざまな変数を設定できます。つまり、fido.colour1つの変数ですが、spot.colour別の変数です。最初のものは変数内のオブジェクトにバインドされていますfido。二、spot。これでDog(4, "brown")、またはを呼び出すと、three.add(five)常に非表示のパラメーターが存在し、パラメーターリストの前にあるぶら下がりの追加パラメーターに割り当てられます。通常はと呼ばれself、ドットの前にあるオブジェクトの値を取得します。したがって、犬__init__(コンストラクター)内ではself、新しい犬が何であるかがわかります。内MyIntegers「はaddself変数内のオブジェクトにバインドされますthree。したがって、three.value外部同じ変数であろうaddように、self.value以内add

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

だから、内の事__init__。それらは、犬の出生証明書に記載されているものと考えることができます。colourそれ自体は確率変数であり、何でも含むことができます。fido.colourまたはself.colour、犬の身分証明書のフォームフィールドのようなもの。そして__init__最初の時間のためにそれを記入店員です。

より明確ですか?

編集:以下のコメントを拡大:

あなたはオブジェクトのリストを意味しますね?

まず、fido実際にはオブジェクトではありません。これは変数であり、現在オブジェクトを含んでいます。これはx = 5xと言うのと同じように、現在5を含んでいる変数です。後で気が変わった場合はfido = Cat(4, "pleasing")(クラスを作成している限りCat)可能であり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__)は、オブジェクトを印刷するときのように、オブジェクトを文字列に変換する方法を説明することです。


7
わあ、ありがとう..これは実際に私には多くの意味があったので、それが何かであるものは何でも、init関数で事前宣言する必要があります。この場合、犬は足と色を持っています。たとえば、2つの数値を追加するクラスを作成した場合、self.firstnumberとself.secondnumberを宣言してから、クラスでfirstnumber + secondnumberを実行して答えを取得しますか?
Lostsoul 2011

1
やや。あなたはそれを行うことができます。しかし、クラスを追加するためだけにクラスを作ることはほとんど意味がありません。クラスは通常、ビヘイビア付きのデータを実装します-純粋なビヘイビアは単なる関数です。答えを関連性のあるものに拡張します。ちょっと待ってください。
アマダン

3
すばらしい答えをありがとう。私は今、クラスの力を見て理解しています。馬鹿げているようです。データを並べ替えて、さまざまなものの状態を一度に維持できることをご存じのとおりです(ループを介して、またはループを介して作成できる変数をできるだけ追跡します)。だから、私は犬あたりの平均脚数を把握する必要がありますか?このように計算を開始できるように、クラスで作成したすべてのオブジェクトのリストを取得する方法はありますか?または、自分が作成したクラスのリスト(つまり[fido、spot])も維持する必要があります
Lostsoul

23

アマダンから完全な説明に私の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")

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

タイプの特性(例:ドイツ語(ハンス))は通常__init__、インスタンス化の瞬間に(python:で)コンストラクターによって定義されます。これは、オブジェクトになるクラスを定義するポイントです。呼吸の生命は、それを個々の特性で満たし、オブジェクトになることにより、抽象的な概念(クラス)と言えます。

しかし、すべてのオブジェクトはクラスのインスタンスなので、すべての基本的な特性タイプと動作を共有します。これは、オブジェクト指向のコンセプトの大きな利点です。

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


5

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

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


私は、私は本当になど。、開発者above..couldn't例をmeans..inことがちょうど「= fooのままに」彼の主なコードに追加されていることを理解していないごめんなさい
Lostsoul

関数のデフォルト値ですか? left=NoneleftはNone、作成時にleftパラメーターが指定されていない場合に初期化されます。
jldupont 2011

私はそれが理にかなっていると思います。それは、Javaの「String left」などで変数をどのように事前宣言する必要があるのでしょうか。その後、クラスに初期化されたら、値を操作できますか?関数に値を送信するだけで、事前に何も初期化する必要がないため、関数と比較すると少し混乱しています。
Lostsoul

1
@Lostsoul:うまくいくleft = fooだろう-一度。クラスの要点は、すべての異なるために賢明な何かをすることですcrawler。クラスは関数ではなく、関数と比較できるものでもありません(より高度になり、関数型プログラミングに取り掛かるまではそうではありませんが、混乱するでしょう)。クラスが実際に何であるかについて私の答えを読んでください-あなたはまだそれを取得していません。
アマダン、2011

4

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

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

>>> 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] []

しかし、attrとして宣言するとstatic、Pythonのように動作します。

[strange] [strange]

3

あなたの車の例に従ってください:を手に入れたら、ランダムな車を手に入れることはできません。つまり、色、ブランド、座席数などを選択します。また、いくつかのものは選択せずに「初期化」しますホイールの数や登録番号のように。

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

クラスは、そのオブジェクトに固有の属性(状態、特性)とメソッド(関数、容量)を持つオブジェクトです(アヒルの場合はそれぞれ白色とフライパワーなど)。

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

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


2

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

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

いくつかの情報についてはPythonドキュメントをチェックしてください。OOの概念についての本を手に取り、学習を続けることをお勧めします。


1
class Dog(object):

    # Class Object Attribute
    species = 'mammal'

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

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

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__

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.