Python ссылок и циклов - PullRequest
1 голос
/ 09 июля 2020

Я привык к perl, где ссылки и переменные явно разделены. Использование python очень запутывает жизнь. Я хочу работать в al oop, создавать объекты и добавлять их в список, но результаты разочаровывают. Я читал, что функции определяют область видимости переменных, но даже инкапсуляция моего кода l oop внутри функций не сокращает его.

Пример следующий:

mylist = []

class thing:
    def __init__(self, stuff=[]):
        self.stuff = stuff

for i in range(10):
    obj = thing()
    obj.stuff.append(1)
    mylist.append(obj)

len(mylist[0].stuff)

I можно было бы ожидать, что длина списка "материала" каждого объекта будет равна 1, но получается 10. Я знаю, что могу использовать глубокую копию, чтобы явно отделить вновь созданные объекты от того, что было раньше, но есть ли более красивый способ ?

Ответы [ 3 ]

0 голосов
/ 09 июля 2020

Попробую это сделать. Когда объект изменяемого списка определен как параметр, он передается классам.


class thing:
    def __init__(self, stuff=[]):
        self.stuff = stuff


for i in range(10):
    obj = thing()
    print(obj)
    obj.stuff.append(1)
    print(obj.stuff)
    mylist.append(obj)
    print(mylist)

<<strong> main .thing объект в 0x10ff4b5f8> [1] [<<strong> main объект .thing в 0x10ff4b5f8>]

<<strong> main объект .thing в 0x10ff4b978> [1, 1] [<<strong> main объект .thing в 0x10ff4b5f8>, <<strong> main объект .thing в 0x10ff4b978>]

<<strong> main объект .thing в 0x10ff4b4e0> [1, 1, 1] [<<strong> main объект .thing в 0x10ff4b5f8>, <<strong> main .thing объект в 0x10ff4b978>, <<strong> main объект .thing в 0x10ff4b4e0>]

<<strong> main объект .thing в 0x10ff4b4a8> [1, 1, 1, 1] [<<strong> main объект .thing в 0x10ff4b5f8>, <<strong> main .thing объект в 0x10ff4b978>, <<strong> main .thing объект в 0x10ff4b4e0>, <<strong> main .thing объект в 0x10ff4b4a8>]

<<strong> main объект .thing в 0x10ff4b5c0> [1, 1, 1, 1, 1] [<<strong> main объект .thing в 0x10ff4b 5f8>, <<strong> main .thing объект в 0x10ff4b978>, <<strong> main .thing объект в 0x10ff4b4e0>, <<strong> main .thing объект в 0x10ff4b4a8>, <<strong> main объект .thing в 0x10ff4b5c0>]

<<strong> main объект .thing в 0x10ff4b588> [1, 1, 1, 1, 1, 1] [<<strong> main .thing объект в 0x10ff4b5f8>, <<strong> main .thing объект в 0x10ff4b978>, <<strong> main .thing объект в 0x10ff4b4e0>, <<strong> main .thing объект в 0x10ff4b4a8>, <<strong> main .thing объект в 0x10ff4b5c0>, <<strong> main .thing объект в 0x10ff4b588>]

<<strong> main .thing объект в 0x10ff4b6d8> [1, 1, 1, 1, 1, 1, 1] [<<strong> main .thing объект в 0x10ff4b5f8>, <<strong> main .thing объект в 0x10ff4b978>, <<strong> main .thing объект в 0x10ff4b4e0>, <<strong> main .thing объект в 0x10ff4b4a8>, <<strong> main .thing объект в 0x10ff4b5c0>, <<strong> основной объект .thing в 0x10ff4b588>, <<strong> main объект .thing в 0x10ff4b6d8>]

<* 108 8 * main </strong> объект .thing в 0x10ff4b710> [1, 1, 1, 1, 1, 1, 1, 1] [<<strong> main объект .thing в 0x10ff4b5f8>, <<strong> main объект .thing в 0x10ff4b978>, <<strong> main объект .thing в 0x10ff4b4e0>, <<strong> main .thing объект в 0x10ff4b4a8>, <<strong> main .thing объект в 0x10ff4b5c0>, <<strong> main .thing объект в 0x10ff4b588>, <<strong> main объект .thing в 0x10ff4b6d8>, <<strong> main .thing объект в 0x10ff4b710>]

<<strong> main объект .thing по адресу 0x10ff4b668> [1, 1, 1, 1, 1, 1, 1, 1, 1] [<<strong> main .thing объект в 0x10ff4b5f8>, <<strong> main объект .thing в 0x10ff4b978>, <<strong> main объект .thing в 0x10ff4b4e0>, <<strong> main .thing объект в 0x10ff4b4a8>, <<strong> main .thing объект в 0x10ff4b5c0>, <<strong> main .thing объект в 0x10ff4b588>, <<strong> main .thing объект в 0x10ff4b6d8>, <<strong> main объект .thing в 0x10ff4b710>, <<strong> main объект .thing в 0x10ff4b668>]

<<strong> main объект .thing в 0x10ff4b748> [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] [<<strong> main объект .thing в 0x10ff4b5f8>, <<strong> main .thing объект в 0x10ff4b978>, <<strong> main .thing объект в 0x10ff4b4e0>, <<strong> main .thing объект в 0x10ff4b4a8>, <<strong> main .thing объект at 0x10ff4b5c0>, <<strong> main объект .thing в 0x10ff4b588>, <<strong> main объект .thing в 0x10ff4b6d8>, <<strong> main .thing объект в 0x10ff4b710>, < main .thing объект в 0x10ff4b668>, <<strong> main .thing объект в 0x10ff4b748>]

При создании списка внутри функционального блока он каждый раз создает новый .

Вот результат при использовании класса ниже.

class Thing:
    __ init__(self, stuff):
        if stuff:
            self.stuff = stuff
        else:
            self.stuff = []

for i in range(10):
     obj = thing()
    print(obj)
    obj.stuff.append(1)
    print(obj.stuff)
    mylist.append(obj)
    print(mylist)

Выход

<<strong> main .thing объект at 0x10ff4b518> [1] [<<strong> main .thing объект в 0x10ff4b518>]

<<strong> main .thing объект в 0x10ff4b4e0> [1] [<<strong> main .thing объект по адресу 0x10ff4b518>, <<strong> main . объект thing в 0x10ff4b4e0>]

<<strong> main .thing объект в 0x10ff4b6d8> [1] [<<strong> main .thing объект в 0x10ff4b518>, <<strong> main объект .thing в 0x10ff4b4e0>, <<strong> main объект .thing в 0x10ff4b6d8>]

<<strong> main объект .thing в 0x10ff4b550> [1] [< main объект .thing в 0x10ff4b518>, <<strong> main объект .thing в 0x10ff4b4e0>, <<strong> main .thing объект в 0x10ff4b6d8>, <<strong> main объект .thing в 0x10ff4b550>]

<<strong> main .thing объект в 0x10ff4b7b8> [1] [<<strong> main .thing объект в 0x10ff4b518>, <<strong> основной объект .thing в 0x10ff4b4e0>, <<strong> main объект .thing в 0x10ff4b6d8>, <<strong> main объект .thing в 0x10ff4b550>, <<strong> main .thing объект в 0x10ff4b7b8>]

<<strong> main .thing объект в 0x10ff4b7f0> [1] [<<strong> main .thing объект в 0x10ff4b518>, <<strong> main объект .thing в 0x10ff4b4e0>, <<strong> main объект .thing в 0x10ff4b 6d8>, <<strong> main объект .thing в 0x10ff4b550>, <<strong> main .thing объект в 0x10ff4b7b8>, <<strong> main объект .thing в 0x10ff4b7f0>]

<<strong> main объект .thing в 0x10ff4b668> [1] [<<strong> main .thing объект в 0x10ff4b518>, <<strong> main объект .thing в 0x10ff4b4e0 >, <<strong> main .thing объект в 0x10ff4b6d8>, <<strong> main .thing объект в 0x10ff4b550>, <<strong> main .thing объект в 0x10ff4b7b8>, <<strong> main .thing объект в 0x10ff4b7f0>, <<strong> main .thing объект в 0x10ff4b668>]

<<strong> main .thing объект в 0x10ff4b6a0> [1] [<<strong> main .thing объект в 0x10ff4b518>, <<strong> main .thing объект в 0x10ff4b4e0>, <<strong> main .thing объект в 0x10ff4b6d8>, <<strong> main .thing объект в 0x10ff4b550>, <<strong> main .thing объект в 0x10ff4b7b8>, <<strong> main .thing объект в 0x10ff4b7f0>, <<strong> main . объект thing в 0x10ff4b668>, <<strong> main .thing объект в 0x10ff4b6a0>] * 12 65 *

<<strong> main объект .thing в 0x10ff4b748> [1] [<<strong> main .thing объект в 0x10ff4b518>, <<strong> main .thing объект в 0x10ff4b4e0>, <<strong> main объект .thing в 0x10ff4b6d8>, <<strong> main объект .thing в 0x10ff4b550>, <<strong> main .thing объект в 0x10ff4b7b8>, <<strong> main объект .thing в 0x10ff4b7f0>, <<strong> main .thing объект в 0x10ff4b668>, <<strong> main .thing объект в 0x10ff4b6a0>, <<strong> main .thing объект в 0x10ff4b748>]

<<strong> main .thing объект в 0x10ff4b828> [1] [<<strong> main .thing объект в 0x10ff4b518>, <<strong> main .thing объект в 0x10ff4b4e0>, <<strong> main .thing объект в 0x10ff4b6d8>, <<strong> main .thing объект в 0x10ff4b550>, <<strong> main .thing объект в 0x10ff4b7b8>, <<strong> main .thing объект в 0x10ff4b7f0>, <<strong> main .thing объект в 0x10ff4b668>, <<strong> main объект .thing в 0x10ff4b6a0 >, <<strong> main объект .thing по адресу 0x10ff4b748>, <<strong> mai n объект .thing по адресу 0x10ff4b828>]

0 голосов
/ 09 июля 2020

Это причуда Python. Значение по умолчанию для аргумента создается только один раз, во время определения функции. Итак, вы можете получить это странное поведение:

def f(x=[]):
    x.append('x')
    return x

f()
# ['x']
f()
# ['x', 'x']
f()
# ['x', 'x', 'x']

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

Чтобы обойти это, вам нужно использовать дозорный, а затем явно проверить, было ли оно переопределено. Это общий шаблон:

def f(x=None):
    if x is None:
        x = []
    x.append('x')
    return x

f()
# ['x']
f()
# ['x']
f(['a', 'b'])
# ['a', 'b', 'x']
0 голосов
/ 09 июля 2020

Проблема здесь в том, что у вас один и тот же объект list используется по умолчанию для всех объектов, созданных с помощью thing()

class thing:
    def __init__(self, stuff=[]):
        self.stuff = stuff

for i in range(3):
    obj = thing()
    print(id(obj.stuff))
# Output
140710582002368
140710582002368
140710582002368

Одним из возможных решений этого может быть не использовать значение по умолчанию, которое будет выглядеть так:

class thing:
  def __init__(self, stuff):
    self.stuff = stuff

for i in range(10):
  obj = thing(stuff = list())
  print(id(obj.stuff))
# Output
139911079590016
139911079590144
139911079590208

Это назначает новый list на каждой итерации for l oop члену stuff.

...