0

この初心者の質問で申し訳ありませんが、答えは簡単だと思いますが、まだわかりません。

いくらか読んでも、オブジェクト指向プログラミングにはまだ理解できない闇があります。メソッドを呼び出すためにクラスの中間インスタンスを作成する必要があることを確認したのは 2 回目です。urllibドキュメントから以下の例を確認してください。

import urllib
opener = urllib.FancyURLopener({})
f = opener.open("http://www.python.org/")
f.read()

openerメソッドを呼び出すためにインスタンスを作成する必要がある理由がわかりませんopen。次のコードが機能しない理由がわかりません:

import urllib
f = urllib.FancyURLopener.open("http://www.python.org/")
f.read()

を呼び出そうとするとエラーが発生しますurllib.FancyURLopener.open:

TypeError: unbound method open() must be called with FancyURLopener instance as first argument (got str instance instead)

この影に光をもたらしてくれませんか?どうもありがとう !

4

2 に答える 2

1

ここでは、クラスの「中間インスタンス」を作成しているのではなく、クラスのインスタンス (必要に応じて「プライマリ」インスタンスと呼びます) を作成しています。

ここでFancyURLopenerは、クラス自体の名前です。クラスはタイプです:

>>> import urllib
>>> type(urllib.FancyURLopener)
<type 'classobj'>

(それが<type 'classobj'>代わりにあるという事実<type 'type'>は、これが Python2 の「古いスタイル」のクラスの 1 つであることを示していますが、それは完全に別の質問の主題です :-) )。型であるため、実際に使用するには、通常、その型のオブジェクトを作成する必要があります。似たようなもの: いくつかの整数を使用するには、int型を参照するだけでなく、整数を作成する必要があります。

クラスタイプには、一連の「クラスメソッド」があります (つまり、参照できます)。これは、実際には「状態ホルダー変数を取る関数」にすぎません。通常はself. したがって、次のタイプのインスタンスを作成します。

>>> x = urllib.FancyURLopener()

x.open(...)そして今、実際に意味する関数を呼び出すことができます: urllib.FancyURLopener.open(x, ...). これにより、内部のコードは、内部urllib.FancyURLopenerにあらゆる種類の状態を隠しておくことができますx。HTTP 接続で持続性を使用したいですか? x接続がまだ開いているかどうかについて、何らかの状態を内部に保持します。いくつかの Web サーバー Cookie を操作したいですか? xそれらを追跡するのに役立つように、内部にいくつかの状態を保持します。あなた (urllib の作成者) が望むものは何でも、x. 関数が呼び出されると、呼び出し元がxとして取得され、selfself.whatever格納された状態になりxます。

(Python は実際には、この隠れていると思われるすべての状態を呼び出し元に公開するため、メンバー名を使用_spam__eggsて邪魔にならないようにしていますが、これも単純な「理由」から離れています。)

于 2013-06-24T02:55:49.527 に答える
0

urllib has many different types of openers. Well, ok, it has a couple, not many, but that's beside the point. If you call urllib.open the way you want, how is urllib supposed to know which opener you intend to use?

It knows this because your "intermediate step" created an instance of a particular type of opener. If you create an instance of FancyURLOpener, python will know that that is the particular type of opener that you want. If you want to use URLOpener instead, create an instance of that, and then you can use it instead.

Don't think of this as an intermediate step, think of it as the step -- the way to tell python "this is the specific type of url opener I want to use".

Now, of course, python could have been written in a non-OO way and had you tell the open method what type of opener you wanted to use. For example, a non-OO way might have you do this: f = urllib.open({}, type="Fancy"). That could work, right? Many people write code in that style and it works, so why bother with objects?

Using an object oriented method means you can create your own opener with its own special properties. For example, the documentation for the fancy version says it "[provides] default handling for the following HTTP response codes: 301, 302, 303, 307 and 401". What if you also want default handling of 404? You might call this the CJOpener, but in order to use it you would have to modify urllib itself to take "CJ" as well as "Fancy" as that last parameter. Do you really want to be modifying the built-in python code?

Classes and objects are the solution. The class defines the interface -- the standard way that an opener should work. You are free to create your own variations, and all you have to do is create a subclass, and then create an instance of that subclass. Once you do that, any python code anywhere in the world that knows how to work with FancyURLOpener and URLOpener instantly knows how to work with your opener, too.

So, the advantage of this intermediate step is a convenient way to tell python which variation of a common API you want to use. All programs that know how to use this API will also know how to use your version of the API too (assuming you don't break the standard API).

于 2013-06-24T02:41:54.390 に答える