The History of Python: Adding Support for User-defined Classes
Adding Support for User-defined Classes (ユーザー定義クラスのサポートの追加)
Believe it or not, classes were added late during Python's first year of development
at CWI, though well before the first public release. However, to understand how
classes were added, it first helps to know a little bit about how Python is
implemented.
信じようと信じまいと、Python におけるクラスというのものは、最初のパブリックリリース以
前からあったものではあるのですがCWI での late during Python's first year of development
で追加されたものなのです。とはいえクラスがどのように追加されたかを知るためにはPython
でクラスがどのように実装されているかを最初に多少なりとも知っておくことは助けになるでし
ょう。
Python is implemented in C as a classic stack-based byte code interpreter or “virtual
machine” along with a collection of primitive types also implemented in C. The
underlying architecture uses “objects” throughout, but since C has no direct support
for objects, they are implemented using structures and function pointers. The Python
virtual machine defines several dozen standard operations that every object type may
or must implement (for example, “get attribute”, “add” and “call”). An object
type is then represented by a statically allocated structure containing a series of
function pointers, one for each standard operation. These function pointers are
typically initialized with references to static functions. However, some operations
are optional, and the object type may leave the function pointer NULL if it chooses
not to implement that operation. In this case, the virtual machine either generates a
run-time error or, in some cases, provides a default implementation of the operation.
The type structure also contains various data fields, one of which is a reference to a
list of additional methods that are unique to this type, represented as an array of
structures containing a string (the method name) and a function pointer (its
implementation) each. Python's unique approach to introspection comes from its
ability to make the type structure itself available at run-time as an object like all
others.
Python は伝統的なスタックベースのバイトコードインタープリターもしくは “virtual
machine”としてCで実装されたもので、そしてやはりCで実装されたプリミティブ型のコレクシ
ョンが一緒にありました。underlying architecture が “objects” を使っていましたがCは直
接にはオブジェクトをサポートしていなかったので、構造体と関数ポインターを用いてオブジェ
クトが実装されていました。Python仮想機械はオブジェクトの型ごとに実装しても良かったり逆
にや実装しておかなければならないような標準的な操作(たとえば“get attribute”, “add”
and “call”)を several dozen 定義していました。そしてオブジェクト型は静的に割り当て
られた一つ一つがそれぞれなんらかの標準操作に対応するような関数ポインターの並びを保持し
ている構造体によって表現されています。オブジェクト型はこれらの関数ポインターは典型的に
は static 関数に対する参照で初期化されていました。しかし一部の操作はoptionalであり、か
つそのオブジェクト型は操作の実装を行わない場合には関数ポインターの値をNULLのままにして
おくということもできました。この場合仮想機械は実行時エラーを生成するかあるいは一部の場
合はその操作のデフォルト実装を提供するかします。型構造体は、様々なデータフィールドや型
に固有な additional メソッドのリストへの参照のいずれかひとつを抱えていて、(メソッド名
をあらわす)文字列と(メソッドを実装している)関数ポインターとをそれごれが保持している構
造体の配列として表現しています。Pythonの introspection に対するunique なアプローチは、
型構造体それ自身を実行時に他のすべてのオブジェクトと同様に利用可能にする能力からきたも
のです。
An important aspect of this implementation is that it is completely C-centric. In fact,
all of the standard operations and methods are implemented by C functions. Originally
the byte code interpreter only supported calling pure Python functions and functions
or methods implemented in C. I believe my colleague Siebren van der Zee was the first
to suggest that Python should allow class definitions similar to those in C++ so that
objects could also be implemented in Python.
この実装に対する An important aspect はそれが完全に C-centric だったということです。
事実、標準操作のすべてと標準メソッドのすべて
(all of the standard operations and methods)は
Cで書かれた関数によって実装されていました。
当初のバイトコードインタープリターは
pure Python 関数とCで実装されていた関数やメソッドの呼び出しだけをサポートしていました。
I believe my colleague Siebren van der Zee was the first to suggest
that Python should allow class definitions similar to those in C++
so that objects could also be implemented in Python.
わたしは my colleague である Siebren van der Zee が最初に
PythonはC++で書かれたクラス定義も許容すべきであるという提案を
したと記憶しています。
これによりPythonでオブジェクトも実装できるようになったのです。
To implement user-defined objects, I settled on the simplest possible design; a scheme
where objects were represented by a new kind of built-in object that stored a class
reference pointing to a "class object" shared by all instances of the same
class, and a dictionary, dubbed the "instance dictionary", that contained
the instance variables.
ユーザー定義オブジェクトを実装するために、わたしの判断は可能なものの中で最も単純な設計
に落ち着いたのです。それはオブジェクトが新しい種類の組込みオブジェクトによって表現され
る同じクラスのすべてのインスタンス変数によって共有される“クラスオブジェクト”であるよ
うな schemeです。
In this implementation, the instance dictionary would contain the instance variables
of each individual object whereas the class object would contain stuff shared between
all instances of the same class--in particular, methods. In implementing class objects,
I again chose the simplest possible design; the set of methods of a class were stored
in a dictionary whose keys are the method names. This, I dubbed the class dictionary.
To support inheritance, class objects would additionally store a reference to the
class objects corresponding to the base classes. At the time, I was fairly naïve about
classes, but I knew about multiple inheritance, which had recently been added to C++.
I decided that as long as I was going to support inheritance, I might as well support
a simple-minded version of multiple inheritance. Thus, every class object could have
one or more base classes.
このような実装においては、インスタンス辞書は同じクラスに属するすべてのインスタンスがメ
ソッドのように共有する stuff を保持するクラスオブジェクトであり個々に独立したオブジェ
クトであるインスタンス変数を保持することになります。クラスオブジェクトの実装でもわたし
は simplest possible design を選択しました。あるクラスのメソッドの集合はメソッド名をキ
ーとして辞書に格納されていたのです。この、わたしがクラス辞書と名づけた継承をサポートす
るためのクラスオブジェクトはベースクラスに対応するクラスオブジェクトへの参照を追加で格
納することになりました。このときわたしはクラスについてとても naive だったのですがその
頃 C++に追加された機能である多重継承については知っていました。わたしは継承をサポートし
ようとしていたときにsimple-minded version の 多重継承もサポートしようと考えていたので、
すべてのクラスオブジェクトは一つ以上のクラスを持つことが可能になっていたのです。
In this implementation, the underlying mechanics of working with objects are actually
very simple. Whenever changes are made to instance or class variables, those changes
are simply reflected in the underlying dictionary object. For example, setting an
instance variable on an instance updates its local instance dictionary. Likewise, when
looking up the value of a instance variable of an object, one merely checks its
instance dictionary for the existence of that variable. If the variable is not found
there, things become a little more interesting. In that case, lookups are performed in
the class dictionary and then in the class dictionaries of each of the base classes.
この実装ではオブジェクトと共に動作する underlying mechanics は非常に単純なものでした。
インスタンス変数やクラス変数に変更が加えられるときはいつでもその変更が underlying
dictionary object に反映されました。たとえばあるインスタンスにインスタンス変数をセット
するとそれに対応するローカルインスタンス辞書が更新されました。同様に、あるオブジェクト
のインスタンス変数の値を検索するときにはその変数の存在に対してインスタンス辞書を一つだ
けチェックすればたいていの場合は済むのです。対象となっている変数がそこで見つけられなけ
れば
things become a little more interesting.
#ものごとはちょっとだけ面白くなります?
このケースではルックアップはクラス辞書内で行われてから、ベースクラスごとのクラス辞書それぞ
れに対して行われます。
The process of looking up attributes in the class object and base classes is most
commonly associated with locating methods. As previously mentioned, methods are stored
in the dictionary of a class object which is shared by all instances of the same class.
Thus, when a method is requested, you naturally won't find it in the instance
dictionary of each individual object. Instead, you have to look it up in the class
dictionary, and then ask each of the base classes in turn, stopping when a hit is
found. Each of the base classes then implements the same algorithm recursively. This
is commonly referred to as the depth-first, left-to-right rule, and has been the
default method resolution order (MRO) used in most versions of Python. More modern
releases have adapted a more sophisticated MRO, but that will be discussed in a later
blog.
クラスオブジェクトやベースクラスにある属性の検索の手順は
most commonly associated with locating methods です。
すでに述べているように、メソッドはクラスオブジェクトの辞書に格納されています
( which is shared by all instances of the same class.)。
したがって、あるメソッドがリクエストされたときに個々の独立したオブジェクトが持っている
インスタンス辞書からそれを探そうとしても見つかりません。そうではなく、クラス辞書から検
索しなければならず、必要があればそのベースクラスに対する問い合わせをメソッドが見つかる
まで行なわなければなりません。ベースクラスのそれぞれはまた同じアルゴリズムを再帰的に実
装しています。このようなやり方は通常、depth-first, left-to-right rule と呼ばれるもので、
Python の大部分のバージョンで使われているデフォルトの解決アルゴリズム(method
resolution order → MRO) となっていました。もっと最近になってのリリースではより
sophisticated された MROが使われていますがそれはこのblogのもっと後の回で論じることにし
ます。
In implementing classes, one of my goals was to keep things simple. Thus, Python
performs no advanced error checking or conformance checking when locating methods. For
example, if a class overrides a method defined in a base class, no checks are
performed to make sure that the redefined method has the same number of arguments or
that it can be called in the same way as the original base-class method. The above
method resolution algorithm merely returns the first method found and calls it with
whatever arguments the user has supplied.
クラスの実装におけるわたしの目標の一つが単純さを保つ(keep things simple)ということでし
た。したがって、Python は高度なエラーチェックもしませんしlocating methods のときに
comformance チェックも行いません。たとえば、あるクラスがそのベースクラスでの定義をオー
バーライドしても再定義されたメソッドがオーバーライド前のものと同じ数の引数を取るのかだ
とか同じ方法で呼び出すことができるかどうかといったことのチェックは実行されません。先の
メソッド検索アルゴリズムはただ単に最初に見つかったメソッドを返しそれをユーザーが提供し
た引数をわたして呼び出します。
A number of other features also fall out of this design. For instance, even though the
class dictionary was initially envisioned as a place to put methods, there was no
inherent reason why other kinds of objects couldn't be placed there as well. Thus, if
objects such as integers or strings are stored in the class dictionary, they become
what are known as class variables- - variables shared by all instances of a given class
instead of being stored inside each instance.
その他の数多くの機能はこの設計に fall out しました。たとえばクラス辞書でさえも当初はメ
ソッドを置く場所として envision されたものであり他の種類のオブジェクトを同様に置くとこ
とができないという(inheretした)理由はありません。したがって、整数や文字列のようなオブ
ジェクトがクラス辞書に格納されると、それらはあるクラスに属しているすべてのインスタンス
で共有される変数であるクラス変数として知られるものになりました。
Although the implementation of classes is simple, it also provides a surprisingly
degree of flexibility. For instance, the implementation not only makes classes
“first-class objects”, which are easily introspected at run time, it also makes it
possible to modify a class dynamically. For example, methods can be added or modified
by simplifying updating the class dictionary after a class object has already been
created! The dynamic nature of Python means that these changes have an immediate
effect on all instances of that class or of any of its subclasses. Likewise,
individual objects can be modified dynamically by adding, modifying, and deleting
instance variables (a feature that I later learned made Python's implementation of
objects more permissive than that found in Smalltalk which restricts the set of
attributes to those specified at the time of object creation).
クラスの実装が単純であったにも関わらず
it also provides a surprisingly degree of flexibility.
たとえばこの実装は実行時に簡単に introspect できる
クラスを“first-class objects” にするだけでなく
クラスを動的に変更することも可能としたのです。
クラスオブジェクトが生成された後にクラス辞書を単に更新するだけで
メソッドを追加したり変更したりすることができたのです!
Python の動的な性質 (dynamic nature of Python) によって
これらの変更が即座に対象となったクラスもしくはそのサブクラスの
すべてのインスタンスに影響を及ぼすことになりました。
同様に、独立した個々のオブジェクトは
インスタンス変数を動的に追加したり変更したり削除することによって
変更することが可能になりました
( さらにあとになってわたしが学んだ機能は
Python におけるオブジェクト実装を
属性の集合がオブジェクトの生成時に指定されていたものに制限されている
Smalltalk よりもさらに permissive なものとしました)。
Development of the class Syntax (クラス構文の開発)
Having designed the run-time representations for user-defined classes and instances,
my next task was to design the syntax for class definitions, and in particular for the
method definitions contained therein. A major design constraint was that I didn't
want to add syntax for methods that differed from the syntax for functions.
Refactoring the grammar and the byte code generator to handle such similar cases
differently felt like a huge task. However, even if I was successful in keeping the
grammar the same, I still had to figure out some way to deal with instance variables.
Initially, I had hoped to emulate implicit instance variables as seen in C++. For
example, in C++, classes are defined by code like this:
ユーザー定義のクラスやインスタンスのための実行時表現を設計したので、わたしの次なる仕事
はクラス定義のための構文を設計することととりわけクラスの中に置かれるメソッド定義をどの
ようにするかを決めることになりました。大きな設計上の制約はわたしがメソッド定義のために、
通常の関数ための構文とは異なった構文を追加するようなことはしたくなかったというものでし
た。文法とバイトコードジェネレーターを
to handle such similar cases differently felt like a huge task.
のためにリファクタリングしましたが、わたしは文法を変えずに保つということには成功しまし
たが、インスタンス変数を扱うための some way を figure out しなければなりませんでした。
C++にみられるのと同じような implicit なインスタンス変数をエミュレートしなければならな
いだろうと考えていました。たとえば C++ではクラスは以下のコード片のようにして定義します:
class A {
public:
int x;
void spam(int y) {
printf("%d %d\n", x, y);
}
};
In this class, an instance variable x has been declared. In methods, references to x
implicitly refer to the corresponding instance variable. For example, in the method
spam(), the variable x is not declared as either function parameter or as local
variable However, since the class has declared an instance variable with that name,
references to x simply refer to that variable. Although I had hoped to provide
something similar in Python, it quickly became clear that such an approach would be
impossible because there was no way to elegantly distinguish instance variables from
local variables in a language without variable declarations.
このクラスでは、インスタンス変数 x は宣言済みです。メソッド内でxを参照するとそれは暗黙
のうちに対応するインスタンス変数を参照します。メソッド spam() の内側では変数 xは関数の
引数としてもローカル変数としても宣言されていませんが、クラスがその名前でインスタンス変
数を宣言しているのでx に対する参照は単純にクラスのインスタンス変数に対するものになるの
です。わたしはPython でも同様なものにしたいと望んだのですが、そのようなアプローチが不
可能であることがすぐに判明しました。その理由は、変数宣言が存在していない言語ではインス
タンス変数とローカル変数とを elegantly に区別するための手段が存在していないというもの
です。
In theory, getting the value of instance variables would be easy enough. Python
already had a search order for unqualified variable names: locals, globals, and
built-ins. Each of these were represented as a dictionary mapping variable names to
values. Thus, for each variable reference, a series of dictionaries would be searched
until a hit was found. For example, when executing a function with a local variable p,
and a global variable q, a statement like “print p, q” would look up p in the first
dictionary in the search order, the dictionary containing local variables, and find a
match. Next it would look up q in the first dictionary, find no match, then look it up
in the second dictionary, the global variables, and find a match.
理論的には、インスタンス変数の値を得るということは十分に簡単なことです。Python はすで
に修飾されていない変数名に対する検索 order を持っていました。ローカル変数、グローバル
変数、そして組み込みのものという順です。これらはそれぞれが変数名を値にマッピングしてい
る辞書として表現されていました。したがって、それぞれが変数のリファレンスである辞書の
series から該当するものが見つかるまで検索されます。たとえばローカル変数 p とグローバル
変数 q を伴った関数を実行するとき、“print p, q”のような文は検索順で最初にあるローカ
ル変数を保持している辞書を検索して pを見つけ、続いてqも同じ辞書で探しますがこれは見つ
かりません。そして検索順で二番目にあるグローバル変数のための辞書で検索を行ってそこでq
を見つけ出します。
It would have been easy to add the current object's instance dictionary in front of
this search list when executing a method. Then, in a method of an object with an
instance variable x and local variable y, a statement like “print x, y” would find x
in the instance dictionary (the first dictionary on the search path) and y in the
local variable dictionary (the second dictionary).
メソッドを実行するときにカレントオブジェクトのインスタンス辞書を検索リストの先頭に追加
することは簡単なことです。そしてインスタンス変数 x と ローカル変数 y を伴ったあるオブ
ジェクトのメソッドの中で、“print x, y”のような文はx をインスタンス辞書(検索パスの最
初の辞書)で発見し、y をローカル変数辞書 (二番目の辞書)で発見することになるでしょう。
The problem with this strategy is that it falls apart for setting instance variables.
Python's assignment doesn’t search for the variable name in the dictionaries, but
simply adds or replaces the variable in the first dictionary in the search order,
normally the local variables. This has the effect that variables are always created in
the local scope by default (although it should be noted that there is a “global
declaration” to override this on a per-function, per-variable basis.)
この戦略に関しての問題はインスタンス変数に対する値の設定に帰着します。Python の代入文
は辞書から代入の対象となる変数の名前を検索することはしません。ただ単に検索順で最初の辞
書、通常はローカル変数用のそれにある変数を追加したり置換したりするだけです。これはデフ
ォルトでは代入によってその変数が常にローカルスコープで作られるという効果をもちます(と
はいえ、関数ごとや variable basis ごとに上記のことをオーバーライドするために “
global declaration”(大域的宣言)が存在するということに注意しておくべきでしょう)。
Without changing this simple-minded approach to assignment, making the instance
dictionary the first item in the search order would make it impossible to assign to
local variables in a method. For example, if you had a method like this
この代入に関する simple-minded なアプローチを変更することなくインスタンス辞書を辞書の
検索順で最初に持ってくることはメソッド内でのローカル変数に対する代入を不可能にしてしま
うのです。たとえば次のようなメソッドがあったとして
def spam(y):
x = 1
y = 2
The assignments to x and y would overwrite the instance variable x and create a new
instance variable y that shadowed the local variable y. Swapping instance variables
and local variables in the search order would merely reverse the problem, making it
impossible to assign to instance variables.
このx と yに対する代入ではインスタンス変数 x を上書きし、
そしてローカル変数 y を shadowed してしまう新しいインスタンス変数 y を生成します
辞書の検索順でインスタンス変数のものとローカル変数のものとを
交換してもただ単に問題が裏返しになるだけで、
インスタンス変数に対する代入が不可能になってしまいます。
Changing the semantics of assignment to assign to an instance variable if one already
existed and to a local otherwise wouldn't work either, since this would create a
bootstrap problem: how does an instance variable get created initially? A possible
solution might have been to require explicit declaration of instance variables as was
the case for global variables, but I really didn’t want to add a feature like that
given that that I had gotten this far without any variable declarations at all. Plus,
the extra specification required for indicating a global variable was more of a
special case that was used sparingly in most code. Requiring a special specification
for instance variables, on the other hand, would have to be used almost everywhere in
a class. Another possible solution would have been to make instance variables
lexically distinct. For example, having instance variables start with a special
character such as @ (an approach taken by Ruby) or by having some kind of special
naming convention involving prefixes or capitalization. Neither of these appealed to
me (and they still don't).
代入文のセマンティクスを、インスタンス変数としてすでに存在している場合にはインスタンス
変数に対する代入にし、そうでない場合にはローカル変数に対する代入のように変更してもうま
くいかず、bootstrap 問題を作り出してしまいます:インスタンス変数は最初にどうやって作る
のでしょうか?可能な解決策は、グローバル変数のそれと同様にはっきりとわかる形でのインス
タンス変数の宣言を要求するというものになるでしょう。しかしわたしは
given that that I had gotten this far without any variable declarations at all
のような機能を追加することを本当にしたくなかったのです。
それに加えて、グローバル変数を indicate するのに要求される追加仕様 (extra specification)
は大部分のコードではあまり使われないような(used sparingly in most code)、
more of a special case でした。
もう一つの解決方法としてインスタンス変数をレキシカルに区別がつくものにしてしまう
というものがありました。たとえば(Rubyがやっているように)@ のような特別な
キャラクターでインスタンス変数の名前を開始するといったものです。
あるいは接頭辞をつけるとかキャピタライズするといった
特殊な命名規則のようなものを導入するというのもあるでしょう。
こういったもののどれもがわたしには魅力あるものには映りませんでした
(これは今でも変わりません)。
Instead, I decided to give up on the idea of implicit references to instance variables.
Languages like C++ let you write this->foo to explicitly reference the instance
variable foo (in case there's a separate local variable foo). Thus, I decided to make
such explicit references the only way to reference instance variables. In addition, I
decided that rather than making the current object ("this") a special
keyword, I would simply make "this" (or its equivalent) the first named
argument to a method. Instance variables would just always be referenced as attributes
of that argument.
結局のところわたしはインスタンス変数に対する暗黙の参照というアイデアをあきらめることにしました。
C++ のような言語はあなたに対してthis->foo のようにインスタンス変数 foo に対する参照
であることをはっきりとした形で記述させます。(in case there's a separate local variable
foo)。ですから、わたしはそのような明確な形での参照がインスタンス変数を参照するための
ただひとつの方法であると決定したのです。また、カレントオブジェクトを表すために特別なキーワー
ド("this")をつくるのではなくあるメソッドの最初の引数の名前が“this”(もしくはそれと同
等のもの)であるとしたのです。インスタンス変数は単にいつもその引数の属性として参照され
ます。
With explicit references, there is no need to have a special syntax for method
definitions nor do you have to worry about complicated semantics concerning variable
lookup. Instead, one simply defines a function whose first argument corresponds to the
instance, which by convention is named "self." For example:
明確な参照を伴っているので、メソッド定義のために特別な構文は必要ありませんし、また、
変数の検索に関して複雑なセマンティクスを心配するような必要もありません。その代わりに定義する関数の
最初の引数がインスタンスに対応するものにするということになります。その引数は規約により
"self" という名前を使うようになっています。
def spam(self,y):
print self.x, y
This approach resembles something I had seen in Modula-3, which had already provided
me with the syntax for import and exception handling. Modula-3 doesn't have classes,
but it lets you create record types containing fully typed function pointer members
that are initialized by default to functions defined nearby, and adds syntactic sugar
so that if x is such a record variable, and m is a function pointer member of that
record, initialized to function f, then calling x.m(args) is equivalent to calling f(x,
args). This matches the typical implementation of objects and methods, and makes it
possible to equate instance variables with attributes of the first argument.
このアプローチは、すでにimport や例外処理のための構文を備えていた
Modula-3 でわたしが見たことがあるようなものを ressemble していました。
Modula-3 はクラスを持っていませんでしたが
完全な型付けをされた関数ポインターであるメンバーを持った
レコード型を作ることができました。
このメンバーはデフォルトでその近くで定義されている関数により初期化されました
(initialized by default to functions defined nearby)。
そして構文糖(syntactice sugar)がまぶされていたので、
レコード型変数 xがあり、m がそのレコードに含まれる関数ポインターメンバーであったとすると
そのメンバーは関数 fに初期化されます。
その後の x.m(args) という呼び出しは f(x, args) という呼び出しと等価です。
これは典型的な実装にマッチするもので、
最初の引数に属性を伴っているインスタンス変数の equate を可能にするものです。
The remaining details of Python's class syntax follow from this design or from the
constraints imposed by the rest of the implementation. Keeping with my desire for
simplicity, I envisioned a class statement as a series of method definitions, which
are syntactically identical to function definitions even though by convention, they
are required to have a first argument named "self". In addition, rather than
devising a new syntax for special kinds of class methods (such as initializers and
destructors), I decided that these features could be handled by simply requiring the
user to implement methods with special names such as __init__, __del__, and so forth.
This naming convention was taken from C where identifiers starting with underscores
are reserved by the compiler and often have special meaning (e.g., macros such as
__FILE__ in the C preprocessor).
Pythonのクラス構文で残っている詳細はこの設計に従ったものであるか
or from the constraints imposed by the rest of the implementation.
単純さに対する自分の要望を保つためにわたしはクラス文を
メソッド定義の並び (series of method definitions) として envision しました。
それは構文的には関数定義と同一のものでありましたが、
クラス文では規約により最初の引数に“self”という名前のものを
要求するようになっていました。
それに加えて、(イニシャライザーやデストラクターのような)特殊なクラスメソッド
のために新しい構文を devise するのではなくユーザーに対して__init__ や __del__
のような特殊な名前を持ったメソッドを実装するようにお願いすることでこれらの機能が
handle できるようにしようとわたしは決めたのです。
この命名規則はアンダースコアから始まる識別子はコンパイラーによって予約されているものであり
しばしば特殊な意味を持っている(たとえばCのプリプロセッサマクロの __FILE__)
という Cのものを借りてきたものです。
Thus, I envisioned that a class would be defined by code that looked like this:
そのため、わたしはクラスは次に示すコードのようにして定義することを envision
(考察/予想/心に描く)したのです:
class A:
def __init__(self,x):
self.x = x
def spam(self,y):
print self.x, y
Again, I wanted to reuse as much of my earlier code as possible. Normally, a function
definition is an executable statement that simply sets a variable in the current
namespace referencing the function object (the variable name is the function name).
Thus, rather than coming up with an entirely different approach for handling classes,
it made sense to me to simply interpret the class body as a series of statements that
were executed in a new namespace. The dictionary of this namespace would then be
captured and used to initialize the class dictionary and create a class object.
Underneath the covers, the specific approach taken is to turn the class body into an
anonymous function that executes all of the statements in the class body and then
returns the resulting dictionary of local variables. This dictionary is then passed to
a helper function that creates a class object. Finally, this class object is then
stored in a variable in the surrounding scope, whose name is the class name. Users are
often surprised to learn that any sequence of valid Python statements can appear in a
class body. This capability was really just a straightforward extension of my desire
to keep the syntax simple as well as not artificially limiting what might possibly be
useful.
繰り返しますが、わたしは可能な限りの量の my earlier code を再利用したいと求めていました。
関数定義は通常、カレントの名前空間で関数オブジェクトの参照している変数を単にセットする
だけの実行文です(この変数の名前が関数名になります)。
したがって、クラスを取り扱うために完全に異なったアプローチを取るのではなく、
クラスの本体をただ単純に新しい名前空間で実行される文の並びであるように解釈する
というのがわたしにとって意味のあるものだったのです。
その名前空間の辞書はクラス辞書を初期化しさらにクラスオブジェクトを生成するために
capture され使われます。
Underneath the covers,
the specific approach taken is
クラスの本体をそれに含まれている文の全てを実行し、
その後でローカル変数のための resulting 辞書を返す
無名関数に turn into するというものです。
この辞書はそれからクラスオブジェクトを生成したヘルパー関数に渡されます。
最終的にこのクラスオブジェクトはそのクラスを囲むスコープに属する
(名前がクラス名と同じである) 変数に格納されます。
ユーザーは、正当なPython の文の任意の並びを
クラス本体に置くことができるということを学んでびっくりすることが頻繁にあります。
この能力は構文を、便利のために恣意的な制限を設けたりしないようにすると同時に
単純に保ちたいというわたしの願望を straightforward に拡張したもので
A final detail is the class instantiation (instance creation) syntax. Many languages,
like C++ and Java, use a special operator, “new”, to create new class instances. In
C++ this may be defensible since class names have a rather special status in the
parser, but in Python this is not the case. I quickly realized that, since Python's
parser doesn't care what kind of object you call, making the class object itself
callable was the right, “minimal” solution, requiring no new syntax. I may have been
ahead of my time here ― today, factory functions are often the preferred pattern for
instance creation, and what I had done was simply to turn each class into its own
factory.
A final detail はインスタンシエーション (インスタンスの生成) 構文です。
C++ や Java など多くの言語では新しいクラスインスタンスを生成するのに特殊な演算子
“new” を使っています。C++ ではクラス名がパーザーにとって特別なステータスを
持つものであるので、これはおそらく defensible (正当なものとして認められる)ですが、
Python ではこれにはあてはまりません。
I quickly realized that,
Python のパーザーがあなたが呼び出したオブジェクトの種類について注意しないので
making the class object itself callable was the right,
クラスオブジェクトそのものを呼び出し可能なものとする
“minimal” solution を採用することによって新しい構文を要求することもなかったのです。
I may have been ahead of my time here ―
今日、ファクトリ関数はしばしばインスタンス生成の preferred pattern であり、
わたしが行ったことはただ単にクラスをそれぞれ固有のファクトリに対応させただけなのです。
Special Methods(特殊メソッド)
As briefly mentioned in the last section, one of my main goals was to keep the
implementation of classes simple. In most object oriented languages, there are a
variety of special operators and methods that only apply to classes. For example, in
C++, there is a special syntax for defining constructors and destructors that is
different than the normal syntax used to define ordinary function and methods.
先のセクションで簡単に言及したように、
わたしの主目標のひとつはクラスの実装をシンプルに保つということでした。
大部分のオブジェクト指向言語では
クラスに対してのみ適用されるような多様な特別な演算子やメソッドがあります。
たとえば C++を例に取ると、
普通の関数やメソッドを定義するのに使われる通常の構文とは異なった
コンストラクターやデストラクターを定義する特別な構文がありました
I really didn't want to introduce additional syntax to handle special operations for
objects. So instead, I handled this by simply mapping special operators to a
predefined set of "special method" names such as __init__ and __del__. By
defining methods with these names, users could supply code related to the construction
and destruction of objects.
わたしは本当に
オブジェクトに対する特殊な操作を取り扱うために新しい構文を持ち込みたくはなかったのです。
わたしは新しい構文を持ち込む代わりに、単純に
__init__ や __del__ のようなあらかじめ決められていた“特殊な名前”に対して
特殊演算子をマッピングすることによって対処しました。
こういった名前を持つメソッドを定義することによって
ユーザーはオブジェクトの構築やは気に関連したコードを supply できるようになったのです。
I also used this technique to allow user classes to redefine the behavior of Python's
operators. As previously noted, Python is implemented in C and uses tables of function
pointers to implement various capabilities of built-in objects (e.g., “get attribute”,
“add” and “call”). To allow these capabilities to be defined in user-defined
classes, I mapped the various function pointers to special method names such as
__getattr__, __add__, and __call__. There is a direct correspondence between these
names and the tables of function pointers one has to define when implementing new
Python objects in C.
わたしはまたこのテクニックをユーザークラスにおいて
Pythonの演算子の振る舞いを再定義できるようにするためにも使いました。
すでに述べているようにPython はCを使って実装されていて、
関数ポインターのテーブルを(“get attribute”,“add” and “call”).
のような組み込みオブジェクトの various capabilities
を実装するために使っていました。
こういったユーザー定義クラスの中で定義が行える能力を可能とするために
こういった __getattr__, __add__, __call__ とのような名前を持った特殊メソッド名に対して
さまざな関数ポインターをマップしました。
こういった名前とCで新しいPython オブジェクトを実装するときには定義しなければならない
関数ポインターのテーブルとの間には direct correspondenceがありました。
Posted by Guido van Rossum at 11:25 AM