프로그래밍 /Python

[Python] 클래스 선언 시 object 상속을 하는 이유

yooj_lee 2022. 5. 18. 18:44
300x250

파이토치 learning rate scheduler 소스 코드를 뜯어보다가 베이스 클래스인 _LRScheduler가 object를 상속받는 것을 알 수 있었다. 클래스 __init__과정에서 super().__init__()도 수행하지 않는데, 즉 어떤 속성도 상속받지 않는데 대체 그럼 object를 상속받는 건 무슨 역할을 하는 것일까 하는 궁금증에 찾아본 내용을 정리한다.


old-style class vs. new-style class

[문제의 코드]

class _LRScheduler(object):

    def __init__(self, optimizer, last_epoch=-1, verbose=False):

        # Attach optimizer
        if not isinstance(optimizer, Optimizer):
            raise TypeError('{} is not an Optimizer'.format(
                type(optimizer).__name__))
        self.optimizer = optimizer

        # Initialize epoch and base learning rates
        if last_epoch == -1:
            for group in optimizer.param_groups:
                group.setdefault('initial_lr', group['lr'])
        else:
            for i, group in enumerate(optimizer.param_groups):
                if 'initial_lr' not in group:
                    raise KeyError("param 'initial_lr' is not specified "
                                   "in param_groups[{}] when resuming an optimizer".format(i))
        self.base_lrs = [group['initial_lr'] for group in optimizer.param_groups]
        self.last_epoch = last_epoch

→ 앞에서 밝힌 바와 같이 object를 상속받았음에도 불구하고 object에 어떠한 의존성도 보이지 않는다.

 

결론부터 말하자면, object를 상속받는 것은 python3 버전에서는 특별한 기능을 하지 않는다. 그냥 클래스를 선언하는 하나의 방식 중 하나일 뿐이다. 따라서, 생략이 가능하다.

object를 상속받는 것을 specify하는 부분이 생기게 된 유래는, python2 (2.2 이전)에서 python built-in 타입의 상속이 불가능한 문제때문이다. dict나 list와 같은 파이썬 내장 자료구조를 상속 받아서 새로운 클래스를 생성하는 게 불가능했다. (스크래치로 빌트인을 user-defined class로 구현해도 C 코드에서 호환이 되지 않음)

따라서, python 2.2 이상 버전에서는 object 타입을 도입해서 이를 상속받아 기존의 빌트인 타입 상속 문제를 해결하고자 했다. 그러나, 기존 코드를 다 수정해야하는 번거로움을 막기 위해 old-style class와 new-style class로 분리하여 기존의 빌트인 타입 상속이 불가한 클래스와 가능한 클래스를 병존하도록 하였다.

# python 2 (2.2 이상)

## old-style class
class Old:
	pass
    
## new-style class
class New(object):
	pass
    
issubclass(Old, object) # False
issubclass(New, object) # True

 

그러나, python3에서는 old-style class를 제거하고 new-style class로 통합하였다. new-style class로 통합이 되면서 클래스 선언 시 더 이상 object를 명시적으로 상속받을 필요가 없어졌다.

# Python3

class CustomClass1:
	pass
    
class CustomClass2(object):
	pass
    
class CustomClass3():
	pass


issubclass(CustomClass1, object) # True
issubclass(CustomClass2, object) # True
issubclass(CustomClass3, object) # True

 

 

위의 3가지 방식 중 어떤 식으로 클래스를 선언하든 모두 object를 상속받는 new-style class로 생성된다.



그럼에도 불구하고, object를 명시해주는 것은 기존 python2 코드와의 호환성을 고려한 것일 가능성이 크다 (아니면 그냥 작성자 마음). 따라서, 저런 코드를 보면 그냥 클래스를 선언했구나~ 하고 넘어가면 되겠다.


References

https://riptutorial.com/python/example/1402/new-style-vs--old-style-classes https://hashcode.co.kr/questions/487/object%EB%8A%94-%EC%99%9C-%EC%83%81%EC%86%8D%EB%B0%9B%EB%8A%94-%EA%B1%B4%EA%B0%80%EC%9A%94
https://jh-bk.tistory.com/24

300x250