게시판

검색 결과: 12

 

class AdvancedList(list):
    testattr = []
    def replace_listcomp(self, old, new):
        print('self:', self)
        a = [new if self[i] == old else self[i] for i in range(len(self))]
        print('repaced list', a)
        self = a # self를 바꿔보자
        AdvancedList.testattr = a
x = AdvancedList([1, 2, 3, 1, 2, 3, 1, 2, 3])
x.replace_listcomp(1, 200)
print(x)
x.testattr
이렇게 해보면,
>>> x.replace_listcomp(1, 200)
self: [1, 2, 3, 1, 2, 3, 1, 2, 3]
repaced list [200, 2, 3, 200, 2, 3, 200, 2, 3]
>>> print(x)
[1, 2, 3, 1, 2, 3, 1, 2, 3]
>>> x.testattr
[200, 2, 3, 200, 2, 3, 200, 2, 3]
>>> 

이런식으로 list comprehension을 쓰면, 아래처럼 class 내에서 list는 잘 replace가 되었는데 정작 self에 할당을 해도 변경이 되지 않습니다. 혹시나 해서 class attribute를 만들어보면 잘 되구요... 제가 어느 부분을 오해하고 있는 것일까요?

 

class AdvancedList(list):
    def hello(self):
        print(self)

x = AdvancedList([1, 2, 3, 1, 2, 3, 1, 2, 3])
x.hello() # [1, 2, 3, 1, 2, 3, 1, 2, 3]
          # 이렇게 나오는 이유는 기반 클래스 list에 __repr__ 메서드가 구현되어 있기 때문임



class AdvancedList2(list):
    def hello(self):
        print(self)

    def __repr__(self):
        # 참고: 0x 포함 10자리
        return "<{}.{} at {:#010x}>".format(__name__, self.__class__.__name__, id(self))

x = AdvancedList2([1, 2, 3, 1, 2, 3, 1, 2, 3])
x.hello() # <__main__.AdvancedList2 at 0x043030f0>
          # 현재 클래스에 __repr__을 구현하면 print 호출 시 현재 클래스의 __repr__이 호출됨
          # 클래스명, 주소 스타일로 표시하려면 위처럼 __repr__을 구현하면 됨



class Hello: # class Hello(object):와 동일
    def hello(self):
        print(self)

x = Hello()
x.hello() # <__main__.Hello object at 0x03741890>
          # 현재 메서드에 __repr__ 메서드가 구현되어 있지 않기 때문에 object의 주소가 그대로 표시됨
          # 기본적으로 파이썬은 object를 상속받으므로 object의 __repr__이 호출되는 것임

         

class AdvancedList3(list):
    def __init__(self, arg):
        super().__init__(arg) # super()를 이용하여 기반 클래스의 __init__을 호출하고
                              # 인스턴스를 생성할 때 받은 값을 넣어줌
   
    def replace(self, old, new):
        while old in self:
            self[self.index(old)] = new

x = AdvancedList3([1, 2, 3, 1, 2, 3, 1, 2, 3])
x.replace(1, 100)
print(x) # [100, 2, 3, 100, 2, 3, 100, 2, 3]

, 박 찬연님이 작성
 
해설: "먼저 클래스의 메서드 안에서 현재 객체를 조작하려면 self를 이용해야 합니다. 여기서는 AdvancedList가 list를 상속받았으므로 self로 리스트의 모든 메서드를 사용할 수 있습니다." 라고 되어 있는데 이해가 잘 가지 않습니다. 

클래스 안에서 print(self) # [1, 2, 3, 1, 2, 3, 1, 2, 3] 이렇게 표현되는데  보통

<__main__.ADvancedList object at 0x03E97700> 처럼 표현되지 않고 실제 리스트의 값이 표현되어 집니다. 

그리고 인스턴스 생성시 

x = AdvancedList() 이렇게 표현하는것 같은데(__init__() 예외)

리스트를 상속 받았는데 인스턴스 생성시 상속자를 직접 넣어 주어도 되는 문법인지 궁금합니다. 감사합니다.  




class AdvancedList(list):
    def replace(self, old, new):
        while old in self:
            self[self.index(old)] = new
x = AdvancedList([1, 2, 3, 1, 2, 3, 1, 2, 3])
x.replace(1, 100)
print(x)


 

답변 감사합니다. 알려주신 사이트 가서 순차 흐름보니 잘 이해되네요.

class AdvancedList(list):

    def __init__(self, num_list):

        self = num_list

        print(self)   ---> 1번

        

    def replace(self, origin, newer):

        print(self)   ---> 2번

        for num in self:            

            if num == origin:

                self[self.index(origin)] = newer

위의 코드에서 __init__ 내부에서 self = num_list 라인이 수행되며 self의 id가 바뀌는 것이 원인이었습니다. 부모 클래스에 의해 인스턴스 x에 인자가 전달되어 리스트가 만들어지는 것인데 __init__ 이 수행되며 인스턴스 x의 id를 바꿔버려서 __init__에서와 replace 의 self가 서로 다른 객체가 되어 이후의 x.replace 메서드를 수행했을때 원하는 결과가 얻어지지 않았습니다.

시험삼아 self 에 바로 할당하지 않고 인스턴스 변수 추가하여 self.num_list = num_list 이런 식으로 작성하고 이후 코드도 변경하니 self의 id 값 안 바뀌고 잘 되네요.

, 김 기업님이 작성
 

리스트를 상속한 클래스라는 점에서 인스턴스 생성시 전달된 인자를 별도로 처리해주지 않아도 해당 인스턴스에 리스트가 생성된다는 것은 이해 했습니다.

그런데 일반적으로 클래스 생성시 인자가 전달되면 init에서 해당 인자로 인스턴스 변수를 초기화 해주므로 그런 관점에서 코드를 아래처럼 해봤는데요.

class AdvancedList(list):

    def __init__(self, num_list):

        self = num_list

        print(self)   ---> 1번

        

    def replace(self, origin, newer):

        print(self)   ---> 2번

        for num in self:            

            if num == origin:

                self[self.index(origin)] = newer

이렇게 하고 수행하면 1번 위치에서는 [1, 2, 3, 1, 2, 3, 1, 2, 3] 이 잘 출력됩니다. 그런데 2번 위치에서는 [] 이렇게만 출력됩니다.

왜 이렇게 되는 것인지 설명 부탁 드립니다.

-------------------------------------------------------------

추가로 테스트를 해봤는데 1번과 2번 위치에서 self의 id가 다르게 나오네요. 같아야 하지 않나요?

 

C++을 모릅니다. 아는 분에게 물어보시기 바랍니다.

프로그래밍 언어의 비교는 <프로그래밍 언어론>을 공부해야 한다고 알고 있습니다.


, 박 희재님이 작성
 

c++에서는 아래와 같이 호출을 하려면 인자가 리스트한개를 받는 그런 생성자를 만들어야한다고 알고있습니다.

파이썬에서는 아래와 같은 리스트 한개를 받는 생성자를 따로 만들필요가 없나요?? 생성자를 따로 만들지 않아도 오류가 뜨지 않아 질문드립니다.

아니면 list 클래스의 생성자가 호출이 되어서 오류가 없는것인가요??

x = AdvancedList([1, 2, 3, 1, 2, 3, 1, 2, 3])

 
>>> x = list([1, 2, 3, 1, 2, 3, 1, 2, 3])
>>> x
[1, 2, 3, 1, 2, 3, 1, 2, 3]
>>> y = [1, 2, 3, 1, 2, 3, 1, 2, 3]
>>> y
[1, 2, 3, 1, 2, 3, 1, 2, 3]
>>>

파이썬의 기본 리스트도 list로 리스트를 만들 수 있습니다.

list를 상속해서 만든 AdvancedList로 리스트를 만든 겁니다.

UNIT 36을 복습하거나 어려우면 책을 학습하고 나중에 다시 복습하는 게 좋을 것 같습니다.