2012-02-27 1 views
4

Я одурачен тем, что, по моему мнению, является очень простым и прямым подклассом списка в Python.Подкласс списка в Python. Почему список и пустой список не работают?

Предположим, что я хочу всю функциональность списка. Я хочу добавить несколько методов к набору по умолчанию по умолчанию.

Ниже приведен пример:

class Mylist(list): 

    def cm1(self): 
     self[0]=10 

    def cm2(self): 
     for i,v in enumerate(self): 
      self[i]=self[i]+10   

    def cm3(self): 
     self=[]   

    def cm4(self): 
     self=self[::-1] 

    def cm5(self): 
     self=[1,2,3,4,5]  

ml=Mylist([1,2,3,4]) 
ml.append(5) 
print "ml, an instance of Mylist: ",ml 
ml.cm1() 
print "cm1() works: ",ml 

ml.cm2() 
print "cm2() works: ",ml 

ml.cm3() 
print "cm3() does NOT work as expected: ",ml  

ml.cm4() 
print "cm4() does NOT work as expected: ",ml  

ml.cm5() 
print "cm5() does NOT work as expected: ",ml 

Выход:

Mylist: [1, 2, 3, 4, 5] 
cm1() works: [10, 2, 3, 4, 5] 
cm2() works: [20, 12, 13, 14, 15] 
cm3() does NOT work as expected: [20, 12, 13, 14, 15] 
cm4() does NOT work as expected: [20, 12, 13, 14, 15] 
cm5() does NOT work as expected: [20, 12, 13, 14, 15] 

Таким образом, кажется, что скалярная назначение работает как я ожидаю и понять. Список или фрагменты не работают, как я понимаю. «Не работает», я имею в виду, что код в методе не меняет экземпляр ml, как это делают первые два метода.

Что нужно для этого, чтобы cm3()cm4() и cm5() работали?

+3

Это не относится к спискам. Это то, как имена и назначение работают в Python - назначение перепроверяет имя и никогда не изменяет объект, к которому в настоящее время привязано имя. –

+0

@Cat Plus Plus: Да, я подозревал это и понимаю. Можно переназначить список подклассов или использовать синтаксис среза? Я просто не знаю, как и не могу найти через goggle или Python docs. Я еще немного зеленый на классах Python ... – dawg

+0

Это зависит от того, что вы ожидаете от «переназначения». –

ответ

6

Проблема здесь состоит в том, что в cm3, cm4 и cm5, вы не изменяем объект! Вы создаете новую в рамках функции-члена, а затем присваиваете ее себе. Внешний охват этого не учитывает. В cm1 и cm2 вы изменяете один и тот же объект, чтобы объект оставался прежним.

Попробуйте использовать функцию id для отладки это:

def cm4(self): 
    self=self[::-1] 
    print 'DEBUG', id(self) 

... 

m1.cm4() 
print 'DEBUG', id(self) 

Вы увидите, что id отличается.

Итак, вы можете спросить, как это сделать? Вам повезло, что списки, которые вы можете назначить в сращивание. Это может быть не так просто с другими структурами данных. То, что это делает, хранит один и тот же список, но заменяет элементы. Для этого, сделайте следующее:

self[:] = ... 

Так, например:

self[:] = self[::-1] 
+2

Вот почему 'self' должен находиться в сигнатуре функций-членов (вы можете называть его любым, что хотите, до его первой позиции). За кулисами 'ml.cm3' превращается в' cm3 (ml) '(если есть аргументы, каждый из них отбрасывает позицию). Поэтому 'self' является передачей по ссылке, как и другие аргументы объекта, и вы просто меняете свою локальную ссылку. –

2

self[:] вместо self, self = ... будет переназначать переменную self только для другого объекта, который не изменит объект списка.

def cm3(self): 
    self[:]=[]   

def cm4(self): 
    self[:]=self[::-1] 

def cm5(self): 
    self[:]=[1,2,3,4,5] 
4

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

Вот перевыполнение ваших членов мутировать правильно:

def cm3(self): 
    self[:] = [] 

def cm4(self): 
    self.reverse() 

def cm5(self): 
    self[:] = [1,2,3,4,5]