파이썬 클래스에서 __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 의 이야기 는 ... blah, blah, blah .... 생성자-소멸자이지만 가비지 콜렉션을 사용할 수 있기 때문에 소멸자가 없습니다.
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_sizeFido는 항상 하나이기 때문에 Fido를 계산하는 것은 의미가 없습니다. 개를 세는 것이 합리적입니다. 전 세계에 2 억 마리의 개가 있다고합시다. Dog 클래스의 속성입니다. Fido는 2 억이라는 숫자와 관련이 없으며 Spot도 마찬가지입니다. colour이상인 "인스턴스 속성"과 달리 "클래스 속성"이라고합니다 legs.

이제는 개가 적고 프로그래밍과 관련된 것입니다. 내가 아래에 쓰는 것처럼 물건을 추가하는 클래스는 합리적이지 않습니다. 어떤 클래스입니까? Python의 클래스는 유사하게 작동하는 서로 다른 데이터 모음으로 구성됩니다. 개 종류는 Fido와 Spot 및 그들과 유사한 다른 동물 199999999998로 구성되어 있으며 모두 가로등 기둥에서 오줌 누고 있습니다. 물건을 추가하는 수업은 무엇으로 구성되어 있습니까? 그들에게 내재 된 어떤 데이터가 다른가? 그리고 그들은 어떤 행동을 공유합니까?

하지만 숫자는 ... 더 흥미로운 주제입니다. 정수라고 말하십시오. 개보다 훨씬 많은 것들이 있습니다. 나는 파이썬이 이미 정수를 가지고 있다는 것을 알고 있지만, 바보처럼 놀고 (파이썬의 정수를 속이고 사용함으로써) 그것들을 다시 "구현"합시다.

따라서 정수는 클래스입니다. 일부 데이터 (가치)와 일부 동작 ( "이 다른 숫자에 나를 추가")이 있습니다. 이것을 보여 봅시다 :

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 라고 가정하고 있음) 지금은 무시합니다. 실제 코드에서는 그렇지 않습니다. 우리는 그것을 확인하기 위해 그것을 테스트 할 것이고, 어쩌면 그것을 강요 할 수도 있습니다 ( "당신은 정수가 아닙니다? golly에 의해, 당신은 하나가되는 데 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)

정수보다 분수가 더 많습니다 (실제로는 아니지만 컴퓨터는 그것을 모릅니다). 두 가지를 만들어 보겠습니다.

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"]두 색상을 변수에 쌓았지만 위치 (이 경우 0 또는 1)로 구분합니다.

속성은 개체에 바인딩 된 변수입니다. 배열과 마찬가지로 우리는 다양한 개에 대해 많은 colour변수를 가질 수 있습니다 . 그래서, 하나의 변수이지만 다른 것입니다. 첫 번째는 변수 내의 객체에 바인딩됩니다 . 두 번째, . 전화 할 때 지금 , 나 항상 매개 변수 목록의 전면에 매달려 여분의 하나에 할당됩니다 눈에 보이지 않는 매개 변수가있을 것입니다. 일반적으로라고 하며 점 앞에있는 개체의 값을 가져옵니다. 따라서 Dog 's (생성자) 내에는 새로운 Dog가 무엇이든 될 것입니다. 내 S ' , 변수의 개체에 바인딩됩니다 . 그러므로,fido.colourspot.colourfidospotDog(4, "brown")three.add(five)self__init__selfMyIntegeraddselfthreethree.value에서 add와 같이 외부에서 동일한 변수 self.valueadd됩니다.

내가이라고 말하면 the_mangy_one = fido, 나는 fido또 다른 이름 으로 알려진 물체를 언급하기 시작할 것 입니다. 지금부터 fido.colour정확히 같은 변수입니다 the_mangy_one.colour.

따라서 __init__. 개의 출생 증명서에 주목하는 것으로 생각할 수 있습니다. colour그 자체로 임의의 변수이며 어떤 것도 포함 할 수 있습니다. fido.colour또는 self.colourDog의 ID 시트의 양식 필드와 같습니다. 그리고 __init__처음으로 그것을 작성하는 점원입니다.

더 명확합니까?

편집 : 아래 댓글에 확장 :

당신은 물건 의 목록을 의미 하지 않습니까?

우선, 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)

여기 censusCatclass 의 클래스 수준 속성이 있습니다.

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 함수에서 미리 선언해야합니다. 이 경우 Dog는 다리와 색이 있습니다. 예를 들어, 두 개의 숫자를 추가하는 클래스를 만들면 self.firstnumber와 self.secondnumber를 선언 한 다음 나중에 클래스에서 firstnumber + secondnumber를 수행하여 답을 얻습니까?
Lostsoul 2011

1
거의. 그렇게 할 수 있습니다. 그러나 단지 무언가를 추가하기 위해 수업을 만드는 것은 말이되지 않습니다. 클래스는 일반적으로 동작으로 데이터를 구현합니다. 순수한 동작은 함수일뿐입니다. 관련성있는 것으로 답을 확장하겠습니다. 조금만 기다려주세요.
Amadan 2011

3
놀라운 답변에 감사드립니다. 나는 지금 수업의 힘을보고 이해합니다. 멍청하게 들리면 죄송합니다. 당신은 내가 데이터를 정렬하고 한 번에 많은 다른 것들의 상태를 유지할 수 있다는 것을 깨달았습니다 (반면 나는 루프를 통해 만들 수있는만큼의 변수 만 추적 할 것입니다). 그럼 개당 평균 다리 수를 알아 내야하나요? 이와 같은 계산을 시작할 수 있도록 클래스로 만든 모든 개체의 목록을 검색하는 방법이 있습니까? 또는 내가 만든 클래스 목록을 유지해야합니까 (예 : [fido, spot])
Lostsoul

23

Amadan철저한 설명에 5 센트를 기부 합니다.

클래스는 추상적 인 방식으로 "유형"에 대한 설명입니다. 사물은 그들의 깨달음, 즉 살아있는 호흡입니다. 객체 지향 세계에는 거의 모든 것의 본질이라고 부를 수있는 주요 아이디어가 있습니다. 그들은:

  1. 캡슐화 (이에 대해 자세히 설명하지 않음)
  2. 계승
  3. 다형성

개체에는 하나 이상의 특성 (= 속성)과 동작 (= 메서드)이 있습니다. 동작은 대부분 특성에 따라 다릅니다. 클래스는 동작이 일반적인 방식으로 수행해야하는 것을 정의하지만 클래스가 객체로 실현 (인스턴스화)되지 않는 한 가능성의 추상적 인 개념으로 남아 있습니다. "상속"과 "다형성"의 도움으로 설명하겠습니다.

    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-loop를보세요. 그러나 그들은 개별적인 특성을 드러 낼 것이고 그것은 다형성 (Polymorphism)입니다 (3).

그래서 각 사람은 좋아하는 음료를 가지고 있지만 모든 국적은 특별한 종류의 음료를 선호합니다. Humans 유형에서 국적을 하위 분류하면 위에서 설명한 것처럼 상속 된 동작을 drink()Method 로 덮어 쓸 수 있습니다 . 그러나 그것은 여전히 ​​클래스 수준이고이 때문에 여전히 일반화입니다.

hans = German(favorite_drink = "Cola")

독일어 클래스를 인스턴스화하고 처음에 기본 특성을 "변경"했습니다. (하지만 당신이 hans.drink ( 'Milk')라고 부르면 그는 여전히 "I need more beer"를 인쇄 할 것입니다.-명백한 버그 ... 아니면 제가 더 큰 회사의 직원이라면 이것이 제가 기능이라고 부르는 것일 수도 있습니다. ;-)! )

예를 들어 Germans (hans)와 같은 유형의 특성은 일반적으로 __init__인스턴스화 순간에 생성자 (python :)를 통해 정의됩니다 . 이것은 객체가 될 클래스를 정의하는 지점입니다. 호흡 생명을 개인의 특성으로 채우고 대상이 됨으로써 추상적 인 개념 (클래스)으로 말할 수 있습니다.

그러나 모든 객체는 클래스의 인스턴스이기 때문에 모든 기본 특성 유형과 일부 동작을 공유합니다. 이것은 객체 지향 개념의 주요 이점입니다.

각 개체의 특성을 보호하기 위해 캡슐화합니다. 즉, 동작과 특성을 결합하여 개체 외부에서 조작하기 어렵게 만듭니다. 그것이 캡슐화입니다 (1)


5

인스턴스의 변수를 초기화하는 것입니다.

예를 crawler들어 위의 예에서 특정 데이터베이스 이름 으로 인스턴스를 만듭니다 .


죄송합니다. 그게 무슨 뜻인지 잘 모르겠습니다. 위의 예에서 .. 개발자가 메인 코드 'left = foo'등을 추가 할 수 없었습니다.
Lostsoul

함수의 기본값을 의미합니까? left=Noneleft는 None생성시 left매개 변수가 지정되지 않은 경우로 초기화 됩니다.
jldupont 2011

나는 그것이 이해되기 시작했다고 생각한다. 자바 "String left"또는 뭔가에서 변수를 미리 선언해야하는 것과 같은가? 그런 다음 클래스로 초기화되면 값을 조작 할 수 있습니까? 함수에 값을 보낼 수 있고 미리 아무것도 초기화 할 필요가 없기 때문에 함수와 비교할 때 약간 혼란 스럽습니다.
Lostsoul 2011

1
@Lostsoul : left = foo작동합니다-한 번. 수업의 요점은 모든 다른 사람에 대해 합리적인 일을하는 것 crawler입니다. 클래스는 함수도 아니고 함수와 비교할 수있는 것이 아닙니다. 실제로 수업이 무엇인지에 대한 내 대답을 읽으십시오-여전히 그것을 얻지 못하고 있습니다.
Amadan 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, 파이썬과 같은 역할을합니다 :

[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__(우리 같은 특정 특성을 운반하는 하나 color또는 brand)와 같이, 다른 속성을 생성 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.