inflearn logo
강의

Course

Instructor

Type Python! Correct class usage and object-oriented programming

[Object-oriented programming + typing] Stack data structure implementation explanation

문수미님과 같은 내용입니다

309

weston07133201

1 asked

1

코드를 살펴봐도 원인을 모르겠어서 질문 드립니다

 

mypy와 pyright 사용시에 각각 다르게 에러가 나고 내용은 아래와 같습니다

 

mypy

error: Item "None" of "Optional[Node[Any]]" has no attribute "item"

 

pyright

error: "pointer" is not a known member of "None"

.

.

error: "item" is not a known member of "None"

 

아마 Optional[Node]에서 None으로 처리될 때 pointer와 item속성이 없어서 이렇게 되는 것 같은데, 처리 방법을 찾지 못해서 질문 남깁니다.

 

아래는 전체 코드와 에러발생 위치입니다.

 

from typing import Optional, Generic, TypeVar

T = TypeVar("T")

class Node(Generic[T]):
    def __init__(self, item: T, pointer: Optional['Node'] = None):
        self.item = item
        self.pointer = pointer


class LinkedList(Generic[T]):
    def __init__(self):
        self.head: Optional[Node[T]] = None

    @property
    def length(self) -> int:
        if self.head is None:
            return 0
        cur_node = self.head
        count: int = 1
        while cur_node.pointer is not None:
            cur_node = cur_node.pointer
            count += 1
        return count


class Stack(Generic[T], LinkedList[T]):
    def push(self, item: T) -> None:
        new_node: Node[T] = Node[T](item)
        if self.head is None:
            self.head = new_node
            return
        cur_node = self.head
        while cur_node.pointer is not None:
            cur_node = cur_node.pointer
        cur_node.pointer = new_node

    
    def __str__(self) -> str:
        result: str = ''
        if self.head is None:
            return result
        cur_node: Node[T] = self.head
        result += f"{cur_node.item}"
        while cur_node.pointer is not None:
            cur_node = cur_node.pointer
            result += f", {cur_node.item}"
        return result
    
        
    def pop(self) -> T:
        if self.head is None:
            raise ValueError("Stack is Empty")
        cur_node = self.head
        if cur_node.pointer is None:
            self.head = None
            return cur_node.item
        while cur_node.pointer.pointer is not None:                  # <- pyright error "pointer" is not... x2
            cur_node = cur_node.pointer                  # <- pyright error "pointer" is not...
        result = cur_node.pointer                  # <- pyright error "pointer" is not...
        cur_node.pointer = None                  # <- pyright error "pointer" is not...
        return result.item                  # <- mypy error / pyright error "item" is not ...
    

if __name__ == '__main__':
    stack = Stack[int]()
    stack.push(0)
    stack.push(1)
    stack.push(2)
    stack.push(3)
    stack.push(4)
    stack.push(5)
    stack.push(6)
    stack.push(7)
    stack.push(8)
    stack.push(9)
    
    print(stack.length)
    print(stack)
    
    print(stack.pop())
    print(stack.pop())
    print(stack.pop())
    print(stack.pop())
    print(stack.pop())
    print(stack.pop())
    print(stack.pop())
    print(stack.pop())
    print(stack.pop())
    print(stack.pop())

oop python

Answer 1

2

clouddev8125

타입체커가 코드를 분석해가면서 타입들이 바르게 연결 되었는지 검사하는데, 

1. pyright 의 경우,

while cur_node.pointer.pointer is not None:
    cur_node = cur_node.pointer  

에서 cur_node를 cur_node. pointer 로 찍을때  point 가 None이 아닌지 명시되지 않아서 에러가 나는 걸로 보이구요.

2. mypy의 경우 result = cur_node.pointer 로 할당 하면, pointer가 None인지 아닌지 mypy에서 알지 못해서 에러가 나는 걸로 보입니다.

3. 아래와 같이 작성하시면 코드가 좀 더 장황해지기는 하나 mypy, pyright 둘다 통과 합니다. mypy 랑 pyright랑 검사하는 방식이나 유추하는 문맥이 좀 다르긴 하네요.

    def pop(self) -> Optional[T]:
        if self.head is None:
            raise ValueError("Stack is empty")
        cur_node: Node[T] = self.head
        if cur_node.pointer is None:
            self.head = None
            return cur_node.item
        while cur_node.pointer is not None: # cur_node.pointer가 None 이 아님을 명시
            if cur_node.pointer.pointer is not None: 
                cur_node = cur_node.pointer
                continue
            result = cur_node.pointer
            cur_node.pointer = None
            return result.item if result is not None else None # result가 None이 아님을 명시

보너스 챕터 마지막 강의 녹화 품질이 문제가 있습니다ㅠㅠ

0

110

1

린터 설치문의

0

362

2

데이터분석에서의 가상환경

0

395

0

print(Robot.how_many()) 하면 None이 뜨는 이유

2

325

2

타입파이썬 문의

1

333

1

프레임워크 질문

1

234

1

클래스 상속 순서? 질문

1

378

2

pip과pip3의 차이

1

2727

1

메서드 리턴 값이 print일 때 print를 찍으면 None

1

247

1

변수의 참조에 대해서 질문입니다.

1

242

1

질문입니다..

1

201

1

pyright 를 이용한 클래스 재정의 코드 실행 문제점 질문 드립니다.

1

445

1

which pyhon이 왜 안될까요..?

1

435

1

pyright 에러나서 질문드립니다.

1

392

1

클래스 변수 관련 질문입니다.

1

296

1

데코레이터 관련 질문

1

223

1

venv 로 만든 가상환경은 파이썬 버젼을 변경하기가 어려운 것 같습니다.

1

1108

1

Final로 타이핑한 변수에 list를 넣는다면

1

225

1

생성자에서 자기 자신 타이핑 하는 경우

1

217

1

f"{객체}" 출력값에서의 숫자값과 id(객체)에서의 숫자값의 차이가 무엇인가요??

1

331

1

타입힌트 실무에서 자주쓰이나요?

2

478

1

스태틱메소드와 클래스메소드

3

261

1

인스턴스와 데이터

2

232

1

call method 관련 질문입니다!

1

188

1