본문 바로가기

python tutorial -9 클래스

https://docs.python.org/ko/3/tutorial/classes.html


python tutorial part 9 

클래스 クラス

클래스 : 데이터와 기능을 함께 묶는 방법

クラスはデータと機能を組み合わせる方法を提供します。 


새 클래스를 만드는 것

새  을 만들어서, 그 형의 새 인스턴스를 만들 수 있도록 합니다. 

인스턴스 -어트리뷰트 / 매소드를 가질 수 있음.


新規にクラスを作成することで、新しいオブジェクトの  を作成し、その型を持つ新しい インスタンス が作れます。 

クラスのそれぞれのインスタンスは自身の状態を保持する属性を持てます。

クラスのインスタンスは、その状態を変更するための (そのクラスが定義する) メソッドも持てます。


다른 프로그래밍 언어들과 비교할 때, 


파이썬은 최소한의 새로운 문법과 개념을 써서 클래스를 추가

C++ 과 모듈라-3혼합

객체 지향기능제공

다중 베이스 클래스 상속

자식 클래스는 메소드 재정의 가능 

메소드는 부모 클래스의 메소드 호출가능


객체들은 임의의 종류의 데이터를 양적 제한 없이 가질 수 있습니다. 

모듈과 마찬가지로, 클래스는 파이썬의 동적인 본성을 함께 나눕니다: 

실행 시간에 만들어지고, 만들어진 후에도 더 수정될 수 있습니다.


Python は、他のプログラミング言語と比較して、最小限の構文と意味付けを使ってクラスを言語に追加しています。

Python のクラスは、C++ と Modula-3 のクラスメカニズムを混ぜたものです。

Python のクラス機構はオブジェクト指向プログラミングの標準的な機能を全て提供しています。

クラスの継承メカニズムは、複数の基底クラスを持つことができ、派生クラスで基底クラスの任意のメソッドをオーバライドすることができます。

メソッドでは、基底クラスのメソッドを同じ名前で呼び出すことができます。

オブジェクトには任意の種類と数のデータを格納することができます。

モジュールと同じく、クラス機構も Python の動的な性質に従うように設計されています。

クラスは実行時に生成され、生成後に変更することができます。


C++ 용어로, 보통 클래스 멤버들은 (데이터 멤버를 포함해서) public (예외는 아래 비공개 변수 를 보세요) 하고, 모든 맴버 함수들은 virtual 입니다. 모듈라-3처럼, 객체의 매소드에서 그 객체의 멤버를 참조하는 줄임 표현은 없습니다: 

메서드 함수는 그 객체를 표현하는 명시적인 첫 번째 인자를 선언하는데, 함수 호출 때 묵시적으로 제공됩니다. 스몰토크처럼, 클래스 자신도 객체입니다. 이것이 임포팅과 이름 변경을 위한 개념을 제공합니다. C++ 나 모듈라-3 와는 달리, 내장형도 사용자가 확장하기 위해 베이스 클래스로 사용할 수 있습니다. 또한, C++ 처럼, 특별한 문법을 갖는 대부분의 내장 연산자들은 (산술 연산자, 서브스크립팅, 등등) 클래스 인스턴스에 대해 새로 정의될 수 있습니다.


(클래스에 대해 보편적으로 받아들여지는 용어들이 없는 상태에서, 이따금 스몰토크나 C++ 용어들을 사용할 것입니다. C++ 보다 객체 지향적 개념들이 파이썬의 것과 더 가까우므로 모듈라-3 용어를 사용할 수도 있지만, 들어본 독자들이 별로 없을 것으로 예상합니다.)


C++ の用語で言えば、通常のクラスメンバ (データメンバも含む) は (プライベート変数 に書かれている例外を除いて) publicであり、メンバ関数はすべて 仮想関数(virtual) です。 Modula-3 にあるような、オブジェクトのメンバをメソッドから参照するための短縮した記法は使えません: メソッド関数の宣言では、オブジェクト自体を表す第一引数を明示しなければなりません。第一引数のオブジェクトはメソッド呼び出しの際に暗黙の引数として渡されます。 Smalltalk に似て、クラスはそれ自体がオブジェクトです。そのため、 import や名前変更といった操作が可能です。 C++ や Modula-3 と違って、ユーザーは組込み型を基底クラスにして拡張を行えます。また、C++ とは同じで Modula-3 とは違う点として、特別な構文を伴うほとんどの組み込み演算子 (算術演算子 (arithmetic operator) や添字表記) はクラスインスタンスで使うために再定義できます。


(クラスに関して普遍的な用語定義がないので、 Smalltalk と C++ の用語を場合に応じて使っていくことにします。 C++ よりも Modula-3 の方がオブジェクト指向の意味論が Python に近いので、 Modula-3 の用語を使いたいのですが、ほとんどの読者は Modula-3 についてしらないでしょうから。)




9.1. 이름과 객체(오브젝트) 名前とオブジェクトについて


객체

개체성(individuality)

여러 이름이 같은 객체에 연결될 수 있습니다. 에일리어싱(aliasing)

불변 기본형들 (숫자, 문자열, 튜플)을 다루는 동안은 안전하게 무시할 수 있습니다. 


オブジェクトには個体性があり、同一のオブジェクトに(複数のスコープから) 複数の名前を割り当てることができます。この機能は他の言語では別名づけ(alias) として知られています。 

Python を一見しただけでは、別名づけの重要性は分からないことが多く、

変更不能な基本型 (数値、文字列、タプル)を扱うときには無視して差し支えありません。



에일리어싱

리스트, 딕셔너리나 그 밖의 다른 가변 객체들 -> 포인터처럼 


しかしながら、別名付けは、リストや辞書や他の多くの型など、

変更可能な型を扱う Python コード上で驚くべき効果があります。

別名付けはいくつかの点でポインタのように振舞い、このことは通常はプログラムに利するように使われます。


예를 들어, 

구현이 포인터만 전달하기 때문에, 

객체를 전달하는 비용이 적게 듭니다; 


그리고 함수가 인자로 전달된 객체를 수정하면, 

호출자는 그 변경을 보게 됩니다


例えば、オブジェクトの受け渡しは、実装上はポインタが渡されるだけなのでコストの低い操作になります。また、関数があるオブジェクトを引数として渡されたとき、関数の呼び出し側からオブジェクトに対する変更を見ることができます




9.2. 파이썬 스코프와 이름 공간  Python のスコープと名前空間


 파이썬 스코프 규칙


이름 공간 은 이름에서 객체로 가는 매핑입니다. 

이름 공간 딕셔너리로 구현


이름 공간의 예

내장 이름들의 집합

모듈의 전역 이름 

함수 호출에서의 지역 이름

객체의 어트리뷰트 집합


이름 공간 중요한 것

서로 다른 이름 공간들의 이름 간에는 아무런 관계가 없다는 것

예를 들어, 두 개의 서로 다른 모듈들은 모두 혼동 없이 함수 maximize 를 정의할 수 있음.


名前空間 (namespace) とは、名前からオブジェクトへの対応付け (mapping) です

ほとんどの名前空間は、現状では Python の辞書として実装されていますが、そのことは通常は (パフォーマンス以外では) 目立つことはないし、将来は変更されるかもしれません。


名前空間の例には、

組込み名の集合 (abs() 等の関数や組込み例外名)、

モジュール内のグローバルな名前

関数を呼び出したときのローカルな名前があります。

オブジェクトの属性からなる集合もまた、ある意味では名前空間です。


名前空間について知っておくべき重要なことは、

異なった名前空間にある名前の間には全く関係がないということです。

例えば、二つの別々のモジュールの両方で関数 maximize という関数を定義することができ、定義自体は混同されることはありません --- モジュールのユーザは名前の前にモジュール名をつけなければなりません。


어트리뷰트 는 점 뒤에 오는 이름 

--- 예를 들어, 

표현식 z.real 에서, real 는 객체 z 의 어트리뷰트입니다. 

모듈에 있는 이름들에 대한 참조는 어트리뷰트 참조입니다:

표현식 modname.funcname 에서, modname 은 모듈 객체고 funcname 는 어트리뷰트입니다. 


 모듈의 어트리뷰트 -  모듈의 전역 이름 간 매핑 : 같은 이름 공간을 공유합니다! [1]


ところで、 属性 という言葉は、ドットに続く名前すべてに対して使っています --- 

例えば式 z.real で、 real はオブジェクト z の属性です。


厳密にいえば、モジュール内の名前に対する参照は属性の参照です。

式 modname.funcname では、 modname はあるモジュールオブジェクトで、 funcname はその属性です。

この場合には、モジュールの属性とモジュールの中で定義されているグローバル名の間には、直接的な対応付けがされます。

これらの名前は同じ名前空間を共有しているのです! [1]


[1]한 가지만 제외하고. 모듈 객체는 __dict__ 라고 불리는 비밀스러운 읽기 전용 어트리뷰트를 갖는데, 모듈의 이름 공간을 구현하는데 사용하는 딕셔너리를 돌려줍니다; 이름 __dict__ 는 어트리뷰트 이지만 전역 이름은 아닙니다. 명백하게, 이것을 사용하는 것은 이름 공간 구현의 추상화를 파괴하는 것이고, 사후 디버거와 같은 것들로만 제한되어야 합니다.
[1]例外が一つあります。モジュールオブジェクトには、秘密の読取り専用の属性 __dict__ があり、モジュールの名前空間を実装するために使われている辞書を返します; __dict__ という名前は属性ですが、グローバルな名前ではありません。この属性を利用すると名前空間の実装に対する抽象化を侵すことになるので、プログラムを検死するデバッガのような用途に限るべきです。


어트리뷰트 :  읽기 전용 / 쓰기

모듈 어트리뷰트 : 쓰기 가능 :  modname.the_answer = 42 

del 문: 삭제 : del modname.the_answer : modname 의 the_answer 삭제


属性は読取り専用にも、書込み可能にもできます。

書込み可能であれば、属性に代入することができます。

モジュール属性は書込み可能で、 modname.the_answer = 42 と書くことができます。

書込み可能な属性は、 del 文で削除することもできます。

例えば、 del modname.the_answer は、 modname で指定されたオブジェクトから属性 the_answer を除去します。



이름 공간 - 서로 다른 수명


내장 이름 공간 - 인터프리터 시작할 때 만들어지고 영원히 지워지지 않습니다. 


모듈 전역 이름 공간 - 모듈 정의를 읽는 동안 - 인터프리터가 끝날 때까지 남습니다. 

인터프리터의 최상위 호출 때문에 실행되는, 스크립트 파일이나 대화형으로 읽히는, 문장

들은 __main__ 이라고 불리는 모듈 일부로 여겨져서 그 들 자신의 이름 공간을 갖습니다. 

(내장 이름들 또한 모듈에 속하는데; 이것을 builtins 라 부릅니다.)


名前空間は様々な時点で作成され、その寿命も様々です。

組み込みの名前が入った名前空間は Python インタプリタが起動するときに作成され、決して削除されることはありません。

モジュールのグローバルな名前空間は、モジュール定義が読み込まれたときに作成されます。


通常、モジュールの名前空間は、インタプリタが終了するまで残ります。インタプリタのトップレベルで実行された文は、スクリプトファイルから読み出されたものでも対話的に読み出されたものでも、 __main__ という名前のモジュールの一部分であるとみなされるので、独自の名前空間を持つことになります。 (組み込みの名前は実際にはモジュール内に存在します。そのモジュールは builtins と呼ばれています。)



함수의 지역 이름 공간

함수가 호출될 때 - 함수가 복귀 /예외를 일으킬 때 삭제

(사실, 잊어버린다는 것이 실제로 일어나는 일에 대한 더 좋은 설명입니다.) 

재귀적 호출은 각각 자기 자신만의 지역 이름 공간을 갖습니다.


関数のローカルな名前空間は、関数が呼び出されたときに作成され、関数から戻ったときや、関数内で例外が送出され、かつ関数内で処理されなかった場合に削除されます。 (実際には、忘れられる、と言ったほうが起きていることをよく表しています。) もちろん、再帰呼出しのときには、各々の呼び出しで各自のローカルな名前空間があります。



스코프 

이름 공간을 직접 액세스할 수 있는 파이썬 프로그램의 텍스트 적인 영역

 "직접 액세스 가능한" 이란 이름에 대한 정규화되지 않은 참조가 그 이름 공간에서 이름을 찾으려고 시도한다는 의미

스코프가 정적으로 결정됨에도 불구하고, 동적으로 사용

실행 중 어느 시점에서건, 이름 공간을 직접 액세스 가능한, 적어도 세 개의 중첩된 스코프가 있습니다:


スコープ (scope) とは、

ある名前空間が直接アクセスできるような、Python プログラムのテキスト上の領域です。

 "直接アクセス可能" とは、修飾なしに (訳注: spam.egg ではなく単に eggのように) 名前を参照した際に、

その名前空間から名前を見つけようと試みることを意味します。


  • 가장 먼저 검색되는, 가장 내부의 스코프는 지역 이름들을 포함합니다
  • 둘러싸고 있는 함수들의 스코프는, 가장 가까이서 둘러싸는 스코프로부터 검색이 시작됩니다, 비 지역(non-local) 이지만 비 전역(non-global) 이름들을 포함합니다
  • 마지막 직전의 스코프는 현재 모듈의 전역 이름들을 포함합니다
  • (가장 나중에 검색되는) 가장 외부의 스코프는 내장 이름들을 포함하고 있는 이름 공간입니다.
  • 最初に探される、最も内側のスコープは、ローカルな名前を持っています。
  • 外側の(enclosing)関数のスコープは、近いほうから順に探され、ローカルでもグローバルでもない名前を持っています。
  • 次のスコープは、現在のモジュールのグローバルな名前を持っています。
  • 一番外側の(最後に検索される)スコープはビルトイン名を持っています。

이름을 global로 선언하면, 모든 참조와 대입은 모듈의 전역 이름들을 포함하는 중간 스코프로 바로 갑니다. 가장 내부의 스코프 바깥에서 발견되는 변수들을 재연결하려면, nonlocal 키워드를 사용할 수 있습니다; nonlocal 로 선언되지 않으면, 그 변수들은 읽기 전용입니다 (그런 변수에 쓰려고 하면 단순히 가장 내부의 스코프에  지역 변수를 만들게 되어, 같은 이름의 바깥 변수를 바꾸지 않고 남겨둡니다).


名前が global と宣言されている場合、その名前に対する参照や代入は全て、モジュールのグローバルな名前の入った中間のスコープに対して直接行われます。最内スコープの外側にある変数に再束縛するには、 nonlocal 文が使えます。nonlocal と宣言されなかった変数は、全て読み出し専用となります (そのような変数に対する書き込みは、単に 新しい ローカル変数をもっとも内側のスコープで作成し、外部のスコープの値は変化しません)。



보통, 지역 스코프는 현재 함수의 지역 이름들을 (텍스트 적으로) 참조합니다. 

함수 바깥에서, 지역 스코프는 전역 스코프와 같은 이름 공간을 참조합니다: 

모듈의 이름 공간. 클래스 정의들은 지역 스코프에 또 하나의 이름 공간을 배치합니다.


通常、ローカルスコープは (プログラムテキスト上の) 現在の関数のローカルな名前を参照します。関数の外側では、ローカルスコープはグローバルな名前空間と同じ名前空間、モジュールの名前空間を参照します。クラス定義では、ローカルスコープの中にもう一つ名前空間が置かれます。



스코프가 텍스트 적으로 결정된다는 것을 깨닫는 것은 중요합니다: 모듈에서 정의된 함수의 전역 스코프는, 어디에서 어떤 에일리어스를 통해 그 함수가 호출되는지에 관계없이, 그 모듈의 이름 공간입니다. 반면에, 이름을 실제로 검색하는 것은 실행시간에 동적으로 수행됩니다 --- 하지만, 언어 정의는 컴파일 시점의 정적인 이름 결정을 향해 진화하고 있어서, 동적인 이름 결정에 의존하지 말아야 합니다! (사실, 지역 변수들은 이미 정적으로 결정됩니다.)


スコープはテキスト上で決定されていると理解することが重要です。モジュール内で定義される関数のグローバルなスコープは、関数がどこから呼び出されても、どんな別名をつけて呼び出されても、そのモジュールの名前空間になります。反対に、実際の名前の検索は実行時に動的に行われます --- とはいえ、言語の定義は、"コンパイル" 時の静的な名前解決の方向に進化しているので、動的な名前解決に頼ってはいけません! (事実、ローカルな変数は既に静的に決定されています。)



파이썬의 특별한 특징은 -- global 문이 없을 때 -- 이름에 대입하면 항상 가장 내부의 스코프로 간다는 것입니다. 대입은 데이터를 복사하지 않습니다 -- 이름을 단지 객체에 연결할 뿐입니다. 삭제도 마찬가지입니다: 문장 del x 는 지역 스코프가 참조하는 이름 공간에서 x 의 연결을 제거합니다. 사실, 새 이름을 소개하는 모든 연산은 지역 스코프를 사용합니다: 특히, import 문과 함수 정의는 모듈이나 함수 이름을 지역 스코프에 연결합니다.


Python 特有の癖として、代入を行うと -- どの global 文も有効でない場合は -- 名前がいつも最も内側のスコープに入るというものがあります。代入はデータのコピーを行いません --- 単に名前をオブジェクトに結びつける (bind) だけです。オブジェクトの削除でも同じです: del x は、 x をローカルスコープが参照している名前空間から削除します。実際、新たな名前を導入する操作は全てローカルスコープを用います。とりわけ、 import文や関数定義は、モジュールや関数の名前をローカルスコープに結び付けます。



global 문은 특정 변수가 전역 스코프에 있으며 그곳에 재연결되어야 함을 가리킬 때 사용될 수 있습니다; nonlocal 문은 특정 변수가 둘러싸는 스코프에 있으며 그곳에 재연결되어야 함을 가리킵니다.


global 文を使うと、特定の変数がグローバルスコープに存在し、そこで再束縛されることを指示できます。 nonlocal 文は、特定の変数が外側のスコープに存在し、そこで再束縛されることを指示します。



9.2.1. 스코프와 이름 공간 예 スコープと名前空間の例

이것은 어떻게 서로 다른 스코프와 이름 공간을 참조하고, global과 nonlocal 이 변수 연결에 어떤 영향을 주는지를 보여주는 예입니다:


異なるスコープと名前空間がどのように参照されるか、また global および nonlocal が変数の束縛にどう影響するか、この例で実演します:


def scope_test():
    def do_local():
        spam = "local spam"

    def do_nonlocal():
        nonlocal spam
        spam = "nonlocal spam"

    def do_global():
        global spam
        spam = "global spam"

    spam = "test spam"
    do_local()
    print("After local assignment:", spam)
    do_nonlocal()
    print("After nonlocal assignment:", spam)
    do_global()
    print("After global assignment:", spam)

scope_test()
print("In global scope:", spam)

예제 코드의 출력은 이렇게 됩니다:

このコード例の出力は:

After local assignment: test spam
After nonlocal assignment: nonlocal spam
After global assignment: nonlocal spam
In global scope: global spam

어떻게 지역 대입이 (이것이 기본입니다) scope_test 의 spam 연결을 바꾸지 않는지에 유의하세요. nonlocal 대입은 scope_test의 spam 연결을 바꾸고 global 대입은 모듈 수준의 연결을 바꿉니다.

global 대입 전에는 spam 의 연결이 없다는 것도 볼 수 있습니다.


このとおり、(デフォルトの) ローカルな 代入は scope_test 上の spam への束縛を変更しませんでした。 nonlocal 代入は scope_test 上の spam への束縛を変更し、 global 代入はモジュールレベルの束縛を変更しました。

またここから、 global 代入の前には spam に何も束縛されていなかったことも分かります。


9.3. 클래스와의 첫 만남 クラス初見

클래스는 약간의 새 문법과 세 개의 객체형과 몇 가지 새 개념들을 도입합니다.

クラスでは、新しい構文を少しと、三つの新たなオブジェクト型、そして新たな意味付けをいくつか取り入れています。


9.3.1. 클래스 정의 문법 クラス定義の構文

클래스 정의의 가장 간단한 형태는 이렇게 생겼습니다:

クラス定義の最も単純な形式は、次のようになります:

class ClassName:
    <statement-1>
    .
    .
    .
    <statement-N>

함수 정의(def 문)처럼, 클래스 정의는 어떤 효과가 생기기 위해서는 먼저 실행되어야 합니다. (상상컨대 클래스 정의를 if 문의 분기나 함수 내부에 놓을 수 있습니다)


関数定義 (def 文) と同様、クラス定義が効果をもつにはまず実行しなければなりません。 (クラス定義を if 文の分岐先や関数内部に置くことも、考え方としてはありえます。)



실재적으로, 클래스 정의 내부의 문장들은 보통 함수 정의들이지만, 다른 문장들도 허락되고 때로 쓸모가 있습니다 --- 나중에 이 주제로 돌아올 것입니다. 클래스 내부의 함수 정의는 보통, 메서드 호출 규약의 영향을 받은, 특별한 형태의 인자 목록을 갖습니다. --- 다시, 이것은 뒤에서 설명됩니다.


実際には、クラス定義の内側にある文は、通常は関数定義になりますが、他の文を書くこともでき、それが役に立つこともあります --- これについては後で述べます。クラス内の関数定義は通常、メソッドの呼び出し規約で決められた独特の形式の引数リストを持ちます --- これについても後で述べます。



클래스 정의에 진입할 때, 새 이름 공간이 만들어지고 지역 스코프로 사용됩니다 --- 그래서, 모든 지역 변수들로의 대입은 이 새 이름 공간으로 갑니다. 특히, 함수 정의는 새 함수의 이름을 이곳에 연결합니다.


クラス定義に入ると、新たな名前空間が作成され、ローカルな名前空間として使われます --- 従って、ローカルな変数に対する全ての代入はこの新たな名前空間に入ります。特に、関数定義を行うと、新たな関数の名前はこの名前空間に結び付けられます。



클래스 정의가 (끝을 통해) 정상적으로 끝날 때, 클래스 객체 가 만들어집니다. 이것은 기본적으로 클래스 정의 때문에 만들어진 이름 공간의 내용물들을 감싸는 싸개입니다; 다음 섹션에서 클래스 객체에 대해 더 배우게 됩니다. 원래의 지역 스코프가 (클래스 정의에 들어가기 직전에 유효하던 것) 다시 사용되고, 클래스 객체는 클래스 정의 헤더에서 주어진 클래스 이름 (예에서 ClassName) 으로 여기에 연결됩니다.


クラス定義から普通に (定義の終端に到達して) 抜けると、 クラスオブジェクト (class object) が生成されます。クラスオブジェクトは、基本的にはクラス定義で作成された名前空間の内容をくるむラッパ (wrapper) です。クラスオブジェクトについては次の節で詳しく学ぶことにします。 (クラス定義に入る前に有効だった) 元のローカルスコープが復帰し、生成されたクラスオブジェクトは復帰したローカルスコープにクラス定義のヘッダで指定した名前 (上の例では ClassName) で結び付けられます。



9.3.2. 클래스 객체 クラスオブジェクト

클래스 객체는 두 종류의 연산을 지원합니다: 어트리뷰트 참조와 인스턴스 만들기.

クラス・オブジェクトでは2種類の演算、属性参照とインスタンス生成をサポートしています。


어트리뷰트 참조 는 파이썬의 모든 어트리뷰트 참조에 사용되는 표준 문법을 사용합니다: obj.name. 올바른 어트리뷰트 이름은 클래스 객체가 만들어질 때 클래스의 이름 공간에 있던 모든 이름입니다. 그래서, 클래스 정의가 이렇게 될 때:


属性参照 (attribute reference) は、Python におけるすべての属性参照で使われている標準的な構文、 obj.name を使います。クラスオブジェクトが生成された際にクラスの名前空間にあった名前すべてが有効な属性名です。従って、以下のようなクラス定義では:


class MyClass:
    """A simple example class"""
    i = 12345

    def f(self):
        return 'hello world'

MyClass.i 와 MyClass.f 는 올바른 어트리뷰트 참조고, 각기 정수와 함수 객체를 돌려줍니다. 클래스 어트리뷰트는 대입할 수도 있어서, 대입을 통해 MyClass.i 의 값을 변경할 수 있습니다. __doc__ 도 역시 올바른 어트리뷰트고, 클래스에 속하는 독스트링을 돌려줍니다: "A simple example class".


MyClass.i と MyClass.f は妥当な属性参照であり、それぞれ整数と関数オブジェクトを返します。クラス属性に代入を行うこともできます。従って、 MyClass.i の値を代入して変更できます。 __doc__ も有効な属性で、そのクラスに属している docstring、この場合は "A simple example class" を返します。



클래스 인스턴스 만들기 는 함수 표기법을 사용합니다. 클래스 객체가 클래스의 새 인스턴스를 돌려주는 매개변수 없는 함수인 체합니다. 예를 들어 (위의 클래스를 가정하면):


クラスの インスタンス化 (instantiation) には関数のような表記法を使います。クラスオブジェクトのことを、単にクラスの新しいインスタンスを返す引数がない関数のように振る舞います。例えば (上記のクラスでいえば):


x = MyClass()

는 클래스의 새 인스턴스 를 만들고 이 객체를 지역 변수 x 에 대입합니다.

は、クラスの新しい インスタンス (instance) を生成し、そのオブジェクトをローカル変数 x へ代入します。


인스턴스 만들기 연산 (클래스 객체 "호출하기") 은 빈 객체를 만듭니다. 많은 클래스는 특정한 초기 상태로 커스터마이즈된 인스턴스로 객체를 만드는 것을 좋아합니다. 그래서 클래스는 이런 식으로 __init__() 라는 이름의 특수 메서드 정의할 수 있습니다:

このクラスのインスタンス生成操作 (クラスオブジェクトの "呼出し") を行うと、空のオブジェクトを生成します。多くのクラスは、オブジェクトを作成する際に、カスタマイズされた特定の初期状態になってほしいと望んでいます。そのために、クラスには __init__() という名前の特別なメソッド定義することができます。例えば次のようにします:


def __init__(self):
    self.data = []

클래스가 __init__() 메서드를 정의할 때, 클래스 인스턴스 만들기는 새로 만들어진 클래스 인스턴스에 대해 자동으로 __init__() 를 호출합니다. 그래서 이 예에서, 새 초기화된 인스턴스를 이렇게 얻을 수 있습니다:


クラスが __init__() メソッドを定義している場合、クラスのインスタンスを生成すると、新しく生成されたクラスインスタンスに対して自動的に __init__() を呼び出します。従って、この例では、新たな初期済みのインスタンスを次のようにして得ることができます:

x = MyClass()

물론, __init__() 메서드는 더 높은 유연성을 위해 인자들을 가질 수 있습니다. 그 경우, 클래스 인스턴스 만들기 연산자로 주어진 인자들은 __init__() 로 전달됩니다. 예를 들어,


もちろん、より大きな柔軟性を持たせるために、 __init__() メソッドに複数の引数をもたせることができます。その場合、次の例のように、クラスのインスタンス生成操作に渡された引数は __init__() に渡されます。例えば、


>>>
>>> class Complex:
...     def __init__(self, realpart, imagpart):
...         self.r = realpart
...         self.i = imagpart
...
>>> x = Complex(3.0, -4.5)
>>> x.r, x.i
(3.0, -4.5)

9.3.3. 인스턴스 객체 インスタンスオブジェクト

이제 인스턴스 객체로 무엇을 할 수 있을까? 인스턴스 객체가 이해하는 오직 한가지 연산은 어트리뷰트 참조입니다. 두 가지 종류의 올바른 어트리뷰트 이름이 있습니다, 데이터 어트리뷰트와 메서드.


ところで、インスタンスオブジェクトを使うと何ができるのでしょうか?インスタンスオブジェクトが理解できる唯一の操作は、属性の参照です。有効な属性の名前には二種類(データ属性およびメソッド)あります。



데이터 어트리뷰트 는 스몰토크의 "인스턴스 변수" 에, C++ 의 "데이터 멤버" 에 해당합니다. 데이터 어트리뷰트는 선언될 필요 없습니다; 지역 변수처럼, 처음 대입될 때 태어납니다. 예를 들어, x 가 위에서 만들어진 MyClass 의 인스턴스면, 다음과 같은 코드 조각은 트레이스 없이 값 16 을 인쇄합니다:


データ属性 (data attribute) は、これは Smalltalk の "インスタンス変数" や C++の "データメンバ" に相当します。データ属性を宣言する必要はありません。ローカルな変数と同様に、これらの属性は最初に代入された時点で湧き出てきます。例えば、上で生成した MyClass のインスタンス x に対して、次のコードを実行すると、値 16 を印字し、 x の痕跡は残りません:


x.counter = 1
while x.counter < 10:
    x.counter = x.counter * 2
print(x.counter)
del x.counter

다른 인스턴스 어트리뷰트 참조는 메서드 입니다. 메서드는 객체에 "속하는" 함수입니다. (파이썬에서, 메서드 라는 용어는 클래스 인스턴스에만 사용되지 않습니다; 다른 객체 형들도 메서드를 가질 수 있습니다. 예를 들어, 리스트 객체는 append, insert, remove, sort 등과 같은 메서드들을 갖습니다. 하지만, 앞으로의 논의에서, 명시적으로 언급하지 않는 한, 메서드 라는 용어를 클래스 인스턴스 객체의 메서드에만 사용할 것입니다.)


もうひとつのインスタンス属性は メソッド (method) です。メソッドとは、オブジェクトに "属している" 関数のことです。(Python では、メソッドという用語はクラスインスタンスだけのものではありません。オブジェクト型にもメソッドを持つことができます。例えば、リストオブジェクトには、 append, insert, remove, sort などといったメソッドがあります。とはいえ、以下では特に明記しない限り、クラスのインスタンスオブジェクトのメソッドだけを意味するものとして使うことにします。)



인스턴스 객체의 올바른 메서드 이름은 그것의 클래스에 달려있습니다. 정의상, 함수 객체인 클래스의 모든 어트리뷰트들은 상응하는 인스턴스의 메서드들을 정의합니다. 그래서 우리의 예제에서, x.f 는 올바른 메서드 참조인데, MyClass.f 가 함수이기 때문입니다. 하지만 x.i 는 그렇지 않은데, MyClass.i 가 함수가 아니기 때문입니다. 그러나, x.f 는 MyClass.f 와 같은 것이 아닙니다 --- 이것은 함수 객체가 아니라 메서드 객체 입니다.


インスタンスオブジェクトで有効なメソッド名は、そのクラスによります。定義により、クラスの全ての関数オブジェクトである属性がインスタンスオブジェクトの妥当なメソッド名に決まります。従って、例では、MyClass.f は関数なので、x.f はメソッドの参照として有効です。しかし、MyClass.i は関数ではないので、x.i はメソッドの参照として有効ではありません。x.f は MyClass.f と同じものではありません --- 関数オブジェクトではなく、メソッドオブジェクト (method object) です。



9.3.4. 메서드 객체 メソッドオブジェクト

보통, 메서드는 연결되자마자 호출됩니다:

普通、メソッドはバインドされた直後に呼び出されます:

x.f()

MyClass 예에서, 이것은 문자열 'hello world' 를 돌려줍니다. 하지만, 메서드를 즉시 호출할 필요는 없습니다: x.f 는 메서드 객체고, 저장된 후에 호출될 수 있습니다. 예를 들어:


MyClass の例では、上のコードは文字列 'hello world' を返すでしょう。しかしながら、必ずしもメソッドをその場で呼び出さなければならないわけではありません。 x.f はメソッドオブジェクトであり、どこかに記憶しておいて後で呼び出すことができます。例えば次のコードは:

xf = x.f
while True:
    print(xf())

는 영원히 계속 hello world 를 인쇄합니다.

hello world を時が終わるまで印字し続けるでしょう。


메서드가 호출될 때 정확히 어떤 일이 일어날까? f() 의 함수 정의가 인자를 지정했음에도 불구하고, 위에서 x.f() 는 인자 없이 호출된 것을 알아챘을 것입니다. 인자는 어떻게 된 걸까? 확실히 파이썬은 인자를 필요로 하는 함수를 인자 없이 호출하면 예외를 일으킵니다 -- 인자가 실제로는 사용되지 않는다 해도...


メソッドが呼び出されるときには実際には何が起きているのでしょうか? f() の関数定義では引数を一つ指定していたにもかかわらず、上の例では x.f() が引数なしで呼び出されています。引数はどうなったのでしょうか?たしか、引数が必要な関数を引数無しで呼び出すと、 Python が例外を送出するはずです --- たとえその引数が実際には使われなくても…。



실제로, 여러분은 답을 짐작할 수 있습니다: 메서드의 특별함은 인스턴스 객체가 함수의 첫 번째 인자로 전달된다는 것입니다. 우리 예에서, 호출 x.f()``은 정확히 ``MyClass.f(x) 와 동등합니다. 일반적으로, n 개의 인자들의 목록으로 메서드를 호출하는 것은, 첫 번째 인자 앞에 메서드의 인스턴스 객체를 삽입해서 만든 인자 목록으로 상응하는 함수를 호출하는 것과 동등합니다.


もう答は想像できているかもしれませんね: メソッドについて特別なこととして、インスタンスオブジェクトが関数の第1引数として渡されます。 例では、 x.f() という呼び出しは、 MyClass.f(x) と厳密に等価なものです。 一般に、 n 個の引数リストもったメソッドの呼出しは、そのメソッドのインスタンスオブジェクトを最初の引数の前に挿入した引数リストで、メソッドに対応する関数を呼び出すことと等価です。



아직 메서드가 어떻게 동작하는지 이해하지 못했다면, 구현을 살펴보는 것이 아마도 문제를 분명하게 만들 수 있을 것입니다. 데이터 어트리뷰트가 아닌 인스턴스 어트리뷰트를 참조하면, 그것의 클래스가 검색됩니다. 만약 그 이름이 함수 객체인 올바른 클래스 어트리뷰트면, 인스턴스 객체와 방금 발견된 함수 객체를 (가리키는 포인터들을) 추상 객체에 함께 묶어서 메서드 객체를 만듭니다: 이것이 메서드 객체입니다. 메서드 객체가 인자 목록으로 호출되면, 인스턴스 객체와 인자 목록으로부터 새 인자 목록이 구성된 후, 함수 객체를 이 새 인자 목록으로 호출합니다.


もしまだメソッドの動作を理解できなければ、一度実装を見てみると事情がよく分かるかもしれません。インスタンスの非データ属性が参照されたときは、そのインスタンスのクラスが検索されます。その名前が有効なクラス属性を表している関数オブジェクトなら、インスタンスオブジェクトと見つかった関数オブジェクト (へのポインタ) を抽象オブジェクト、すなわちメソッドオブジェクトにパックして作成します。メソッドオブジェクトが引数リストと共に呼び出されるとき、インスタンスオブジェクトと渡された引数リストから新しい引数リストを作成して、元の関数オブジェクトを新しい引数リストで呼び出します。



9.3.5. 클래스와 인스턴스 변수 クラスとインスタンス変数

일반적으로 말해서, 인스턴스 변수는 인스턴스별 데이터를 위한 것이고 클래스 변수는 그 클래스의 모든 인스턴스에서 공유되는 어트리뷰트와 메서드를 위한 것입니다:

一般的に、インスタンス変数はそれぞれのインスタンスについて固有のデータのためのもので、クラス変数はそのクラスのすべてのインスタンスによって共有される属性やメソッドのためのものです:

class Dog:

    kind = 'canine'         # class variable shared by all instances

    def __init__(self, name):
        self.name = name    # instance variable unique to each instance

>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.kind                  # shared by all dogs
'canine'
>>> e.kind                  # shared by all dogs
'canine'
>>> d.name                  # unique to d
'Fido'
>>> e.name                  # unique to e
'Buddy'

이름과 객체에 관한 한마디 에서 논의했듯이, 리스트나 딕셔너리와 같은 가변 객체가 참여할 때 공유 데이터는 예상치 못한 효과를 줄 가능성이 있습니다. 예를 들어, 다음 코드에서 tricks 리스트는 클래스 변수로 사용되지 않아야 하는데, 하나의 리스트가 모든 Dog 인스턴스들에 공유되기 때문입니다.


名前とオブジェクトについて で議論したように、共有データはリストや辞書のような mutable オブジェクトが関与すると驚くべき効果を持ち得ます。例えば、以下のコードの tricks リストはクラス変数として使われるべきではありません、なぜならたった一つのリストがすべての Dog インスタンスによって共有されることになり得るからです:

class Dog:

    tricks = []             # mistaken use of a class variable

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

    def add_trick(self, trick):
        self.tricks.append(trick)

>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.add_trick('roll over')
>>> e.add_trick('play dead')
>>> d.tricks                # unexpectedly shared by all dogs
['roll over', 'play dead']

대신, 클래스의 올바른 설계는 인스턴스 변수를 사용해야 합니다:

このクラスの正しい設計ではインスタンス変数を代わりに使用するべきです:

class Dog:

    def __init__(self, name):
        self.name = name
        self.tricks = []    # creates a new empty list for each dog

    def add_trick(self, trick):
        self.tricks.append(trick)

>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.add_trick('roll over')
>>> e.add_trick('play dead')
>>> d.tricks
['roll over']
>>> e.tricks
['play dead']

9.4. 기타 주의사항들 いろいろな注意点

데이터 어트리뷰트는 같은 이름의 메서드 어트리뷰트를 덮어씁니다; 의도하지 않은 이름 충돌(큰 프로그램에서 찾기 어려운 버그를 만듭니다)을 피하려면, 충돌의 기회를 최소화하는 어떤 종류의 규칙을 사용하는 것이 현명합니다. 가능한 규칙에는 메서드 이름을 대문자로 시작하는 것, 데이터 어트리뷰트의 이름에 작고 특별한 문자열 (아마도 밑줄 하나)을 앞에 붙이는 것, 메서드에는 동사를 데이터 어트리뷰트에는 명사를 쓰는 것들이 있습니다.


データ属性は同じ名前のメソッド属性を上書きしてしまいます。大規模なプログラムでみつけにくいバグを引き起こすことがあるこの偶然的な名前の衝突を避けるには、衝突の可能性を最小限にするような規約を使うのが賢明です。可能な規約としては、メソッド名を大文字で始める、データ属性名の先頭に短い一意な文字列 (あるいはただの下線) をつける、またメソッドには動詞、データ属性には名詞を用いる、などがあります。



데이터 어트리뷰트는 메서드 뿐만 아니라 객체의 일반적인 사용자 ("클라이언트")에 의해서 참조될 수도 있습니다. 달리 표현하면, 클래스는 순수하게 추상적인 데이터형을 구현하는데 사용될 수 없습니다. 사실, 파이썬에서는 데이터 은닉을 강제할 방법이 없습니다 --- 모두 관례에 의존합니다. (반면에, C로 작성된 파이썬 구현은 필요하다면 구현 상세를 완전히 숨기고 객체에 대한 액세스를 제어할 수 있습니다; 이것은 C로 작성된 파이썬 확장에서 사용될 수 있습니다.)


データ属性は、メソッドから参照できると同時に、通常のオブジェクトのユーザ ("クライアント") からも参照できます。言い換えると、クラスは純粋な抽象データ型として使うことができません。実際、 Python では、データ隠蔽を補強するための機構はなにもありません --- データの隠蔽はすべて規約に基づいています。 (逆に、C 言語で書かれた Python の実装では実装の詳細を完全に隠蔽し、必要に応じてオブジェクトへのアクセスを制御できます。この機構は C 言語で書かれた Python 拡張で使うことができます。)



클라이언트는 데이터 어트리뷰트를 조심스럽게 사용해야 합니다 --- 클라이언트는 데이터 어트리뷰트를 건드려서 메서드들에 의해 유지되는 불변성 들을 망가뜨릴 수 있습니다. 클라이언트는 이름 충돌을 피하는 한 메서드들의 유효성을 손상하지 않고도 그들 자신의 데이터 어트리뷰트를 인스턴스 객체에 추가할 수도 있음에 유의하세요 --- 다시 한번, 명명 규칙은 여러 골칫거리를 피할 수 있게 합니다.


クライアントはデータ属性を注意深く扱うべきです --- クライアントは、メソッドが維持しているデータ属性の不変式を踏みにじり、台無しにするかもしれません。クライアントは、名前の衝突が回避されている限り、メソッドの有効性に影響を及ぼすことなくインスタンスに独自の属性を追加することができる、ということに注意してください --- ここでも、名前付けの規約は頭痛の種を無くしてくれます。


메서드 안에서 데이터 어트리뷰트들(또는 다른 메서드들!)을 참조하는 줄임 표현은 없습니다. 저는 이것이 실제로 메서드의 가독성을 높인다는 것을 알게 되었습니다: 메서드를 훑어볼 때 지역 변수와 인스턴스 변수를 혼동할 우려가 없습니다.


メソッドの中から、データ属性を (または別のメソッドも!) 参照するための短縮された記法はありません。私は、この仕様がメソッドの可読性を高めていると感じています。あるメソッドを眺めているときにローカルな変数とインスタンス変数をはっきり区別できるからです。



종종, 메서드의 첫 번째 인자는 self 라고 불립니다. 이것은 관례일 뿐입니다: 이름 self 는 파이썬에서 아무런 특별한 의미를 갖지 않습니다. 하지만, 이 규칙을 따르지 않을 때 여러분의 코드가 다른 파이썬 프로그래머들이 읽기에 불편하고, 클래스 브라우저프로그램도 이런 규칙에 의존하도록 작성되었다고 상상할 수 있음에 유의하세요.


よく、メソッドの最初の引数を self と呼びます。この名前付けは単なる慣習でしかありません。 self という名前は、 Python では何ら特殊な意味を持ちません。とはいえ、この慣行に従わないと、コードは他の Python プログラマにとってやや読みにくいものとなります。また、 クラスブラウザ (class browser) プログラムがこの慣行をあてにして書かれているかもしれません。



클래스 어트리뷰트인 모든 함수는 그 클래스의 인스턴스들을 위한 메서드를 정의합니다. 함수 정의가 클래스 정의에 텍스트 적으로 둘러싸일 필요는 없습니다: 함수 객체를 클래스의 지역 변수로 대입하는 것 역시 가능합니다. 예를 들어:


クラス属性である関数オブジェクトはいずれも、そのクラスのインスタンスのためのメソッドを定義しています。関数定義は、テキスト上でクラス定義の中に入っている必要はありません。関数オブジェクトをクラスのローカルな変数の中に代入するのも OK です。例えば以下のコードのようにします:


# Function defined outside the class
def f1(self, x, y):
    return min(x, x+y)

class C:
    f = f1

    def g(self):
        return 'hello world'

    h = g

이제 fgh 는 모두 함수 객체를 가리키는 클래스 C 의 어트리뷰트고, 결과적으로 이것들은 모두 C 의 인스턴스들의 메서드입니다 --- h 는 정확히 g 와 동등합니다. 이런 방식은 프로그램의 독자들에게 혼란을 주기만 한다는 점에 주의하세요.


これで、 f 、 g 、および h は、すべて C の属性であり関数オブジェクトを参照しています。従って、これら全ては、 C のインスタンスのメソッドとなります --- h は g と全く等価です。これを実践しても、大抵は単にプログラムの読者に混乱をもたらすだけなので注意してください。


메서드는 self 인자의 메서드 어트리뷰트를 사용해서 다른 메서드를 호출할 수 있습니다:

メソッドは、 self 引数のメソッド属性を使って、他のメソッドを呼び出すことができます:

class Bag:
    def __init__(self):
        self.data = []

    def add(self, x):
        self.data.append(x)

    def addtwice(self, x):
        self.add(x)
        self.add(x)

메서드는 일반 함수들과 마찬가지로 전역 이름을 참조할 수 있습니다. 

メソッドは、通常の関数と同じようにしてグローバルな名前を参照します。


메서드에 결합한 전역 스코프는 그것의 정의를 포함하는 모듈입니다. (클래스는 결코 전역 스코프로 사용되지 않습니다.) 

あるメソッドに関するグローバルスコープは、その定義を含むモジュールです。(クラスはグローバルなスコープとして用いられることはありません。) 


메서드에서 전역 데이터를 사용할 좋은 이유를 거의 만나지 못하지만, 전역 스코프를 정당하게 사용하는 여러 가지 경우가 있습니다: 

メソッドでグローバルなデータを使う良い理由はほとんどありませんが、グローバルなスコープを使うべき場面は多々あります。


한가지는, 전역 스코프에 정의된 함수와 메서드 뿐만 아니라, 그곳에 임포트된 함수와 모듈도 메서드가 사용할 수 있다는 것입니다. 보통, 메서드를 포함하는 클래스 자신은 이 전역 스코프에 정의되고, 다음 섹션에서 메서드가 자신의 클래스를 참조하길 원하는 몇 가지 좋은 이유를 보게 될 것입니다.


一つ挙げると、メソッド内から、グローバルなスコープに import された関数やモジュールや、そのモジュール中で定義された関数やクラスを使うことができます。通常、メソッドの入っているクラス自体はグローバルなスコープ内で定義されています。次の節では、メソッドが自分のクラスを参照する理由として正当なものを見てみましょう。



각 값은 객체고, 그러므로 클래스 ( 이라고도 불린다) 를 갖습니다. 이것은 object.__class__ 에 저장되어 있습니다.

個々の値はオブジェクトなので、 クラス ( とも言います) を持っています。それは object.__class__ に保持されています。

9.5. 상속 継承

물론, 상속을 지원하지 않는다면 언어 기능은 "클래스"라는 이름을 붙일만한 가치가 없을 것입니다. 파생 클래스 정의의 문법은 이렇게 생겼습니다:

言うまでもなく、継承の概念をサポートしない言語機能は "クラス" と呼ぶに値しません。派生クラス (derived class) を定義する構文は次のようになります:

class DerivedClassName(BaseClassName):
    <statement-1>
    .
    .
    .
    <statement-N>

이름 BaseClassName 은 파생 클래스 정의를 포함하는 스코프에 정의되어 있어야 합니다. 

베이스 클래스 이름의 자리에 다른 임의의 표현식도 허락됩니다. 예를 들어, 베이스 클래스가 다른 모듈에 정의되어 있을 때 유용합니다:


基底クラス (base class) の名前 BaseClassName は、派生クラス定義の入っているスコープで定義されていなければなりません。

基底クラス名のかわりに任意の式を入れることもできます。これは次の例のように、基底クラスが別モジュールで定義されているときに便利なことがあります:

class DerivedClassName(modname.BaseClassName):

파생 클래스 정의의 실행은 베이스 클래스와 같은 방식으로 진행됩니다. 클래스 객체가 만들어질 때, 베이스 클래스가 기억됩니다. 이것은 어트리뷰트 참조를 결정할 때 사용됩니다: 요청된 어트리뷰트가 클래스에서 발견되지 않으면 베이스 클래스로 검색을 확장합니다. 베이스 클래스 또한 다른 클래스로부터 파생되었다면 이 규칙은 재귀적으로 적용됩니다.


派生クラス定義の実行は、基底クラスの場合と同じように進められます。クラスオブジェクトが構築される時、基底クラスが記憶されます。記憶された基底クラスは、属性参照を解決するために使われます。要求された属性がクラスに見つからなかった場合、基底クラスに検索が進みます。この規則は、基底クラスが他の何らかのクラスから派生したものであった場合、再帰的に適用されます。



파생 클래스의 인스턴스 만들기에 특별한 것은 없습니다: DerivedClassName() 는 그 클래스의 새 인스턴스를 만듭니다. 메서드 참조는 다음과 같이 결정됩니다: 대응하는 클래스 어트리뷰트가 검색되는데, 필요하면 베이스 클래스의 연쇄를 타고 내려갑니다. 이것이 함수 객체를 준다면 메서드 참조는 올바릅니다.


派生クラスのインスタンス化では、特別なことは何もありません。 DerivedClassName() はクラスの新たなインスタンスを生成します。メソッドの参照は次のようにして解決されます。まず対応するクラス属性が検索されます。検索は、必要に応じ、基底クラス連鎖を下って行われ、検索の結果として何らかの関数オブジェクトがもたらされた場合、メソッド参照は有効なものとなります。



파생 클래스는 베이스 클래스의 메서드들을 재정의할 수 있습니다. 메서드가 같은 객체의 다른 메서드를 호출할 때 특별한 권한 같은 것은 없으므로, 베이스 클래스에 정의된 다른 메서드를 호출하는 베이스 클래스의 메서드는 재정의된 파생 클래스의 메서드를 호출하게 됩니다. (C++ 프로그래머를 위한 표현으로: 파이썬의 모든 메서드는 실질적으로 virtual 입니다.)


派生クラスは基底クラスのメソッドを上書き (override) することができます。メソッドは同じオブジェクトの別のメソッドを呼び出す際に何ら特殊な権限を持ちません。このため、ある基底クラスのメソッドが、同じ基底クラスで定義されているもう一つのメソッド呼び出しを行っている場合、派生クラスで上書きされた何らかのメソッドが呼び出されることになるかもしれません。 (C++ プログラマへ: Python では、すべてのメソッドは事実上 virtual です。)



파생 클래스에서 재정의된 메서드가, 같은 이름의 베이스 클래스 메서드를 단순히 갈아치우기보다 사실은 확장하고 싶을 수 있습니다.

 베이스 클래스의 메서드를 직접 호출하는 간단한 방법이 있습니다: 단지 BaseClassName.methodname(self, arguments) 를 호출하면 됩니다. 이것은 때로 클라이언트에게도 쓸모가 있습니다. (이것은 베이스 클래스가 전역 스코프에서 BaseClassName 으로 액세스 될 수 있을 때만 동작함에 주의하세요.)

파이썬에는 상속과 함께 사용할 수 있는 두 개의 내장 함수가 있습니다:


派生クラスで上書きしているメソッドでは、基底クラスの同名のメソッドを置き換えるのではなく、拡張したいのかもしれません。基底クラスのメソッドを直接呼び出す簡単な方法があります。単に BaseClassName.methodname(self, arguments) を呼び出すだけです。この仕様は、場合によってはクライアントでも役に立ちます。 (この呼び出し方が動作するのは、基底クラスがグローバルスコープの BaseClassName という名前でアクセスできるときだけです。)

Python には継承に関係する 2 つの組み込み関数があります:


  • 인스턴스의 형을 검사하려면 isinstance() 를 사용합니다: isinstance(obj, int) 는 obj.__class__ 가 int 거나 int에서 파생된 클래스인 경우만 True 가 됩니다.
  • 클래스 상속을 검사하려면 issubclass() 를 사용합니다: issubclass(bool, int) 는 True 인데, bool 이 int 의 서브 클래스이기 때문입니다. 하지만, issubclass(float, int)는 False 인데, float 는 int 의 서브 클래스가 아니기 때문입니다.
  • isinstance() を使うとインスタンスの型が調べられます。 isinstance(obj, int) は obj.__class__ が int や int の派生クラスの場合に限り True になります。
  • issubclass() を使うとクラスの継承関係が調べられます。 bool は int のサブクラスなので issubclass(bool, int) は True です。しかし、 float は int のサブクラスではないので issubclass(float, int) は False です。

9.5.1. 다중 상속 多重継承

파이썬은 다중 상속의 형태도 지원합니다. 여러 개의 베이스 클래스를 갖는 클래스 정의는 이런 식입니다:

Python では、多重継承 (multiple inheritance) の形式もサポートしています。複数の基底クラスをもつクラス定義は次のようになります:

class DerivedClassName(Base1, Base2, Base3):
    <statement-1>
    .
    .
    .
    <statement-N>

대부분의 목적상, 가장 간단한 경우에, 부모 클래스로부터 상속된 어트리뷰트들의 검색을 깊이 우선으로, 왼쪽에서 오른쪽으로, 계층 구조에서 겹치는 같은 클래스를 두 번 검색하지 않는 것으로 생각할 수 있습니다. 그래서, 어트리뷰트가 DerivedClassName 에서 발견되지 않으면, Base1 에서 찾고, 그다음 (재귀적으로) Base1의 베이스 클래스들을 검색합니다. 거기에서도 발견되지 않으면, Base2 에서 찾고, 이런 식으로 계속합니다.


ほとんどのシンプルな多重継承において、親クラスから継承される属性の検索は、深さ優先で、左から右に、そして継承の階層の中で同じクラスが複数出てくる(訳注: ダイアモンド継承と呼ばれます)場合に2度探索をしない、と考えることができます。なので、 DerivedClassName にある属性が存在しない場合、まず Base1 から検索され、そして(再帰的に) Base1 の基底クラスから検索され、それでも見つからなかった場合は Base2 から検索される、といった具合になります。



사실, 이것보다는 약간 더 복잡합니다; 메서드 결정 순서는 super() 로의 협력적인 호출을 지원하기 위해 동적으로 변경됩니다. 이 접근법은 몇몇 다른 다중 상속 언어들에서 call-next-method 라고 알려져 있고, 단일 상속 언어들에서 발견되는 super 호출보다 더 강력합니다.


実際には、それよりもう少しだけ複雑です。協調的な super() の呼び出しのためにメソッドの解決順序は動的に変更されます。このアプローチは他の多重継承のある言語で call-next-method として知られており、単一継承しかない言語の super 呼び出しよりも強力です。



동적인 순서가 필요한 이유는, 모든 다중 상속의 경우는 하나나 그 이상의 다이아몬드 관계 (적어도 부모 클래스 중 하나가 가장 바닥 클래스들로부터 여러 경로를 통해 액세스 되는 경우) 를 만들기 때문입니다. 예를 들어, 모든 클래스는 object 를 계승하기 때문에, 모든 다중 상속은 object 에 이르는 여러 경로를 제공합니다. 베이스 클래스들이 여러 번 액세스 되지 않게 하려고, 동적인 알고리즘이 검색 순서를 선형화하는데, 각 클래스에서 지정된 왼쪽에서 오른쪽으로 가는 순서를 보존하고, 각 부모를 오직 한 번만 호출하고, 단조적 (부모들의 우선순위에 영향을 주지 않으면서 서브 클래스를 만들 수 있다는 의미입니다) 이도록 만듭니다. 모두 함께 사용될 때, 이 성질들은 다중 상속으로 신뢰성 있고 확장성 있는 클래스들을 설계할 수 있도록 만듭니다. 더 자세한 내용은, https://www.python.org/download/releases/2.3/mro/ 를 보세요.


多重継承の全ての場合に 1 つかそれ以上のダイヤモンド継承 (少なくとも 1 つの祖先クラスに対し最も下のクラスから到達する経路が複数ある状態) があるので、動的順序付けが必要です。例えば、全ての新形式のクラスは object を継承しているので、どの多重継承でも objectへ到達するための道は複数存在します。基底クラスが複数回アクセスされないようにするために、動的アルゴリズムで検索順序を直列化し、各クラスで指定されている祖先クラスどうしの左から右への順序は崩さず、各祖先クラスを一度だけ呼び出し、かつ一様になる (つまり祖先クラスの順序に影響を与えずにサブクラス化できる) ようにします。まとめると、これらの特徴のおかげで信頼性と拡張性のある多重継承したクラスを設計することができるのです。さらに詳細を知りたければ、 https://www.python.org/download/releases/2.3/mro/ を見てください。


9.6. 비공개 변수 プライベート変数

객체 내부에서만 액세스할 수 있는 "비공개" 인스턴스 변수는 파이썬에 존재하지 않습니다. 하지만, 대부분의 파이썬 코드에서 따르고 있는 규약이 있습니다: 밑줄로 시작하는 이름은 (예를 들어, _spam) API의 공개적이지 않은 부분으로 취급되어야 합니다 (그것이 함수, 메서드, 데이터 멤버중 무엇이건 간에). 구현 상세이고 통보 없이 변경되는 대상으로 취급되어야 합니다.


オブジェクトの中からしかアクセス出来ない "プライベート" インスタンス変数は、 Python にはありません。しかし、ほとんどの Python コードが従っている慣習があります。アンダースコアで始まる名前 (例えば _spam) は、 (関数であれメソッドであれデータメンバであれ) 非 public なAPIとして扱います。これらは、予告なく変更されるかもしれない実装の詳細として扱われるべきです。



클래스-비공개 멤버들의 올바른 사례가 있으므로 (즉 서브 클래스에서 정의된 이름들과의 충돌을 피하고자), 이름 뒤섞기 (name mangling) 라고 불리는 메커니즘에 대한 제한된 지원이 있습니다. __spam 형태의 (최소 두 개의 밑줄로 시작하고, 최대 한 개의 밑줄로 끝납니다) 모든 식별자는 _classname__spam 로 텍스트 적으로 치환되는데, classname 은 현재 클래스 이름에서 앞에 오는 밑줄을 제거한 것입니다. 이 뒤섞기는 클래스 정의에 등장하는 이상, 식별자의 문법적 위치와 무관하게 수행됩니다.


クラスのプライベートメンバについて適切なユースケース(特にサブクラスで定義された名前との衝突を避ける場合)があるので、名前マングリング (name mangling) と呼ばれる、限定されたサポート機構があります。 __spam (先頭に二個以上の下線文字、末尾に一個以下の下線文字) という形式の識別子は、 _classname__spam へとテキスト置換されるようになりました。ここで classname は、現在のクラス名から先頭の下線文字をはぎとった名前になります。このような難号化 (mangle) は、識別子の文法的な位置にかかわらず行われるので、クラス定義内に現れた識別子全てに対して実行されます。


이름 뒤섞기는 클래스 내부의 메서드 호출을 방해하지 않고 서브 클래스들이 메서드를 재정의할 수 있도록 하는 데 도움을 줍니다. 예를 들어:


名前マングリングは、サブクラスが内部のメソッド呼び出しを壊さずにメソッドをオーバーライドするのに便利です。例えば:

class Mapping:
    def __init__(self, iterable):
        self.items_list = []
        self.__update(iterable)

    def update(self, iterable):
        for item in iterable:
            self.items_list.append(item)

    __update = update   # private copy of original update() method

class MappingSubclass(Mapping):

    def update(self, keys, values):
        # provides new signature for update()
        # but does not break __init__()
        for item in zip(keys, values):
            self.items_list.append(item)

위의 예는 MappingSubclass가 __update 식별자를 도입하더라도 작동합니다. Mapping 클래스에서는 _Mapping__update로 MappingSubclass 클래스에서는 _MappingSubclass__update로 각각 대체 되기 때문입니다.


上の例は、もし仮に MappingSubclass に __update 識別子を実装したとしてもきちんと動きます。 その理由は、 Mapping クラスではその識別子を _Mapping__update に、 MappingSubclassクラスでは _MappingSubclass__update にそれぞれ置き換えるからです。



뒤섞기 규칙은 대체로 사고를 피하고자 설계되었다는 것에 주의하세요; 여전히 비공개로 취급되는 변수들을 액세스하거나 수정할 수 있습니다. 이것은 디버거와 같은 특별한 상황에서 쓸모 있기조차 합니다.


号化の規則は主に不慮の事故を防ぐためのものだということに注意してください; 確信犯的な方法で、プライベートとされている変数にアクセスしたり変更することは依然として可能なのです。デバッガのような特殊な状況では、この仕様は便利ですらあります。



exec() 나 eval() 로 전달된 코드는 호출하는 클래스의 클래스 이름을 현재 클래스로 여기지 않는다는 것에 주의하세요; 이것은 global 문의 효과와 유사한데, 효과가 함께 바이트-컴파일된 코드로 제한됩니다. 같은 제약이 __dict__ 를 직접 참조할 때뿐만 아니라, getattr()setattr()delattr() 에도 적용됩니다.


exec() や eval() へ渡されたコードでは、呼出し元のクラス名を現在のクラスと見なさないことに注意してください。この仕様は global 文の効果と似ており、その効果もまた同様に、バイトコンパイルされたコードに制限されています。同じ制約が getattr() と setattr() と delattr() にも適用されます。また、__dict__ を直接参照するときにも適用されます。



9.7. 잡동사니 残りのはしばし

때로 몇몇 이름 붙은 데이터 항목들을 함께 묶어주는 파스칼의 "record" 나 C의 "struct" 와 유사한 데이터형을 갖는 것이 쓸모 있습니다. 빈 클래스 정의가 훌륭히 할 수 있는 일입니다:


Pascal の "レコード (record)" や、C 言語の "構造体 (struct)" のような、名前つきのデータ要素を一まとめにするデータ型があると便利なことがあります。空のクラス定義を使うとうまくできます:


class Employee:
    pass

john = Employee()  # Create an empty employee record

# Fill the fields of the record
john.name = 'John Doe'
john.dept = 'computer lab'
john.salary = 1000

특정한 추상적인 데이터형을 기대하는 파이썬 코드 조각은, 종종 그 데이터형의 메서드를 흉내 내는 클래스를 대신 전달받을 수 있습니다. 예를 들어, 파일 객체로부터 데이터를 포맷하는 함수가 있을 때, 대신 문자열 버퍼에서 데이터를 읽는 메서드 read() 와 readline() 을 제공하는 클래스를 정의한 후 인자로 전달할 수 있습니다.


ある特定の抽象データ型を要求する Python コードの断片に、そのデータ型のメソッドをエミュレーションするクラスを代わりに渡すことができます。例えば、ファイルオブジェクトから何らかのデータを構築する関数がある場合、 read() と readline() を持つクラスを定義して、ファイルではなく文字列バッファからデータを取得するようにしておき、引数として渡すことができます。



인스턴스 메서드 객체도 어트리뷰트를 갖습니다: m.__self__ 는 메서드 m() 과 결합한 인스턴스 객체이고, m.__func__ 는 메서드에 상응하는 함수 객체입니다.


インスタンスメソッドオブジェクトにも属性があります。 m.__self__ はメソッド m() の属しているインスタンスオブジェクトで、 m.__func__ はメソッドに対応する関数オブジェクトです。


9.8. 이터레이터 イテレータ (iterator)

지금쯤 아마도 여러분은 대부분의 컨테이너 객체들을 for 문으로 루핑할 수 있음을 눈치챘을 것입니다:

すでに気づいているでしょうが、 for 文を使うとほとんどのコンテナオブジェクトにわたってループを行うことができます:

for element in [1, 2, 3]:
    print(element)
for element in (1, 2, 3):
    print(element)
for key in {'one':1, 'two':2}:
    print(key)
for char in "123":
    print(char)
for line in open("myfile.txt"):
    print(line, end='')

이런 스타일의 액세스는 명료하고, 간결하고, 편리합니다. 이터레이터를 사용하면 파이썬이 보편화하고 통합됩니다. 무대 뒤에서, for 문은 컨테이너 객체에 대해 iter() 를 호출합니다. 이 함수는 메서드 __next__() 를 정의하는 이터레이터 객체를 돌려주는데, 이 메서드는 컨테이너의 요소들을 한 번에 하나씩 액세스합니다. 


남은 요소가 없으면, __next__() 는 StopIteration 예외를 일으켜서 for 루프에 종료를 알립니다. next() 내장 함수를 사용해서 __next__() 메서드를 호출할 수 있습니다; 이 예는 이 모든 것들이 어떻게 동작하는지 보여줍니다:


こういう要素へのアクセス方法は明確で簡潔で使い易いものです。イテレータの活用は Python へ広く行き渡り、統一感を持たせています。裏では for 文はコンテナオブジェクトに対して iter() 関数を呼んでいます。関数は、コンテナの中の要素に1つずつアクセスする __next__() メソッドが定義されているイテレータオブジェクトを返します。こ


れ以上要素が無い場合は、 __next__() メソッドは StopIteration 例外を送出し、その通知を受け for ループは終了します。組み込みの next() 関数を使って __next__() メソッドを直接呼ぶこともできます; この例は関数がどう働くのかを示しています:


>>>
>>> s = 'abc'
>>> it = iter(s)
>>> it
<iterator object at 0x00A1DB50>
>>> next(it)
'a'
>>> next(it)
'b'
>>> next(it)
'c'
>>> next(it)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
    next(it)
StopIteration

이터레이터 프로토콜의 뒤에 있는 메커니즘을 살펴보면, 여러분의 클래스에 이터레이터 동작을 쉽게 추가할 수 있습니다. __next__() 메서드를 가진 객체를 돌려주는 __iter__() 메서드를 정의합니다. 클래스가 __next__() 를 정의하면, __iter__() 는 그냥 self 를 돌려줄 수 있습니다.


イテレータプロトコルの裏にある仕組みを観察していれば、自作のクラスにイテレータとしての振舞いを追加するのは簡単です。 __next__() メソッドを持つオブジェクトを返す __iter__() メソッドを定義するのです。クラスが __next__() メソッドを定義している場合、 __iter__() メソッドは単に self を返すことも可能です:

class Reverse:
    """Iterator for looping over a sequence backwards."""
    def __init__(self, data):
        self.data = data
        self.index = len(data)

    def __iter__(self):
        return self

    def __next__(self):
        if self.index == 0:
            raise StopIteration
        self.index = self.index - 1
        return self.data[self.index]
>>>
>>> rev = Reverse('spam')
>>> iter(rev)
<__main__.Reverse object at 0x00A1DB50>
>>> for char in rev:
...     print(char)
...
m
a
p
s

9.9. 제너레이터 ジェネレータ (generator)

제너레이터 는 이터레이터를 만드는 간단하고 강력한 도구입니다. 일반적인 함수처럼 작성되지만 값을 돌려주고 싶을 때마다 yield 문을 사용합니다. 제너레이터에 next() 가 호출될 때마다, 제너레이터는 떠난 곳에서 실행을 재개합니다 (모든 데이터 값들과 어떤 문장이 마지막으로 실행되었는지 기억합니다). 예는 제너레이터를 사소할 정도로 쉽게 만들 수 있음을 보여줍니다:

ジェネレータ(generator)は、イテレータを作成するための簡潔で強力なツールです。ジェネレータは通常の関数のように書かれますが、何らかのデータを返すときには yield 文を使います。そのジェネレータに対して next() が呼び出されるたびに、ジェネレータは以前に中断した処理を再開します (ジェネレータは、全てのデータ値と最後にどの文が実行されたかを記憶しています)。以下の例を見れば、ジェネレータがとても簡単に作成できることがわかります:


def reverse(data):
    for index in range(len(data)-1, -1, -1):
        yield data[index]
>>>
>>> for char in reverse('golf'):
...     print(char)
...
f
l
o
g

제너레이터로 할 수 있는 모든 것은 앞 절에서 설명했듯이 클래스 기반 이터레이터로도 할 수 있습니다. 제너레이터가 간단한 이유는 __iter__() 와 __next__() 메서드가 저절로 만들어지기 때문입니다.


ジェネレータでできることは、前の節で解説したクラスを使ったイテレータでも実現できます。ジェネレータの定義がコンパクトになるのは __iter__() メソッドと __next__() メソッドが自動で作成されるからです。



또 하나의 주요 기능은 지역 변수들과 실행 상태가 호출 간에 자동으로 보관된다는 것입니다. 

이것은 self.index 나 self.data와 같은 인스턴스 변수를 사용하는 접근법에 비교해 함수를 쓰기 쉽고 명료하게 만듭니다.


ジェネレータのもう一つの重要な機能は、呼び出しごとにローカル変数と実行状態が自動的に保存されるということです。これにより、 self.index や self.data といったインスタンス変数を使ったアプローチよりも簡単に関数を書くことができるようになります。


자동 메서드 생성과 프로그램 상태의 저장에 더해, 제너레이터가 종료할 때 자동으로 StopIteration 을 일으킵니다. 조합하면, 이 기능들이 일반 함수를 작성하는 것만큼 이터레이터를 만들기 쉽게 만듭니다.


メソッドを自動生成したりプログラムの実行状態を自動保存するほかに、ジェネレータは終了時に自動的に StopIteration を送出します。これらの機能を組み合わせると、通常の関数を書くのと同じ労力で、簡単にイテレータを生成できます。


9.10. 제너레이터 표현식  ジェネレータ式

간단한 제너레이터는 리스트 컴프리헨션과 비슷하지만, 꺾쇠괄호 대신 괄호를 사용하는 문법을 사용한 표현식으로 간결하게 코딩할 수 있습니다. 이 표현식들은 둘러싸는 함수가 제너레이터를 즉시 사용하는 상황을 위해 설계되었습니다. 제너레이터 표현식은 완전한 제너레이터 정의보다 간결하지만, 융통성은 떨어지고, 비슷한 리스트 컴프리헨션보다 메모리를 덜 쓰는 경향이 있습니다.

예:


単純なジェネレータなら式として簡潔にコーディングできます。 その式はリスト内包表記に似た構文を使いますが、角括弧ではなく丸括弧で囲います。 ジェネレータ式は、関数の中でジェネレータをすぐに使いたいような状況のために用意されています。 ジェネレータ式は完全なジェネレータの定義よりコンパクトですが、ちょっと融通の効かないところがあります。 同じ内容を返すリスト内包表記よりはメモリに優しいことが多いという利点があります。

例:

>>>
>>> sum(i*i for i in range(10))                 # sum of squares
285

>>> xvec = [10, 20, 30]
>>> yvec = [7, 5, 3]
>>> sum(x*y for x,y in zip(xvec, yvec))         # dot product
260

>>> from math import pi, sin
>>> sine_table = {x: sin(x*pi/180) for x in range(0, 91)}

>>> unique_words = set(word  for line in page  for word in line.split())

>>> valedictorian = max((student.gpa, student.name) for student in graduates)

>>> data = 'golf'
>>> list(data[i] for i in range(len(data)-1, -1, -1))
['f', 'l', 'o', 'g']