Модуль Python / Переменная кровотечения класса - PullRequest
0 голосов
/ 24 апреля 2009

Хорошо, мне потребовалось немного времени, чтобы сузить эту проблему, но похоже, что Python делает эту единственную цель. Может кто-нибудь объяснить, почему это происходит и что я могу сделать, чтобы это исправить?

Файл: library / testModule.py

class testClass:

    myvars = dict()

    def __getattr__(self, k):
        if self.myvars.has_key(k):
            return self.myvars[k]

    def __setattr__(self, k, v):
        self.myvars[k] = v

    def __str__(self):
        l = []
        for k, v in self.myvars.iteritems():
            l.append(str(k) + ":" + str(v))

        return " - ".join(l)

test.py

from library import testModule

#I get the same result if I instantiate both classes one after another
c1 = testClass()
c1.foo = "hello"
c2 = testClass()

print("c1: " + str(c1) + "\n")
print("c2: " + str(c2) + "\n")

Выход:

c1: foo:hello
c2: foo:hello

Мое лучшее предположение состоит в том, что, поскольку library имеет файл "__init__.py", весь модуль загружается как объект класса, и теперь он становится частью долговременного объекта ... это так?

Ответы [ 3 ]

7 голосов
/ 24 апреля 2009

myvars является свойством класса , а не экземпляра . Это означает, что когда вы вставляете атрибут в myvars из экземпляра c1, атрибут связывается с классом testClass, а не конкретно с экземпляром c1. Поскольку c2 является экземпляром того же класса, он также имеет тот же атрибут.

Вы можете получить желаемое поведение, написав это:

class testClass:
    def __init__(self):
        self.myvars = dict()

    def __getattr__(self, k):
        if self.myvars.has_key(k):
            return self.myvars[k]

    def __setattr__(self, k, v):
        self.myvars[k] = v

    def __str__(self):
        l = []
        for k, v in self.myvars.iteritems():
            l.append(str(k) + ":" + str(v))
        return " - ".join(l)
2 голосов
/ 24 апреля 2009

Остальные ответы верны и точны. Позвольте мне остановиться на некоторых из ваших заблуждений.

Мое лучшее предположение состоит в том, что поскольку библиотека имеет файл "__init__.py", весь модуль загружается как объект класса, и теперь он становится частью долговременного объекта ... это так?

Все пакеты имеют файл __init__.py. Нужно сделать что-то пакет python. Этот пакет может содержать или не содержать код. Если это так, то гарантированно выполнится. В общем случае это не имеет никакого отношения к тому, как выполняются другие модули в пакете, хотя, безусловно, можно добавить много действительно классных хитростей, которые на него влияют.

Что касается того, как работают модули и классы, часто очень полезно думать о модуле как об объекте класса, экземпляр которого создается один раз. Загрузчик выполняет файлы один раз, и все переменные, определения классов и определения функций, доступные в конце файла, становятся доступными как часть модуля.

То же самое относится и к классам, за исключением того, что функции, объявленные внутри классов, преобразуются в методы (и один специальный метод позволяет создать экземпляр класса). Итак, testModule имеет-101 * имеет-1015 *. Все три объекта уникальны: не будет нескольких экземпляров ни одного из них. И отношение has-a действительно более или менее одинаково, говорим ли мы «модуль имеет-объект класса» или «объект класса имеет-переменную класса». (Разница заключается в деталях реализации, которые вас не должны касаться.)

0 голосов
/ 24 апреля 2009

Хорошую справку о том, как использовать getattr и другие подобные методы, смотрите в Руководстве по использованию дескрипторов , и нет ничего подобного практике!

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