2013-06-24 2 views
0

Извините за этот новичок вопрос ребята, я уверен, что ответ прост, но я до сих пор его не понимаю.Зачем определять промежуточные экземпляры для вызова метода в Python?

Несмотря на некоторое чтение, объектно-ориентированное программирование все еще имеет темноту, я не понимаю. Во второй раз я вижу, что необходимо создать промежуточный экземпляр класса для вызова метода. Проверьте приведенную ниже пример из 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) 

Не могли бы вы, ребята, принести свет в этой тени? Большое спасибо !

+1

Ответ Игнасио правильный, но для разработки «FancyURLopener» является * классом *, тогда как FancyURLopener ({}) 'является * экземпляром * класса. Метод 'open' работает только при вызове из экземпляра. В сообщении об ошибке говорится о том, что экземпляр является «первым аргументом», который немного запутан, но имеет смысл, если вы понимаете, что методы экземпляра определяются как «self» (текущий экземпляр) в качестве первого аргумента. – Fraxtil

+0

Я не получил ваш ответ в первый раз, когда я прочитал его, но после прочтения, что ниже, это совершенно разумно. Спасибо! –

ответ

1

Здесь вы не создаете «промежуточный экземпляр» класса, вы создаете экземпляр (называете его «основным», если хотите) классом.

Здесь FancyURLopener - это название самого класса. Класс является типа:

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

(тот факт, что это <type 'classobj'> вместо <type 'type'> говорит вам, что это один из «старого стиля» классов python2, но это тема для другого вопроса :-)). Поскольку это тип, чтобы использовать его, вам обычно нужно создать объект такого типа. Вид, похожий на: для использования некоторых целых чисел, вы должны делать целые числа, а не просто ссылаться на тип int.

Тип класса имеет (то есть, позволяет вам ссылаться) кучу «методов класса», которые на самом деле являются «функциями, которые принимают переменную держателя состояния», которую мы обычно накладываем на self. Таким образом, вы создаете экземпляр типа:

>>> x = urllib.FancyURLopener() 

и теперь вы можете вызывать функции с x.open(...), которые на самом деле означает: urllib.FancyURLopener.open(x, ...). Это позволяет использовать код внутри urllib.FancyURLopener, чтобы скрыть все виды состояний внутри x. Хотите, чтобы HTTP-соединения использовали постоянство? Сохраняйте какое-либо состояние внутри x относительно того, все ли соединение открыто. Хотите манипулировать некоторыми веб-серверами? Держите некоторое состояние внутри x, чтобы помочь отследить их. Все, что вы (писатель urllib) хотите, можете вставить его в x. Когда вы вызываете свои функции, вы получаете x вызывающего абонента в качестве self, а self.whatever - это состояние, заключенное в x.

(Python фактически выставляет все это якобы скрытое состояние вызывающей стороны, так что люди используют _spam и __eggs имен членов, чтобы помочь сохранить их в стороне, но опять-таки, что получает от простого «почему».)

+0

«Поскольку это тип, на самом деле его использовать, вы, как правило, должны создавать объект такого типа. Подобно тому, как использовать некоторые целые числа, вы должны делать целые числа, а не просто ссылаться на тип' int'. Хорошо! Как я понимаю, «FancyURLopener» является классом модуля «urllib», так же как «array» является классом модуля «numpy». Не так ли? Так что имеет смысл, что мне нужно создать экземпляр класса с 'opener = urllib.FancyURLopener()' перед тем, как использовать метод 'open()' этого класса! спасибо! –

0

Урлиб имеет много разных типов открывалок. Ну, ладно, у него есть пара, а не много, но это не относится к делу. Если вы вызываете urllib.open так, как вы хотите, как должен урлиб знать, какой нож вы собираетесь использовать?

Он знает об этом, потому что ваш «промежуточный шаг» создал экземпляр определенного типа открывателя. Если вы создадите экземпляр FancyURLOpener, python будет знать, что это особый тип открывателя, который вы хотите. Если вы хотите вместо этого использовать URLOpener, создайте экземпляр , который, а затем вы можете использовать его вместо этого.

Не думайте об этом как о промежуточном шаге, думайте об этом как шаг - способ рассказать python «это конкретный тип открывателя url, который я хочу использовать».

Теперь, конечно, питон мог быть написан не-OO-способом, и если бы вы сказали открытому методу, какой тип открывателя вы хотели использовать. Например, способ, отличный от OO, мог бы сделать это: f = urllib.open({}, type="Fancy"). Это может сработать, да? Многие люди пишут код в этом стиле, и он работает, так зачем беспокоиться об объектах?

Использование объектно-ориентированного метода означает, что вы можете создать свой собственный нож с его собственными специальными свойствами. Например, в документации для причудливой версии говорится, что «[предоставляет] обработку по умолчанию для следующих кодов ответов HTTP: 301, 302, 303, 307 и 401». Что делать, если вам также нужна обработка по умолчанию 404? Вы можете назвать это CJOpener, но для его использования вам придется самому изменить urllib, чтобы взять «CJ», а также «Fancy» в качестве последнего параметра. Вы действительно хотите изменить встроенный код python?

Классы и объекты являются решением. Класс определяет интерфейс - стандартный способ, которым должен работать открыватель. Вы можете создавать свои собственные варианты, и все, что вам нужно сделать, это создать подкласс, а затем создать экземпляр этого подкласса. Как только вы это сделаете, любой код python в любой точке мира, который знает, как работать с FancyURLOpener и URLOpener, мгновенно знает, как работать с вашим открывателем.

Итак, преимущество этого промежуточного шага - удобный способ рассказать python о том, какой вариант использования обычного API вы хотите использовать. Все программы, которые знают, как использовать этот API, также будут знать, как использовать вашу версию API тоже (при условии, что вы не нарушите стандартный API).

+0

Спасибо за объяснение преимуществ на занятия! Я обязательно запомню эти мудрые слова! –

Смежные вопросы