Копия списка Python и который использовать в качестве переменной класса

#python #python-3.x #list #class #copy

#python #python-3.x #Список #класс #Копировать

Вопрос:

Я смущен следующими результатами, поскольку, насколько я понимаю, [:] выполняется неглубокая копия, и когда вы меняете либо старый список, либо недавно скопированный, оба они должны измениться? (Это было показано на одном из курсов Coursera, которым я следую). Также, если я хочу объявить список как переменную класса, с намерением, которое является значениями по умолчанию, и дочерние классы могут переопределить его / изменить его, если захотят, но родительский должен оставаться неизменным, это правильный способ сделать это? Большое спасибо за вашу помощь.

 oldlist=[["a"],"b"]
newlist= oldlist[:]
newlist[0]="2"
oldlist[0].append(["c"])
print(oldlist) #printed out  [['a', ['c']], 'b']
print(newlist) #printed out ['2', 'b']

class Book():
similar_books =['book one','book two']
def __init__ (self, n, l):
    self.name= n
    self.like = l
    self.similar_books = self.similar_books[:]  # is it the correct way to do so?
 

Комментарии:

1. Я думаю, вы получаете желаемое поведение из кода. вы можете продолжить таким же образом.

2. Я думаю, вам следует вместо этого использовать Google: «статическое свойство в pyhton»..

Ответ №1:

Согласно официальной документации Python, фрагмент списка является мелкой копией. В этом случае мелкая копия создает новый составной объект, а затем вставляет ссылку на исходный содержащийся объект. Когда «2» присваивается индексу [0] newlist, ссылка перезаписывается, и newlist больше не является составным объектом. Если бы вы добавили только [«c»] к индексу [0] oldlist, вы получили бы ожидаемое поведение при мелком копировании.

Для второй части вашего вопроса объекты, инициализированные внутри родительского класса (но вне конструктора), являются статическими и не будут переопределены или изменены дочерними классами. Из любопытства, почему бы просто не назначить [‘book one’,’book two’] непосредственно self.similar_books в методе init?

 class Book(object):
    def __init__(self, n, l):
        self.name = n
        self.like = l
        self.similar_books = ['book one', 'book two']


class FavouriteBook(Book):
    def __init__(self):
        super().__init__('name', 'like')
        self.similar_books = ['book_3']
 

Комментарии:

1. Спасибо. Идея заключается в том, что если есть дочерний класс, по умолчанию дочерний класс будет иметь similar_books=['book one','book two'] , но дочерний класс также может сделать что-то подобное, чтобы определить свой собственный similar_book атрибут : class FavouriteBook(Book): similar_books = ['book3'] . Таким образом FavouriteBook , класс имеет book3 вместо book 1 и 2 как similar_book . Это правильный путь?

2. Инициализация similar_books=['book one','book two'] перед конструктором является избыточной. Я предполагаю, что вы вызовете суперконструктор для присвоения имени и типа дочернему классу, super().__init__('name', 'like') . Как только вы вызываете суперконструктор, дочерний класс наследует similar_books , который затем можно переопределить self.similar_books = ['book_3'] . Ответ обновлен примером.