2013-03-12 3 views
1

Я пытаюсь скомпоновать некоторый пример кода, и я столкнулся с чем-то, что для меня не имело смысла. Не включая весь источник, я постараюсь настроить таргетинг на то, что я считаю важными разделами, и, надеюсь, я получу все это.Подкласс Dict, Переменные класса

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

class Payment(dict): 
    customer = film = None 

А вот где он использует Оплата ...

columns = [item[0] for item in cursor.description] 
payments = [] 
for row in cursor.fetchall(): 
    payment = Payment(zip(columns, row)) #I believe this is where he loads dict items 
    payment.customer = customers[payment["customer_id"]] #This is where he assigns 'class variable' 
    payment.film = films[payment["film_id"]] 
    payments.append(payment) 

В окончательном списке, не должны ли все «платежи» иметь одинаковые значения (которые, как оказалось, являются еще одним типом)? Вот где мое замешательство.

Оказалось, что эти два атрибута имеют уникальные значения по всей доске. Это связано с подклассом Dict? Скопированы ли значения, а не ссылки (так что технически они являются переменными класса, но поскольку они скопированы, они по-прежнему остаются уникальными).

Просто, когда я думал, что я понял простую механику OO, это бросает меня ...

ответ

4

В следующем:

payment.customer = customers[payment["customer_id"]] #This is where he assigns 'class variable' 
payment.film = films[payment["film_id"]] 

вы не изменяя значения payment.customer и payment.film. Вместо этого вы являетесь , переустанавливая их, что делает их специфичными для экземпляра .

Рассмотрим следующий пример:

class X(object): 
    val = ['orig'] 

x1 = X() 
x2 = X() 
x3 = X() 
x1.val = ['rebound']  # rebind 
x2.val[0] = 'modified' # modify in place 
print x1.val, id(x1.val) 
print x2.val, id(x2.val) 
print x3.val, id(x3.val) 

Печатает

['rebound'] 2907552 
['modified'] 2771544 
['modified'] 2771544 

Обратите внимание, как x1.val становится совершенно отдельная переменная, как только это было отскока, в то время как x2.val и x3.val продолжают оба относятся к тому же списку ,

2

Когда Python просматривает атрибут объекта, он сначала смотрит на экземпляр, затем на класс, а затем на суперклассы.

После этого

payment = Payment(zip(columns, row)) #I believe this is where he loads dict items 

Вы можете проверить, что payment.__dict__ не имеет записей для customer или film

При попытке доступа (GetAttr) payment.film, так как экземпляр не имеет film атрибут, вы будете получите payment.__class__.film.

Присвоение атрибутов всегда (если это не дескриптор) будет создавать запись в экземпляре dict, и поэтому он изолирован от всех других экземпляров.

И некоторые переводчика весело:

>>> class C(dict): 
... foo = "class foo" 
... 
>>> c = C() 
>>> c.__dict__ 
{} 
>>> c.foo 
'class foo' 
>>> c.foo = "instance foo" 
>>> c.__dict__ 
{'foo': 'instance foo'} 
>>> c.foo 
'instance foo' 
>>> del c.foo 
>>> c.foo 
'class foo' 

Кстати, поскольку код в вашем примере не имеет доступа к этим атрибутам класса, это будет работать так же хорошо:

class Payment(dict): 
    pass 

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

+0

Я видел эту технику, используемую в случаях, когда создание экземпляра не всегда инициализирует все атрибуты экземпляра. В этом случае это может быть полезным способом присвоить значение по умолчанию атрибуту экземпляра, который может или не может быть инициализирован в экземпляре. «Пирамида» использует этот стиль довольно много. – Duncan

+0

Ответ NPE помог, но этот лучший иллюстрированный поиск атрибутов. Я думаю, я был в замешательстве, потому что обычно мой доступ к переменной переменной класса из экземпляра обычно доступен только для чтения. Я только пишу переменную класса из staticmethod. – user2097818

+0

Если бы я хотел рассматривать «foo» (как в вашем примере) как переменную класса явно из моего экземпляра, мне нужно будет использовать C.foo из моих методов экземпляра? (предположим, что переменная является целым числом) – user2097818

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