Найти - Пользователи
Полная версия: Изменение элементов списка
Начало » Python для новичков » Изменение элементов списка
1
vanvanov
Приветствую!
Заранее извиняюсь, если слишком нубский вопрос или непонятно, чего хочу.
Допустим, есть такой код:
 #!/usr/bin/python3
# -*- coding: UTF-8 -*-
class Block:
    
    def __init__(self):
        self._text = ''
        self._type = ''
class Blocks:
    
    def __init__(self):
        self._blocks = []
    
    def add(self):
        self._blocks.append(Block())
    
    def transc(self):
        for block in self._blocks:
            if block._type == 'comment':
                block._type = 'transc'
Конкретно вопрос про присваивание внутри Blocks.transc. У меня достаточно давно возникла ситуация, когда изменение элементов списка внутри класса почему-то не срабатывало (не приводило к изменению self._blocks). Отследить проблему тогда не удалось, но с этого времени побаиваюсь делать просто что-то типа
 block._type =
и делаю
 self._blocks[i]._type =
. Вторая конструкция срабатывает всегда, но она слишком громоздкая. Поэтому вопрос: всегда ли будет работать присваивание по типу
 block._type =
и есть ли тут какие-нибудь подводные камни?
py.user.next
vanvanov
и есть ли тут какие-нибудь подводные камни?
Вообще неясно, что это за классы. Если поля должны меняться снаружи, то должен быть интерфейс для этого (набор методов, которые может вызывать пользователь у объекта). Если поля не могут меняться снаружи, то метод transc() вообще ничего никогда не сделает, так как все блоки всегда будут пустыми.

И если ты решил лезть руками прямо в поля, это вообще неправильно, так как код, который лезет в поля напрямую, цементирует их в программе, что приводит к неизменяемости программы. Если там будет обнаружен баг, ты его даже исправить не сможешь, потому что всё зацементировано.

Так что в идеале Block() должен иметь методы для установки полей. А Blocks.add() должен иметь аргумент принятия блока (Block() должен создаваться и подаваться снаружи, а не создаваться внутри).
vanvanov
Если поля не могут меняться снаружи, то метод transc() вообще ничего никогда не сделает, так как все блоки всегда будут пустыми.
Ничего не понял. Можете привести пример? У меня блоки не пустые:
 #!/usr/bin/python3
# -*- coding: UTF-8 -*-
class Block:
    
    def __init__(self):
        self._text = ''
        self._type = ''
class Blocks:
    
    def __init__(self):
        self._blocks = []
    
    def add(self):
        for i in range(5):
            self._blocks.append(Block())
    
    def change(self):
        for i in range(len(self._blocks)):
            self._blocks[i]._type = str(i)
        self._blocks[3]._type = 'comment'
    
    def transc(self):
        for block in self._blocks:
            if block._type == 'comment':
                block._type = 'transc'
    
    def print(self):
        for i in range(len(self._blocks)):
            print(i,':',self._blocks[i]._type)
    
    def run(self):
        self.add()
        self.change()
        self.transc()
        self.print()
if __name__ == '__main__':
    Blocks().run()
Так что в идеале Block() должен иметь методы для установки полей
У меня класс Block только хранит параметры, не более. Пользуюсь вместо словаря, потому что словарь в коде выглядит слишком громоздко и не всегда удобен. А здесь я просто вызвал класс, и он создал все нужные мне переменные - я могу не опасаться получить KeyError.
doza_and
vanvanov
когда изменение элементов списка внутри класса почему-то не срабатывало
надо разбираться а не опасаться.
Подводных камней в использовании списков внутри классов нет.
vanvanov
Пользуюсь вместо словаря
Тогда не надо подчеркивания ставить первой буквой. Так принято делать для закрытых для доступа полей
vanvanov
я могу не опасаться получить KeyError.
Для этого есть метод get
 >>> a={}
>>> a.get(1,2)
2
.
py.user.next
vanvanov
Ничего не понял. Можете привести пример? У меня блоки не пустые:
Так ты первый код в вопросе вообще другой написал. В самом начале вопроса код вообще бессмысленный.

vanvanov
У меня класс Block только хранит параметры, не более.
Значит они не должны быть приватными, как написал doza_and.

vanvanov
Поэтому вопрос: всегда ли будет работать присваивание по типу
  
block._type =
и есть ли тут какие-нибудь подводные камни?
Будет работать, никаких подводных камней тут нет. Поизучай тему привязывания имён в питоне.
https://docs.python.org/3/reference/executionmodel.html#naming-and-binding
vanvanov
doza_and
Тогда не надо подчеркивания ставить первой буквой. Так принято делать для закрытых для доступа полей
Я в курсе, но как еще различать переменные и методы? Венгерская нотация в Питоне как-то не прижилась. Имхо, отмечать переменные как “закрытые для доступа” достаточно логично, поскольку код яснее, когда какой-либо метод класса возвращает значение, а не когда сторонний класс дергает не свои переменные. К тому же, есть ведь и __такие, и __такие__ закрытые методы. Но это все сугубо мое имхо. Объясните, пожалуйста, как лучше.
py.user.next
vanvanov
Я в курсе, но как еще различать переменные и методы?
Прочитай PEP8
https://www.python.org/dev/peps/pep-0008/#naming-conventions
https://www.python.org/dev/peps/pep-0008/#designing-for-inheritance
Public attributes should have no leading underscores.



For simple public data attributes, it is best to expose just the attribute name, without complicated accessor/mutator methods. Keep in mind that Python provides an easy path to future enhancement, should you find that a simple data attribute needs to grow functional behavior. In that case, use properties to hide functional implementation behind simple data attribute access syntax.

vanvanov
Объясните, пожалуйста, как лучше.
Ты бы читал книги, там бы тебя отослали к PEP'ам. А так ты пытаешься сам догадаться, что и зачем. Потеряешь время только впустую и придёшь всё равно к тому, что в книгах и документации описано.
vanvanov
Спасибо за рекомендации.
Только что натолкнулся на пример:
 #!/usr/bin/python3
# -*- coding: UTF-8 -*-
import urllib.parse
class Test:
    
    def __init__(self,url):
        self._url = url
    
    '''
    def quote(self):
        self._url = list(self._url)
        for symbol in self._url:
            if not symbol in (':','/','=','&','?'):
                symbol = urllib.parse.quote(symbol)
        self._url = ''.join(self._url)
    '''
    
    def quote(self):
        self._url = list(self._url)
        for i in range(len(self._url)):
            if not self._url[i] in (':','/','=','&','?'):
                self._url[i] = urllib.parse.quote(self._url[i])
        self._url = ''.join(self._url)
    
    def report(self):
        print('"' + self._url + '"')
    
    def run(self):
        self.quote()
        self.report()
if __name__ == '__main__':
    Test('https://www.multitran.com/m.exe?l1=2&l2=1&s=компьютер').run()
Почему процедура quote работает, а закомментированная процедура - не работает?
py.user.next
vanvanov
Почему процедура quote работает, а закомментированная процедура - не работает?
Потому что имя symbol сначала привязано к одному объекту, а потом в цикле оно просто перепривязывается к другому объекту. С первым объектом ничего не происходит, от него отвязывается единственное имя и он просто остаётся в списке, каким и был до привязывания имени к нему.

Вот пример
  
>>> n = 1
>>> n
1
>>> n = 2
>>> n
2
>>>
Имя n привязали к объекту число со значением 1. Затем имя n привязали к другому объекту число со значением 2. Как только имя n привязали к другому объекту, первый объект, потеряв своё имя, высвободился из памяти (уничтожился).

К одному и тому же объекту может быть привязано много имён
  
>>> a = b = c = 1
>>> a
1
>>> b
1
>>> c
1
>>>
Как только объект теряет все свои имена, он удаляется из памяти. Там не только имена влияют на это, есть ещё и безымянные ссылки. Если объект находится в списке, который имеет имя и висит в памяти, то объект не будет удалён, потому что список на него ссылается (имеет невидимую ссылку). Но как только список потеряет имя и он при этом нигде не будет содержаться сам (в списке или кортеже), все объекты в этом списке удалятся и сам список тоже.

Если бы ты читал книжки, то ты бы оттуда всё это узнал, потому что там это пишут. Не нужно догадываться самому, питон не простой язык, он очень развитый и там много всяких таких фишек. Просто не хочется тебе книжки сюда переписывать, там это написано лучше, полнее и время тратить не надо, чтобы это всё писать.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB