Как работают классы Python? - PullRequest
       10

Как работают классы Python?

4 голосов
/ 16 февраля 2009

У меня есть файл кода из фреймворка boto, вставленный ниже, все операторы печати принадлежат мне, и одна закомментированная строка тоже моя, все остальное принадлежит указанному автору.

Мой вопрос заключается в том, в каком порядке создаются экземпляры и распределения в python при создании экземпляра класса? Приведенный ниже код автора основан на предположении, что DefaultDomainName будет существовать при создании экземпляра класса (например, вызывается __init __ ()), но, похоже, это не так, по крайней мере в моем тестировании в python 2.5 OS X.

В методе менеджера класса __init __ () мои операторы печати отображаются как 'Нет'. И операторы печати в глобальной функции set_domain () далее показывают «None» до установки Manager.DefaultDomainName и показывают ожидаемое значение «test_domain» после назначения. Но при повторном создании экземпляра Manager после вызова set_domain () метод __init __ () по-прежнему показывает «None».

Может кто-нибудь помочь мне и объяснить, что здесь происходит. Это будет с благодарностью. Спасибо.



# Copyright (c) 2006,2007,2008 Mitch Garnaat http://garnaat.org/
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish, dis-
# tribute, sublicense, and/or sell copies of the Software, and to permit
# persons to whom the Software is furnished to do so, subject to the fol-
# lowing conditions:
#
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.

import boto
from boto.utils import find_class

class Manager(object):

    DefaultDomainName = boto.config.get('Persist', 'default_domain', None)

    def __init__(self, domain_name=None, aws_access_key_id=None, aws_secret_access_key=None, debug=0):
        self.domain_name = domain_name
        self.aws_access_key_id = aws_access_key_id
        self.aws_secret_access_key = aws_secret_access_key
        self.domain = None
        self.sdb = None
        self.s3 = None
        if not self.domain_name:
            print "1: %s" % self.DefaultDomainName
            print "2: %s" % Manager.DefaultDomainName
            self.domain_name = self.DefaultDomainName
            #self.domain_name = 'test_domain'
            if self.domain_name:
                boto.log.info('No SimpleDB domain set, using default_domain: %s' % self.domain_name)
            else:
                boto.log.warning('No SimpleDB domain set, persistance is disabled')
        if self.domain_name:
            self.sdb = boto.connect_sdb(aws_access_key_id=self.aws_access_key_id,
                                        aws_secret_access_key=self.aws_secret_access_key,
                                        debug=debug)
            self.domain = self.sdb.lookup(self.domain_name)
            if not self.domain:
                self.domain = self.sdb.create_domain(self.domain_name)

    def get_s3_connection(self):
        if not self.s3:
            self.s3 = boto.connect_s3(self.aws_access_key_id, self.aws_secret_access_key)
        return self.s3

def get_manager(domain_name=None, aws_access_key_id=None, aws_secret_access_key=None, debug=0):
    return Manager(domain_name, aws_access_key_id, aws_secret_access_key, debug=debug)

def set_domain(domain_name):
    print "3: %s" % Manager.DefaultDomainName
    Manager.DefaultDomainName = domain_name
    print "4: %s" % Manager.DefaultDomainName

def get_domain():
    return Manager.DefaultDomainName

def revive_object_from_id(id, manager):
    if not manager.domain:
        return None
    attrs = manager.domain.get_attributes(id, ['__module__', '__type__', '__lineage__'])
    try:
        cls = find_class(attrs['__module__'], attrs['__type__'])
        return cls(id, manager=manager)
    except ImportError:
        return None

def object_lister(cls, query_lister, manager):
    for item in query_lister:
        if cls:
            yield cls(item.name)
        else:
            o = revive_object_from_id(item.name, manager)
            if o:
                yield o

Ответы [ 4 ]

9 голосов
/ 16 февраля 2009

Несколько заметок на питоне

Когда python выполняет блок class , он создает все «атрибуты» этого класса, когда встречается с ними. Обычно это переменные класса, а также функции (методы) и т. П.

Таким образом, значение «Manager.DefaultDomainName» устанавливается, когда оно встречается в определении класса. Этот код запускается только один раз - больше никогда. Причина этого в том, что он просто «определяет» объект класса с именем «Manager».

Когда создается объект класса «Менеджер», он является экземпляром класса «Менеджер». (это может звучать многократно). Чтобы быть совершенно понятным, значение:

self.DefaultDomainName

не существует. Следуя правилам классов, python говорит: «Хм, этого экземпляра объекта не существует, я посмотрю на объект (ы) класса». Таким образом, python фактически находит значение в:

Manager.DefaultDomainName

# also referenced by
self.__class__.DefaultDomainName

Все это служит примером того, что атрибут класса «Manager.DefaultDomainName» создается только один раз, может существовать только один раз и может содержать только одно значение за один раз.


В приведенном выше примере запустите встроенную функцию id () для каждого из значений:

print "1: %s" % id(self.DefaultDomainName)
print "2: %s" % id(Manager.DefaultDomainName)

Вы должны увидеть, что они относятся к одной и той же ячейке памяти.


Теперь, в (не) ответ на первоначальный вопрос ... Я не знаю, просматривая код выше. Я бы посоветовал вам попробовать несколько методов, чтобы выяснить это:

# Debug with pdb.  Follow every step of the process to ensure that you are 
# setting valeus as you thought, and that the code you thought would be 
# called is actually being called.  I've had many problems like this where 
# the error was in procedure, not in the actual code at hand.
import pdb; pdb.set_trace()

# check to see if id(Manager) is the same as id(self.__class__)

# in the set_domain() function:
# check to see what attributes you can see on Manager, 
# and if they match the attributes on Manager and self.__class__ in __init__

Пожалуйста, обновите здесь, когда вы разберетесь.

1 голос
/ 16 февраля 2009

Спасибо всем за помощь. Я понял, чего мне не хватало:

Определения классов используемых мной классов boto содержат переменные класса для Manager, которые, в свою очередь, служат значением по умолчанию, если в __init__() этих классов не передается Manager. Я даже не думал о том, что эти переменные класса будут оцениваться с помощью оператора import при импорте модулей, содержащих эти классы.

Таким образом, значения self.domain_name этих переменных класса были установлены из DefaultDomainName еще до того, как я даже вызвал set_domain(), и поскольку у меня нет настроек файлов конфигурации, как указано в ruds, это значение было None.

Итак, я должен немного переделать свой код, но спасибо всем за помощь новичку в Python.

1 голос
/ 16 февраля 2009

Что сказал гагуа. Кроме того, я предполагаю, что boto.config.get(...) возвращает None, предположительно потому, что ключ default_domain не определен в разделе Persist вашего конфигурационного файла.

boto.config определяется в boto/__init__.py как config = boto.pyami.config.Config() (по существу). boto.pyami.config.Config является подклассом стандарта ConfigParser.SafeConfigParser, и он ищет файлы конфигурации в местах, указанных boto.pyami.BotoConfigLocations, по умолчанию это список, содержащий /etc/boto.cfg и $HOME/.boto. Если у вас нет конфигурации в любом из этих расположений, у вас не будет имени домена по умолчанию.

0 голосов
/ 16 февраля 2009

при загрузке модуля python выполняет каждый код построчно. Поскольку код выполняется, все переменные класса должны быть установлены во время загрузки. Скорее всего, ваша функция boto.config.get была только что возвращена. Нет. Другими словами, да, все переменные класса размещаются перед переменными экземпляра.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...