klrk
Янв. 27, 2011 00:05:56
Добрый вечер!
Недавно начал разбираться с ООП в Python, и при написании небольшого скрипта столкнулся со следующей проблемой:
class Bot(object):
def __init__(self):
self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookielib.CookieJar()))
# subclasses
self.Auth = Auth()
self.Info = Info()
# more subclasses
def __setProxy(self, proxy):
self.opener.add_handler(urllib2.ProxyHandler({'http' : proxy}))
pass
class Auth(Bot):
def __init__(self):
self.login = None
self.passw = None
self.sid = None
def LoginAuth(self, login, pwd, proxy={}):
if proxy:
self.__setProxy(proxy)
self.login, self.passw = login, pwd
data = urllib.urlencode(
{
'login' : self.email,
'password' : self.passw
}
)
html = self.opener.open("http://...", data).read()
if (html.find("authorized") != -1):
return True
return False
def CookieAuth(self, cookie, proxy={}):
if proxy:
self.__setProxy(proxy)
self.sid = cookie
self.opener.addheaders = [
('Cookie', 'sid='+self.sid)
]
html = self.opener.open("http://...").read()
if (html.find("authorized") != -1):
return True
return False
class Info(Bot):
def __init__(self):
pass
# # # # # # # #
X = Bot()
X.Auth.CookieAuth("cookie")
Вылетает в строке
self.opener.addheaders = с AttributeError: ‘Auth’ object has no attribute ‘opener’. Подскажите, пожалуйста, что не так? И, возможно, будут какие-то рекомендации к архитектуре класса?
Заранее большое спасибо!
Андрей Светлов
Янв. 27, 2011 02:01:56
Вызывайте в конструкторе своего родителя.
И не называйте методы __method, не нужно..
pyuser
Янв. 27, 2011 02:03:17
Ну это и не удивительно :)
Ваш конструктор класса Auth нужно дополнить одной строкой:
super(Auth, self).__init__()
таким образом вы избавитесь от указанной ошибки (правда, при этом попадете в бесконечный цикл :()
klrk
Янв. 27, 2011 09:51:24
Андрей Светлов,
pyuser,
Большое спасибо за ответы!
Андрей Светлов
И не называйте методы __method, не нужно..
А почему? Читал, что по-настоящему приватных методов в Питоне нету, и к __method всё-равно можно будет обратиться через Class._Class__method, но почему-то решил использовать :) Причина неиспользования в этом, или есть что-то ещё?
pyuser
таким образом вы избавитесь от указанной ошибки (правда, при этом попадете в бесконечный цикл sad)
А какие последствия этого?
pyuser
Янв. 27, 2011 10:46:37
klrk
А какие последствия этого?
Не попробуете - не узнаете :D
Посмотрите на свой код, у Вас при создании объекта класса Bot создается объект класса Auth, при создании которого вызывается конструктор класса Bot, который, в свою очередь, снова попытается создать объект класса Auth, … и так до бесконечности :)
klrk
Янв. 27, 2011 12:22:42
pyuser, понятно, большое спасибо!
Мне бы не хотелось выносить всю реализацию в Bot, гораздо нагляднее, как мне кажется, с текущей структурой - Bot.Auth.method1 и т.п.. Первое, что пришло на ум - в каждом саб-классе хранить копию opener из Bot, но почему-то не нравится мне такой метод :)
А что бы Вы посоветовали в этой ситуации?
Soteric
Янв. 27, 2011 12:51:17
Что такое Bot и что такое Auth и почему один является наследником другого?
В вашем примере Auth не наследник Bot, а его свойство.
klrk
Янв. 27, 2011 13:36:18
Soteric, спасибо, уже понял эту ошибку. А есть ли какие-то способы доступа к атрибуту базового класса (в данном случае Bot.opener) из методов свойства (Bot.Auth)?
Soteric
Янв. 27, 2011 13:57:12
Не понял вопроса. Если некий экземпляр Auth является свойством Bot, то чтобы получить доступ к методам Bot, ему также необходимо иметь на него ссылку в виде свойства/поля (и здесь не играет роли кто чьим родителем/наследником является). Если Auth является наследником Bot, то он может обращаться ко всем открытым методам своего родителя как к своим (при этом Bot.Auth как я уже сказал не является отношением родитель-наследник и Auth здесь никак не может управлять Bot - они здесь два разных независимых друг от друга объекта). Лучше объясните что вы пытаетесь получить, какую смысловую нагрузку несут ваши классы Bot, Auth и Info, а вам объяснят как правильно организовать между ними связь (в виде наследования или нет). Потому что сейчас особой связи между ними я не вижу.
klrk
Янв. 27, 2011 14:31:54
Soteric,
Есть сайт, на котором нужно программно имитировать поведение человека (Bot). Бот должен проходить авторизацию различными методами (саб-класс Auth)/менять различную информацию (Info)/и т.д. Можно, конечно, реализовать все это в Bot, добавляя к имени каждого метода тип его применения (вроде Bot.AuthByMail()), но т.к. для каждого типа методов может быть достаточно много, мне захотелось “выделить” из в отдельные классы (Bot.Auth.byMail()).
Проблема заключается в том, что все вспомогательные классы для соединения с сайтом должны использовать opener, описанный в Bot, и я не нашел способа, как сделать это без явной передачи этого атрибута в конструктор каждого из подклассов.