5-1. 클래스

클래스는 왜 필요한가?

  • 프로그래머들이 가장 많이 사용하는 프로그래밍 언어 중 하나인 C 언어에는 클래스가 없음
    • 굳이 클래스가 없어도 프로그램을 충분히 만들 수 있음
  • 클래스는 지금까지 공부한 함수나 자료형처럼 프로그램 작성을 위해 꼭 필요한 요소는 아님
  • 프로그램을 작성할 때 클래스를 적재적소에 사용하면 얻을 수 있는 이익이 많음

계산기의 “더하기” 기능을 구현한 파이썬 코드

result = 0

def add(num):
    global result
    result += num
    return result

print(add(3))
print(add(4))
  • 이전에 계산한 결괏값을 유지하기 위해서 result 전역 변수(global)를 사용
3
7
  • 만일 한 프로그램에서 2대의 계산기가 필요한 상황이 발생하면 각 계산기는 각각의 결괏값을 유지해야 하기 때문에 위와 같이 add 함수 하나만으로는 결괏값을 따로 유지할 수 없음
  • 이런 상황을 해결하려면 다음과 같이 함수를 각각 따로 만들어야 함

클래스와 객체

  • 과자 틀 → 클래스 (class)
  • 과자 틀에 의해서 만들어진 과자 → 객체 (object)
  • 클래스(class)란 똑같은 무엇인가를 계속해서 만들어 낼 수 있는 설계 도면(과자 틀)
  • 객체(object)란 클래스로 만든 피조물(과자 틀을 사용해 만든 과자)
  • 동일한 클래스로 만든 객체들은 서로 전혀 영향을 주지 않음

파이썬 클래스의 가장 간단한 예

>>> class Cookie:
>>>    pass
  • 객체는 클래스로 만들며 1개의 클래스는 무수히 많은 객체를 만들어 낼 수 있음
>>> a = Cookie()
>>> b = Cookie()
  • Cookie()의 결괏값을 돌려받은 a와 b가 바로 객체
  • 마치 함수를 사용해서 그 결괏값을 돌려받는 모습과 비슷

[객체와 인스턴스의 차이]

  • a = Cookie() 이렇게 만든 a는 객체
  • 객체는 Cookie의 인스턴스
    • 즉 인스턴스라는 말은 특정 객체(a)가 어떤 클래스(Cookie)의 객체인지를 관계 위주로 설명할 때 사용

사칙연산 클래스 만들기

클래스를 어떻게 만들지 먼저 구상하기

  • 클래스로 만든 객체를 중심으로 어떤 식으로 동작하게 할것인지 미리 구상을 한 후에 생각한 것들을 하나씩 해결하면서 완성해 나가는 것이 좋음

사칙연산을 가능하게 하는 FourCal 클래스

  • a = FourCal()를 입력해서 a라는 객체를 만듬
>>> a = FourCal()
  • a.setdata(4, 2)처럼 입력해서 숫자 4와 2를 a에 지정
>>> a.setdata(4, 2)
  • a.add()를 수행하면 두 수를 합한 결과(4 + 2)를 반환
>>> print(a.add())
6
  • a.mul()을 수행하면 두 수를 곱한 결과(4 * 2)를 반환
>>> print(a.mul())
8
  • a.sub()를 수행하면 두 수를 뺀 결과(4 - 2)를 반환
>>> print(a.sub())
2
  • a.div()를 수행하면 두 수를 나눈 결과(4 / 2)를 반환
>>> print(a.div())
2
  • 이렇게 동작하는 FourCal 클래스를 만드는 것이 목표

클래스 구조 만들기

  • 동작하는 클래스를 만듬
>>> class FourCal:
...     pass
... 
>>>
  • 대화형 인터프리터에서 pass란 문장만을 포함한 FourCal 클래스를 만듬
  • 현재 상태에서 FourCal 클래스는 아무 변수나 함수도 포함하지 않지만, 우리가 원하는 객체 a를 만들 수 있는 기능은 가지고 있음

pass는 아무것도 수행하지 않는 문법으로 임시로 코드를 작성할 때 주로 사용함

>>> a = FourCal()
>>> type(a)
<class '__main__.FourCal'>

type 함수는 파이썬이 자체로 가지고 있는 내장 함수로 객체 타입을 출력함

객체에 숫자 지정할 수 있게 만들기

>>> a.setdata(4, 2)
>>> class FourCal:
...     def setdata(self, first, second):
...         self.first = first
...         self.second = second
...
>>>
  • FourCal 클래스에서 pass 문장을 삭제하고 그 대신 setdata 함수를 만듬
  • 클래스 안에 구현된 함수는 메서드(Method)라고 부름
    • 클래스 내부의 함수는 항상 메서드라고 표현함

일반적인 함수

def 함수명(매개변수):
    수행할 문장
    ...
  • 메서드도 클래스에 포함되어 있다는 점만 제외하면 일반 함수와 같음

setdata 메서드

def setdata(self, first, second):   # ① 메서드의 매개변수
    self.first = first              # ② 메서드의 수행문
    self.second = second            # ② 메서드의 수행문

① setdata 메서드의 매개변수

  • setdata 메서드는 매개변수로 self, first, second 3개 입력값을 받음
  • 일반 함수와는 달리 메서드의 첫 번째 매개변수 self는 특별한 의미를 가짐

a 객체를 만들고 a 객체를 통해 setdata 메서드를 호출

>>> a = FourCal()
>>> a.setdata(4, 2)

객체를 통해 클래스의 메서드를 호출하려면 a.setdata(4, 2)와 같이 도트(.) 연산자를 사용

  • setdata 메서드에는 self, first, second 총 3개의 매개변수가 필요한데 실제로는 a.setdata(4, 2)처럼 2개 값만 전달함
  • 그 이유는 a.setdata(4, 2)처럼 호출하면 setdata 메서드의 첫 번째 매개변수 self에는 setdata메서드를 호출한 객체 a가 자동으로 전달됨

  • 파이썬 메서드의 첫 번째 매개변수 이름은 관례적으로 self를 사용
  • 객체를 호출할 때 호출한 객체 자신이 전달되기 때문에 self를 사용함
    • self말고 다른 이름을 사용해도 상관없음

메서드의 첫 번째 매개변수 self를 명시적으로 구현하는 것은 파이썬만의 독특한 특징 자바 같은 언어는 첫 번째 매개변수 self가 필요없음

[메서드의 또 다른 호출 방법]

  • 잘 사용하지는 않지만 다음과 같이 클래스를 통해 메서드를 호출하는 것도 가능
>>> a = FourCal()
>>> FourCal.setdata(a, 4, 2)
  • 클래스 이름.메서드 형태로 호출할 때는 객체 a를 첫 번째 매개변수 self에 꼭 전달해줘야 함
  • 객체.메서드 형태로 호출할 때는 self를 반드시 생략해서 호출해야함
>>> a = FourCal()
>>> a.setdata(4, 2)

② setdata 메서드의 수행문

def setdata(self, first, second):   # ① 메서드의 매개변수
    self.first = first              # ② 메서드의 수행문
    self.second = second            # ② 메서드의 수행문
  • a.setdata(4, 2)처럼 호출하면 setdata 메서드의 매개변수 first, second에는 각각 값 4와 2가 전달되어 setdata 메서드의 수행문은 다음과 같이 해석
self.first = 4
self.second = 2
  • self는 전달된 객체 a이므로 다시 다음과 같이 해석
a.first = 4
a.second = 2
  • a.first = 4 문장이 수행되면 a 객체에 객체변수 first가 생성되고 값 4가 저장됨
  • 마찬가지로 a.second = 2 문장이 수행되면 a 객체에 객체변수 second가 생성되고 값 2가 저장

객체에 생성되는 객체만의 변수를 객체변수라고 함

>>> a = FourCal()
>>> a.setdata(4, 2)
>>> print(a.first)
4
>>> print(a.second)
2
  • a 객체에 객체변수 first와 second가 생성되었음을 확인할 수 있음
>>> a = FourCal()
>>> b = FourCal()
  • a 객체의 객체변수 first를 다음과 같이 생성
>>> a.setdata(4, 2)
>>> print(a.first)
4
  • b 객체의 객체변수 first를 다음과 같이 생성
>>> b.setdata(3, 7)
>>> print(b.first)
3
  • b 객체의 객체변수 first에는 값 3이 저장
>>> print(a.first)
4
  • a 객체의 first 값은 b 객체의 first 값에 영향받지 않고 원래 값을 유지
  • 클래스로 만든 객체의 객체변수는 다른 객체의 객체변수에 상관없이 독립적인 값을 유지

  • id 함수를 사용하면 객체변수가 독립적인 값을 유지한다는 점을 좀 더 명확하게 증명할 수 있음

id 함수객체의 주소를 돌려주는 파이썬 내장 함수

>>> a = FourCal()
>>> b = FourCal()
>>> a.setdata(4, 2)
>>> b.setdata(3, 7)
>>> id(a.first)   # a의 first 주소값을 확인
1839194944
>>> id(b.first)   # b의 first 주소값을 확인
1839194928
  • a 객체의 first 주소 값과 b 객체의 first 주소 값이 서로 다르므로 각각 다른 곳에 그 값이 저장됨
  • 객체변수는 그 객체의 고유 값을 저장할 수 있는 공간
  • 객체 변수는 다른 객체들 영향받지 않고 독립적으로 그 값을 유지한다는 점을 꼭 기억!
    • 클래스에서는 이 부분을 이해하는 것이 가장 중요

더하기 기능 만들기

>>> a = FourCal()
>>> a.setdata(4, 2)
>>> print(a.add())
6
>>> class FourCal:
...     def setdata(self, first, second):
...         self.first = first
...         self.second = second
...     def add(self):
...         result = self.first + self.second
...         return result
...
>>>
  • 새롭게 추가된 것은 add 메서드
>>> a = FourCal()
>>> a.setdata(4, 2)
  • a객체의 first, second 객체변수에는 각각 값 4와 2가 저장됨

  • add 메서드를 호출

>>> print(a.add())
>>> 6
  • a.add()라고 호출하면 add 메서드가 호출되어 값 6이 출력됨
def add(self):
    result = self.first + self.second
    return result
  • add 메서드의 매개변수는 self이고 반환 값은 result
  • 반환 값인 result를 계산하는 부분
result = self.first + self.second
  • a.add()와 같이 a 객체에 의해 add 메서드가 수행되면 add 메서드의 self에는 객체 a가 자동으로 입력되므로 위 내용은 다음과 같이 해석
result = a.first + a.second
  • a.add() 메서드 호출 전에 a.setdata(4, 2) 가 먼저 호출되어 a.first = 4, a.second = 2 라고 이미 설정되었기 때문에 다시 다음과 같이 해석
result = 4 + 2
  • a.add()를 호출하면 6을 반환
>>> print(a.add())
6

곱하기, 빼기, 나누기 기능 만들기

>>> class FourCal:
...     def setdata(self, first, second):
...         self.first = first
...         self.second = second
...     def add(self):
...         result = self.first + self.second
...         return result
...     def mul(self):
...         result = self.first * self.second
...         return result
...     def sub(self):
...         result = self.first - self.second
...         return result
...     def div(self):
...         result = self.first / self.second
...         return result
...
>>>
>>> a = FourCal()
>>> b = FourCal()
>>> a.setdata(4, 2)
>>> b.setdata(3, 8)
>>> a.add()
6
>>> a.mul()
8
>>> a.sub()
2
>>> a.div()
2
>>> b.add()
11
>>> b.mul()
24
>>> b.sub()
-5
>>> b.div()
0.375

생성자 (Constructor)

>>> a = FourCal()
>>> a.add()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in add
AttributeError: 'FourCal' object has no attribute 'first'
  • FourCal 클래스의 인스턴스 a에 setdata 메서드를 수행하지 않고 add 메서드를 수행하면 “AttributeError: ‘FourCal’ object has no attribute ‘first’” 오류가 발생함
    • setdata 메서드를 수행해야 객체 a의 객체변수 first와 second가 생성되기 때문
  • 객체에 초깃값을 설정해야 할 필요가 있을 때는 setdata와 같은 메서드를 호출하여 초깃값을 설정하기보다는 생성자를 구현하는 것이 안전한 방법이다. 생성자(Constructor)란 객체가 생성될 때 자동으로 호출되는 메서드를 의미
  • 파이썬 메서드 이름으로 __init__를 사용하면 이 메서드는 생성자

__init__ 메서드의 init 앞뒤로 붙은 __는 언더스코어(_) 두 개를 붙여씀

>>> class FourCal:
...     def __init__(self, first, second):
...         self.first = first
...         self.second = second
...     def setdata(self, first, second):
...         self.first = first
...         self.second = second
...     def add(self):
...         result = self.first + self.second
...         return result
...     def mul(self):
...         result = self.first * self.second
...         return result
...     def sub(self):
...         result = self.first - self.second
...         return result
...     def div(self):
...         result = self.first / self.second
...         return result
...
>>>

생성자 __init__ 메서드

def __init__(self, first, second):
    self.first = first
    self.second = second
  • __init__ 메서드는 setdata 메서드와 이름만 다르고 모든 게 동일
  • 단 메서드 이름을 __init__으로 했기 때문에 생성자로 인식되어 객체가 생성되는 시점에 자동으로 호출되는 차이가 있음
>>> a = FourCal()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() missing 2 required positional arguments: 'first' and 'second'
  • a = FourCal()을 수행할 때 생성자 __init__이 호출되어 위와 같은 오류가 발생
    • 오류가 발생한 이유는 생성자의 매개변수 first와 second에 해당하는 값이 전달되지 않았기 때문
  • 위 오류를 해결하려면 다음처럼 first와 second에 해당되는 값을 전달하여 객체를 생성해야 함
>>> a = FourCal(4, 2)
>>> 
  • __init__ 메서드의 매개변수에는 각각 오른쪽과 같은 값이 대입
매개변수
self 생성되는 객체
first 4
second 2

__init__ 메서드도 다른 메서드와 마찬가지로 첫 번째 매개변수 self에 생성되는 객체가 자동으로 전달된다는 점을 기억하자.

  • __init__ 메서드가 호출되면 setdata 메서드를 호출했을 때와 마찬가지로 first와 second라는 객체변수가 생성
>>> a = FourCal(4, 2)
>>> print(a.first)
4
>>> print(a.second)
2
>>> a = FourCal(4, 2)
>>> a.add()
6
>>> a.div()
2.0

클래스의 상속

  • 상속(Inheritance)이란 “물려받다”, “재산을 상속받다”라고 할 때의 상속과 같은 의미
  • 클래스에도 이 개념을 적용할 수 있음. 어떤 클래스를 만들 때 다른 클래스의 기능을 물려받을 수 있게 만들 수 있음
  • 이번에는 상속 개념을 사용하여 우리가 만든 FourCal 클래스에 ab (a의 b제곱)을 구할 수 있는 기능을 추가
  • FourCal 클래스를 상속하는 MoreFourCal 클래스는 다음과 같이 간단하게 구현
>>> class MoreFourCal(FourCal):
...     pass
... 
>>>
  • 클래스를 상속하기 위해서는 다음처럼 클래스 이름 뒤 괄호 안에 상속할 클래스 이름을 넣어주면 됨

class 클래스 이름(상속할 클래스 이름)

  • MoreFourCal 클래스는 FourCal 클래스를 상속했으므로 FourCal 클래스의 모든 기능을 사용
>>> a = MoreFourCal(4, 2)
>>> a.add()
6
>>> a.mul()
8
>>> a.sub()
2
>>> a.div()
2
  • 상속받은 FourCal 클래스의 기능을 모두 사용할 수 있음을 확인할 수 있음

왜 상속을 해야 할까?

  • 보통 상속은 기존 클래스를 변경하지 않고 기능을 추가하거나 기존 기능을 변경하려고 할 때 사용
  • “클래스에 기능을 추가하고 싶으면 기존 클래스를 수정하면 되는데 왜 굳이 상속을 받아서 처리해야 하지?” 라는 의문이 들 수도 있음
    • 하지만 기존 클래스가 라이브러리 형태로 제공되거나 수정이 허용되지 않는 상황이라면 상속을 사용해야 함

a의 b제곱(ab)을 계산하는 MoreFourCal 클래스

>>> class MoreFourCal(FourCal):
...     def pow(self):
...         result = self.first ** self.second
...         return result
...
>>>
  • pass 문장은 삭제하고 위와 같이 두 수의 거듭제곱을 구할 수 있는 pow 메서드를 추가해 주었다. 그리고 다음과 같이 pow 메서드를 수행
>>> a = MoreFourCal(4, 2)
>>> a.pow()
16
  • MoreFourCal 클래스로 만든 a 객체에 값 4와 2를 설정한 후 pow 메서드를 호출하면 4의 2제곱 (42)인 16을 돌려주는 것을 확인할 수 있음

    상속은 MoreFourCal 클래스처럼 기존 클래스(FourCal)는 그대로 놔둔 채 클래스의 기능을 확장시킬 때 주로 사용

메서드 오버라이딩

>>> a = FourCal(4, 0)
>>> a.div()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
    result = self.first / self.second
ZeroDivisionError: division by zero
  • FourCal 클래스의 객체 a에 4와 0 값을 설정하고 div 메서드를 호출하면 4를 0으로 나누려고 하기 때문에 위와 같은 ZeroDivisionError 오류가 발생
  • 하지만 0으로 나눌 때 오류가 아닌 0을 돌려주도록 만들고 싶다면 어떻게 해야 할까?
  • 다음과 같이 FourCal 클래스를 상속하는 SafeFourCal 클래스
>>> class SafeFourCal(FourCal):
...     def div(self):
...         if self.second == 0:  # 나누는 값이 0인 경우 0을 리턴하도록 수정
...             return 0
...         else:
...             return self.first / self.second
...
>>>
  • SafeFourCal 클래스는 FourCal 클래스에 있는 div 메서드를 동일한 이름으로 다시 작성하였음
  • 이렇게 부모 클래스(상속한 클래스)에 있는 메서드를 동일한 이름으로 다시 만드는 것을 메서드 오버라이딩(Overriding, 덮어쓰기)이라고 함
  • 이렇게 메서드를 오버라이딩하면 부모클래스의 메서드 대신 오버라이딩한 메서드가 호출됨
  • SafeFourCal 클래스에 오버라이딩한 div 메서드는 나누는 값이 0인 경우에는 0을 돌려주도록 수정
  • 이제 다시 위에서 수행한 예제를 FourCal 클래스 대신 SafeFourCal 클래스를 사용하여 수행
>>> a = SafeFourCal(4, 0)
>>> a.div()
0
  • FourCal 클래스와는 달리 ZeroDivisionError가 발생하지 않고 의도한 대로 0을 돌려주는 것을 확인할 수 있음

클래스 변수

  • 객체변수는 다른 객체들에 영향받지 않고 독립적으로 그 값을 유지함
  • 객체변수와는 성격이 다른 클래스 변수
>>> class Family:
...     lastname = "김"
...
  • Family 클래스에 선언한 lastname이 바로 클래스 변수
  • 클래스 변수는 클래스 안에 함수를 선언하는 것과 마찬가지로 클래스 안에 변수를 선언하여 생성

Family 클래스를 다음과 같이 사용해 보자.

>>> print(Family.lastname)

  • 클래스 변수는 위 예와 같이 클래스이름.클래스 변수로 사용할 수 있음
  • 또는 다음과 같이 Family 클래스로 만든 객체를 통해서도 클래스 변수를 사용할 수 있음
>>> a = Family()
>>> b = Family()
>>> print(a.lastname)

>>> print(b.lastname)

  • 만약 Family 클래스의 lastname을 다음과 같이 “박”이라는 문자열로 바꾸면?
>>> Family.lastname = "박"
>>> print(a.lastname)

>>> print(b.lastname)

  • 클래스 변수 값을 변경했더니 클래스로 만든 객체의 lastname 값도 모두 변경된다는 것을 확인할 수 있음
  • 즉 클래스 변수는 클래스로 만든 모든 객체에 공유된다는 특징이 있음
  • id 함수를 사용하면 클래스 변수가 공유됨
>>> id(Family.lastname)
4480159136
>>> id(a.lastname)
4480159136
>>> id(b.lastname)
4480159136
  • id 값이 모두 같으므로 Family.lastname, a.lastname, b.lastname은 모두 같은 메모리
  • 클래스에서 클래스 변수보다는 객체변수가 훨씬 중요
    • 실무 프로그래밍을 할 때도 클래스 변수보다는 객체변수를 사용하는 비율이 훨씬 높음

5-2. 모듈

  • 모듈이란 함수나 변수 또는 클래스를 모아 놓은 파일
  • 모듈은 다른 파이썬 프로그램에서 불러와 사용할 수 있게끔 만든 파이썬 파일
  • 파이썬으로 프로그래밍을 할 때 굉장히 많은 모듈을 사용함
  • 다른 사람들이 이미 만들어 놓은 모듈을 사용할 수도 있고 직접 만들어서 사용할 수도 있음

모듈 생성

# mod1.py
def add(a, b):
    return a + b

def sub(a, b): 
    return a-b
  • add와 sub 함수만 있는 파일 mod1.py이 모듈

파이썬 확장자 .py로 만든 파이썬 파일은 모두 모듈

모듈 불러오기

  • 명령 프롬프트 창을 열고 mod1.py를 저장한 디렉터리로 이동한 다음 대화형 인터프리터를 실행
> python
>>>
>>> import mod1
>>> print(mod1.add(3, 4))
7
>>> print(mod1.sub(4, 2))
2
  • mod1.py를 불러오기 위해 import mod1을 입력
    • 실수로 import mod1.py로 입력하지 않도록 주의
  • import는 이미 만들어 놓은 파이썬 모듈을 사용할 수 있게 해주는 명령어
  • mod1.py 파일에 있는 add 함수를 사용하기 위해서는 위 예와 같이 mod1.add처럼 모듈 이름 뒤에 ”.”(도트 연산자)를 붙이고 함수 이름을 쓰면됨

import는 현재 디렉터리에 있는 파일이나 파이썬 라이브러리가 저장된 디렉터리에 있는 모듈만 불러올 수 있음 파이썬 라이브러리는 파이썬을 설치할 때 자동으로 설치되는 파이썬 모듈을 말함

import의 사용 방법

import 모듈이름
  • 모듈 이름은 mod1.py에서 .py 확장자를 제거한 mod1만 적어야 함
    • 확장자를 제거한 모듈이름만 적어야 함
  • mod1.add, mod1.sub처럼 쓰지 않고 add, sub처럼 모듈 이름 없이 함수 이름만 쓰고 싶은 경우 “from 모듈 이름 import 모듈 함수”를 사용하면됨
from 모듈이름 import 모듈함수
  • 위 형식을 사용하면 위와 같이 모듈 이름을 붙이지 않고 바로 해당 모듈의 함수를 쓸 수 있음
>>> from mod1 import add
>>> add(3, 4)
7
  • 위와 같이 하면 mod1.py 파일의 add 함수만 사용할 수 있음

add 함수와 sub 함수를 둘 다 사용하기 위한 2가지 방법

from mod1 import add, sub
  • 첫 번째 방법은 from 모듈 이름 import 모듈 함수1, 모듈 함수2처럼 사용
  • 콤마로 구분하여 필요한 함수를 불러올 수 있음
from mod1 import *
  • 두 번째 방법은 위와 같이 * 문자를 사용하는 방법
  • * 문자는 “모든 것”이라는 뜻인데 파이썬에서도 마찬가지 의미로 사용됨
  • from mod1 import *는 mod1.py의 모든 함수를 불러서 사용하겠다는 뜻

if __name__ == “__main__”: 의 의미

# mod1.py 
def add(a, b): 
    return a+b

def sub(a, b): 
    return a-b

print(add(1, 4))
print(sub(4, 2))
  • add(1, 4)sub(4, 2)의 결과를 출력하는 다음 문장을 추가함
  • mod1.py 파일은 다음과 같이 실행할 수 있음
> python mod1.py
5
2
  • mod1.py 파일의 add와 sub 함수를 사용하기 위해 mod1 모듈을 import할 때는 좀 이상한 문제가 생김
> python
Type "help", "copyright", "credits" or "license" for more information.
>>> import mod1
5
2
  • 단지 mod1.py 파일의 add와 sub 함수만 사용하려고 했는데 import mod1을 수행하는 순간 mod1.py가 실행이 되어 결괏값을 출력함
  • 이러한 문제를 방지하려면 mod1.py 파일을 다음처럼 변경해야함
# mod1.py 
def add(a, b): 
    return a+b

def sub(a, b): 
    return a-b

if __name__ == "__main__":
    print(add(1, 4))
    print(sub(4, 2))
  • if __name__ == "__main__"을 사용하면 > python mod1.py처럼 직접 이 파일을 실행했을 때는 __name__ == "__main__"이 참이 되어 if문 다음 문장이 수행됨
  • 반대로 대화형 인터프리터나 다른 파일에서 이 모듈을 불러서 사용할 때는 __name__ == "__main__"이 거짓이 되어 if문 다음 문장이 수행되지 않음
  • 위와 같이 수정한 후 다시 대화형 인터프리터를 열고 실행하면 아무 결괏값도 출력되지 않는 것을 확인할 수 있음
>>> import mod1
>>>

__name__ 변수란?

  • 파이썬의 __name__ 변수는 파이썬이 내부적으로 사용하는 특별한 변수 이름
  • 만약 > python mod1.py처럼 직접 mod1.py 파일을 실행할 경우 mod1.py의 __name__ 변수에는 __main__ 값이 저장됨
  • 하지만 파이썬 셸이나 다른 파이썬 모듈에서 mod1을 import 할 경우에는 mod1.py의 __name__ 변수에는 mod1.py의 모듈 이름 값 mod1이 저장됨
>>> import mod1
>>> mod1.__name__
'mod1'

클래스나 변수 등을 포함한 모듈

  • 모듈은 함수만 포함했지만 클래스나 변수 등을 포함할 수 있음
# mod2.py 
PI = 3.141592	# 변수

class Math:		# 클래스
    def solv(self, r): 
        return PI * (r ** 2) 

def add(a, b): 	# 함수
    return a+b 
  • 이 파일은 원의 넓이를 계산하는 Math 클래스와 두 값을 더하는 add 함수 그리고 원주율 값에 해당되는 PI 변수처럼 클래스, 함수, 변수 등을 모두 포함하고 있음
> python
Type "help", "copyright", "credits" or "license" for more information.
>>> import mod2
>>> print(mod2.PI)
3.141592
  • mod2.PI처럼 입력해서 mod2.py 파일에 있는 PI 변수 값을 사용할 수 있음
>>> a = mod2.Math()
>>> print(a.solv(2))
12.566368
  • mod2.py에 있는 Math 클래스를 사용하는 방법을 보여줌
  • 위 예처럼 모듈 안에 있는 클래스를 사용하려면 “.”(도트 연산자)로 클래스 이름 앞에 모듈 이름을 먼저 입력해야 함
>>> print(mod2.add(mod2.PI, 4.4))
7.541592
  • mod2.py에 있는 add 함수 역시 당연히 사용할 수 있음

다른 파일에서 모듈 불러오기

  • 지금까지는 만들어 놓은 모듈 파일을 사용하기 위해 대화형 인터프리터만 사용함

다른 파이썬 파일에서 이전에 만들어 놓은 모듈을 불러와서 사용하는 방법

  • 조금 전에 만든 모듈인 mod2.py 파일을 다른 파이썬 파일에서 불러와 사용할 것임
  • 에디터로 modtest.py 파일을 다음과 같이 작성
# modtest.py
import mod2
result = mod2.add(3, 4)
print(result)
  • 다른 파이썬 파일에서도 import mod2로 mod2 모듈을 불러와서 사용할 수 있음
    • 대화형 인터프리터에서 한 것과 마찬가지 방법임
  • 위 예제가 정상적으로 실행되기 위해서는 modtest.py 파일과 mod2.py 파일이 동일한 디렉터리에 있어야 함

[모듈을 불러오는 또 다른 방법]

  • 지금껏 명령 프롬프트 창을 열고 모듈이 있는 디렉터리로 이동한 다음에 모듈을 사용할 수 있었음
  • 이번에는 모듈을 저장한 디렉터리로 이동하지 않고 모듈을 불러와서 사용하는 방법

1. sys.path.append(모듈을 저장한 디렉터리) 사용하기

  • 먼저 sys 모듈을 불러옴
> python
>>> import sys
  • sys 모듈은 파이썬을 설치할 때 함께 설치되는 라이브러리 모듈
  • sys 모듈을 사용하면 파이썬 라이브러리가 설치되어 있는 디렉터리를 확인할 수 있음
>>> sys.path
['', 'C:\\Windows\\SYSTEM32\\python37.zip', 'c:\\Python37\\DLLs', 
'c:\\Python37\\lib', 'c:\\Python37', 'c:\\Python37\\lib\\site-packages']
  • sys.path는 파이썬 라이브러리가 설치되어 있는 디렉터리를 보여 줌
  • 만약 파이썬 모듈이 위 디렉터리에 들어 있다면 모듈이 저장된 디렉터리로 이동할 필요 없이 바로 불러서 사용할 수 있음
    • 그렇다면 sys.path에 디렉터리를 추가하면 아무 곳에서나 불러 사용할 수 있음

명령 프롬프트 창에서는 /, \든 상관없지만, 소스 코드 안에서는 반드시 / 또는 \\ 기호를 사용해야 함

  • sys.path의 결괏값이 리스트이므로 다음과 같이 할 수 있음
>>> sys.path.append("C:/doit/mymod")
>>> sys.path
['', 'C:\\Windows\\SYSTEM32\\python37.zip', 'c:\\Python37\\DLLs', 
'c:\\Python37\\lib', 'c:\\Python37', 'c:\\Python37\\lib\\site-packages', 
'C:/doit/mymod']
>>>
  • sys.path.append를 사용해서 C:/doit/mymod라는 디렉터리를 sys.path에 추가한 후 다시 sys.path를 보면 가장 마지막 요소에 C:/doit/mymod라고 추가된 것을 확인할 수 있음
>>> import mod2
>>> print(mod2.add(3,4))
7
  • 실제로 모듈을 이상 없이 불러와서 사용할 수 있음

2. PYTHONPATH 환경 변수 사용하기

  • 모듈을 불러와서 사용하는 또 다른 방법으로는 PYTHONPATH 환경 변수를 사용하는 방법
C:\doit>set PYTHONPATH=C:\doit\mymod
C:\doit>python
>>> import mod2
>>> print(mod2.add(3,4))
7
  • set 명령어를 사용해 PYTHONPATH 환경 변수에 mod2.py 파일이 있는 C:\doit\mymod 디렉터리를 설정
  • 그러면 디렉터리 이동이나 별도의 모듈 추가 작업 없이 mod2 모듈을 불러와서 사용할 수 있음

5-3. 패키지

패키지란 무엇인가?

  • 패키지(Packages)는 도트(.)를 사용하여 파이썬 모듈을 계층적(디렉터리 구조)으로 관리할 수 있게 해주는 것
    • 예를 들어 모듈 이름이 A.B인 경우에 A는 패키지 이름이 되고 B는 A 패키지의 B모듈

파이썬에서 모듈은 하나의 .py 파일

  • 파이썬 패키지는 디렉터리와 파이썬 모듈로 이루어짐

가상의 game 패키지 예

game/
    __init__.py
    sound/
        __init__.py
        echo.py
        wav.py
    graphic/
        __init__.py
        screen.py
        render.py
    play/
        __init__.py
        run.py
        test.py
  • game, sound, graphic, play는 디렉터리이고 확장자가 .py인 파일은 파이썬 모듈
  • game 디렉터리가 이 패키지의 루트 디렉터리이고 sound, graphic, play는 서브 디렉터리

간단한 파이썬 프로그램이 아니라면 이렇게 패키지 구조로 파이썬 프로그램을 만드는 것이 공동 작업이나 유지 보수 등 여러 면에서 유리 또한 패키지 구조로 모듈을 만들면 다른 모듈과 이름이 겹치더라도 더 안전하게 사용할 수 있음

패키지 만들기

패키지 기본 구성 요소 준비하기

1. C:/doit 디렉터리 밑에 game 및 기타 서브 디렉터리를 생성하고 .py 파일들을 다음과 같이 구성

C:/doit/game/__init__.py
C:/doit/game/sound/__init__.py
C:/doit/game/sound/echo.py
C:/doit/game/graphic/__init__.py
C:/doit/game/graphic/render.py

2. 각 디렉터리에 __init__.py 파일을 만들어 놓기만 하고 내용은 일단 비워 둠

3. echo.py 파일은 다음과 같이 만듬

# echo.py
def echo_test():
    print("echo")

4. render.py 파일은 다음과 같이 만듬

# render.py
def render_test():
    print("render")

5. 다음 예제를 수행하기 전에 우리가 만든 game 패키지를 참조할 수 있도록 명령 프롬프트 창에서 set 명령어로 PYTHONPATH 환경 변수에 C:/doit 디렉터리를 추가
그리고 파이썬 인터프리터(Interactive shell)를 실행

C:\> set PYTHONPATH=C:/doit
C:\> python
Type "help", "copyright", "credits" or "license" for more information.
>>> 

패키지 안의 함수 실행하기

  • 패키지를 사용하여 echo.py 파일의 echo_test 함수를 실행
  • 패키지 안의 함수를 실행하는 방법은 다음 3가지가 있음
  • 다음 예제는 import 예제이므로 하나의 예제를 실행하고 나서 다음 예제를 실행할 때에는 반드시 인터프리터를 종료하고 다시 실행해야 함
  • 인터프리터를 다시 시작하지 않을 경우 이전에 import한 것들이 메모리에 남아 있어 엉뚱한 결과가 나올 수 있음(윈도우의 경우 인터프리터 종료는 Ctrl+Z).
  • 첫 번째는 echo 모듈을 import하여 실행하는 방법으로, 다음과 같이 실행함

echo 모듈은 echo.py 파일

>>> import game.sound.echo
>>> game.sound.echo.echo_test()
echo
  • 두 번째는 echo 모듈이 있는 디렉터리까지를 from … import하여 실행하는 방법
>>> from game.sound import echo
>>> echo.echo_test()
echo
  • 세 번째는 echo 모듈의 echo_test 함수를 직접 import하여 실행하는 방법
>>> from game.sound.echo import echo_test
>>> echo_test()
echo
  • 하지만 다음과 같이 echo_test 함수를 사용하는 것은 불가능

다음 예제는 반드시 파이썬 인터프리터를 종료하고 다시 실행해야 함

>>> import game
>>> game.sound.echo.echo_test()
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'sound'
  • import game을 수행하면 game 디렉터리의 __init__.py에 정의한 것만 참조할 수 있음
  • 다음처럼 echo_test 함수를 사용하는 것도 불가능
>>> import game.sound.echo.echo_test
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
ImportError: No module named echo_test
  • 도트 연산자(.)를 사용해서 import a.b.c처럼 import할 때 가장 마지막 항목인 c는 반드시 모듈 또는 패키지여야만 함

init.py 의 용도

  • __init__.py 파일은 해당 디렉터리가 패키지의 일부임을 알려주는 역할
  • 만약 game, sound, graphic 등 패키지에 포함된 디렉터리에 __init__.py 파일이 없다면 패키지로 인식되지 않음

python3.3 버전부터는 __init__.py 파일이 없어도 패키지로 인식함(PEP 420). 하지만 하위 버전 호환을 위해 __init__.py 파일을 생성하는 것이 안전한 방법

>>> from game.sound import *
>>> echo.echo_test()
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
NameError: name 'echo' is not defined
  • 분명 game.sound 패키지에서 모든 것(*)을 import하였으므로 echo 모듈을 사용할 수 있어야 할 것 같은데 echo라는 이름이 정의되지 않았다는 이름 오류(NameError)가 발생함
  • 이렇게 특정 디렉터리의 모듈을 *를 사용하여 import할 때에는 다음과 같이 해당 디렉터리의 __init__.py 파일에 __all__ 변수를 설정하고 import할 수 있는 모듈을 정의해야함
# C:/doit/game/sound/__init__.py
__all__ = ['echo']
  • 여기에서 __all__이 의미하는 것은 sound 디렉터리에서 * 기호를 사용하여 import할 경우 이곳에 정의된 echo 모듈만 import된다는 의미

착각하기 쉬운데 from game.sound.echo import *__all__과 상관없이 무조건 import됨 이렇게 __all__과 상관없이 무조건 import되는 경우는 from a.b.c import * 에서 from의 마지막 항목인 c가 모듈인 경우

  • 위와 같이 __init__.py 파일을 변경한 후 위 예제를 수행하면 원하던 결과가 출력되는 것을 확인할 수 있음
>>> from game.sound import *
>>> echo.echo_test()
echo

relative 패키지

  • 만약 graphic 디렉터리의 render.py 모듈이 sound 디렉터리의 echo.py 모듈을 사용하고 싶다면 다음과 같이 render.py를 수정하면 가능
# render.py
from game.sound.echo import echo_test
def render_test():
    print("render")
    echo_test()
  • from game.sound.echo import echo_test 문장을 추가하여 echo_test 함수를 사용할 수 있도록 수정함
>>> from game.graphic.render import render_test
>>> render_test()
render
echo
  • 위 예제처럼 from game.sound.echo import echo_test를 입력해 전체 경로를 사용하여 import할 수도 있지만 다음과 같이 relative하게 import하는 것도 가능
# render.py
from ..sound.echo import echo_test

def render_test():
    print("render")
    echo_test()
  • from game.sound.echo import echo_testfrom ..sound.echo import echo_test로 변경됨
  • 여기에서 ..은 render.py 파일의 부모 디렉터리를 의미
  • 따라서 render.py 파일의 부모 디렉터리는 game이므로 위와 같은 import가 가능

render.py 파일의 현재 디렉터리는 graphic이고 부모 디렉터리는 game

  • relative한 접근자에는 다음과 같음
    • .. – 부모 디렉터리
    • . – 현재 디렉터리

5-4. 예외 처리

  • 프로그램을 만들다 보면 수없이 많은 오류를 만나게 됨
  • 물론 오류가 발생하는 이유는 프로그램이 잘못 동작하는 것을 막기 위한 파이썬의 배려
  • 하지만 때때로 이러한 오류를 무시하고 싶을 때 이를 위해 파이썬은 try, except를 사용해서 예외적으로 오류를 처리할 수 있게 해줌

오류는 어떤 때 발생하는가?

  • 디렉터리 안에 없는 파일을 열려고 시도했을 때 발생하는 오류
>>> f = open("나없는파일", 'r')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
FileNotFoundError: [Errno 2] No such file or directory: '나없는파일'
  • 없는 파일을 열려고 시도하면 FileNotFoundError 오류가 발생
  • 0으로 다른 숫자를 나누는 경우 오류 발생
>>> 4 / 0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
  • 4를 0으로 나누려니까 ZeroDivisionError 오류가 발생
>>> a = [1,2,3]
>>> a[4]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range
  • a는 리스트 [1, 2, 3]인데 a[4]는 a 리스트에서 얻을 수 없는 값 따라서 IndexError 오류가 발생
  • 파이썬은 이런 오류가 발생하면 프로그램을 중단하고 오류 메시지를 보여줌

오류 예외 처리 기법

try, except문

  • 오류 처리를 위한 try, except문의 기본 구조
try:
    ...
except [발생 오류[as 오류 메시지 변수]]:
    ...
  • try 블록 수행 중 오류가 발생하면 except 블록이 수행됨 하지만 try 블록에서 오류가 발생하지 않는다면 except 블록은 수행되지 않음

except [발생 오류 [as 오류 메시지 변수]]:

  • [ ] 기호는 괄호 안의 내용을 생략할 수 있다는 관례 표기법

except 구문 3가지 방법

1. try, except만 쓰는 방법

try:
    ...
except:
    ...
  • 오류 종류에 상관없이 오류가 발생하면 except 블록을 수행

2. 발생 오류만 포함한 except문

try:
    ...
except 발생 오류:
    ...
  • 오류가 발생했을 때 except문에 미리 정해 놓은 오류 이름과 일치할 때만 except 블록을 수행

3. 발생 오류와 오류 메시지 변수까지 포함한 except문

try:
    ...
except 발생 오류 as 오류 메시지 변수:
    ...
  • 두 번째 경우에서 오류 메시지의 내용까지 알고 싶을 때 사용하는 방법

이 방법의 예

try:
    4 / 0
except ZeroDivisionError as e:
    print(e)
  • 4를 0으로 나누려고 하면 ZeroDivisionError가 발생하여 except 블록이 실행되고 변수 e에 담기는 오류 메시지를 다음과 같이 출력

결과값: division by zero

try .. finally

  • try문에는 finally절을 사용할 수 있음
  • finally절은 try문 수행 도중 예외 발생 여부에 상관없이 항상 수행됨
  • 보통 finally절은 사용한 리소스를 close해야 할 때에 많이 사용
f = open('foo.txt', 'w')
try:
    # 무언가를 수행한다.
finally:
    f.close()
  • foo.txt 파일을 쓰기 모드로 연 후에 try문을 수행한 후 예외 발생 여부와 상관없이 finally절에서 f.close()로 열린 파일을 닫을 수 있음

여러개의 오류처리하기

try:
    ...
except 발생 오류1:
   	... 
except 발생 오류2:
   	...
  • 0으로 나누는 오류와 인덱싱 오류를 다음과 같이 처리할 수 있음
try:
    a = [1,2]
    print(a[3])
    4/0
except ZeroDivisionError:
    print("0으로 나눌 수 없습니다.")
except IndexError:
    print("인덱싱 할 수 없습니다.")
  • a는 2개의 요솟값을 가지고 있기 때문에 a[3]IndexError를 발생시키므로 “인덱싱할 수 없습니다.”라는 문자열이 출력됨
  • 인덱싱 오류가 먼저 발생했으므로 4/0으로 발생되는 ZeroDivisionError 오류는 발생하지 않음
try:
    a = [1,2]
    print(a[3])
    4/0
except ZeroDivisionError as e:
    print(e)
except IndexError as e:
    print(e)
  • 프로그램을 실행하면 “list index out of range” 오류 메시지가 출력
  • ZerroDivisionErrorIndexError를 함께 처리할 수도 있음
try:
    a = [1,2]
    print(a[3])
    4/0
except (ZeroDivisionError, IndexError) as e:
    print(e)

try문에 else절 사용하기

  • try문에는 다음처럼 else절을 사용할 수 있음
try:
    ...
except [발생 오류[as 오류 메시지 변수]]:
    ...
else:  # 오류가 없을 경우에만 수행된다.
    ...
  • try문 수행중 오류가 발생하면 except절이 수행되고 오류가 없으면 else절이 수행됨
try:
    age=int(input('나이를 입력하세요: '))
except:
    print('입력이 정확하지 않습니다.')
else:
    if age <= 18:
        print('미성년자는 출입금지입니다.')
    else:
        print('환영합니다.')
  • 만약 ‘나이를 입력하세요:’ 라는 질문에 숫자가 아닌 다른 값을 입력하면 오류가 발생하여 ‘입력이 정확하지 않습니다.’라는 문장을 출력함
  • 오류가 없을 경우에만 else절이 수행됨

오류 회피하기

  • 특정 오류가 발생했을 때 그냥 통과시켜야 할 경우
try:
    f = open("나없는파일", 'r')
except FileNotFoundError:
    pass
  • try문 안에서 FileNotFoundError가 발생할 경우에 pass를 사용하여 오류를 그냥 회피하도록 작성한 예제

오류 일부러 발생시키기

  • 이상하게 들리겠지만 프로그래밍을 하다 보면 종종 오류를 일부러 발생시켜야 할 경우도 생김
  • 파이썬은 raise 명령어를 사용해 오류를 강제로 발생시킬 수 있음

  • 예를 들어 Bird 클래스를 상속받는 자식 클래스는 반드시 fly라는 함수를 구현하도록 만들고 싶은 경우(강제로 그렇게 하고 싶은 경우)
class Bird:
    def fly(self):
        raise NotImplementedError
  • 위 예제는 Bird 클래스를 상속받는 자식 클래스는 반드시 fly 함수를 구현해야 한다는 의지를 보여줌
  • 만약 자식 클래스가 fly 함수를 구현하지 않은 상태로 fly 함수를 호출한다면?

NotImplementedError는 파이썬 내장 오류로, 꼭 작성해야 하는 부분이 구현되지 않았을 경우 일부러 오류를 일으키기 위해 사용함

class Eagle(Bird):
    pass

eagle = Eagle()
eagle.fly()
  • Eagle 클래스는 Bird 클래스를 상속받는다. 그런데 Eagle 클래스에서 fly 함수를 구현하지 않았기 때문에 Bird 클래스의 fly 함수가 호출됨
  • 그리고 raise문에 의해 NotImplemented Error가 발생함

상속받는 클래스에서 함수를 재구현하는 것을 메서드 오버라이딩이라고 부름

Traceback (most recent call last):
  File "...", line 33, in <module>
    eagle.fly()
  File "...", line 26, in fly
    raise NotImplementedError
NotImplementedError
  • NotImplementedError가 발생되지 않게 하려면 다음과 같이 Eagle 클래스에 fly 함수를 반드시 구현해야함
class Eagle(Bird):
    def fly(self):
        print("very fast")

eagle = Eagle()
eagle.fly()
  • 위 예처럼 fly 함수를 구현한 후 프로그램을 실행하면 오류 없이 다음 문장이 출력됨
very fast

예외 만들기

  • 프로그램 수행 도중 특수한 경우에만 예외 처리를 하기 위해서 종종 예외를 만들어서 사용
  • 예외는 다음과 같이 파이썬 내장 클래스인 Exception 클래스를 상속하여 만들 수 있음
class MyError(Exception):
    pass
  • 별명을 출력해 주는 함수를 다음과 같이 작성
def say_nick(nick):
    if nick == '바보':
        raise MyError()
    print(nick)
  • 다음과 같이 say_nick 함수를 호출
say_nick("천사")
say_nick("바보")
  • 저장한 뒤 프로그램을 실행해 보면 다음과 같이 “천사”가 한 번 출력된 후 MyError가 발생
천사
Traceback (most recent call last):
  File "...", line 11, in <module>
    say_nick("바보")
  File "...", line 7, in say_nick
    raise MyError()
__main__.MyError
  • 이번에는 예외 처리 기법을 사용하여 MyError 발생을 예외 처리
try:
    say_nick("천사")
    say_nick("바보")
except MyError:
    print("허용되지 않는 별명입니다.")
  • 프로그램을 실행하면 다음과 같이 출력
천사
허용되지 않는 별명입니다.
  • 만약 오류 메시지를 사용하고 싶다면 다음처럼 예외 처리를 하면 됨
try:
    say_nick("천사")
    say_nick("바보")
except MyError as e:
    print(e)
  • 하지만 프로그램을 실행해 보면 print(e)로 오류 메시지가 출력되지 않음
  • 오류 메시지를 출력했을 때 오류 메시지가 보이게 하려면 오류 클래스에 다음과 같은 __str__ 메서드를 구현해야 함
  • __str__ 메서드는 print(e)처럼 오류 메시지를 print문으로 출력할 경우에 호출되는 메서드
class MyError(Exception):
    def __str__(self):
        return "허용되지 않는 별명입니다."
  • 프로그램을 다시 실행해 보면 “허용되지 않는 별명입니다.”라는 오류메시지가 출력됨

5-5. 내장 함수

  • 파이썬 내장 함수는 외부 모듈과 달리 import가 필요하지 않기 때문에 아무런 설정 없이 바로 사용할 수 있

abs

  • abs(x)는 어떤 숫자를 입력받았을 때, 그 숫자의 절댓값을 돌려주는 함수
>>> abs(3)
3
>>> abs(-3)
3
>>> abs(-1.2)
1.2

all

  • all(x)는 반복 가능한(iterable) 자료형 x를 입력 인수로 받으며 이 x의 요소가 모두 참이면 True, 거짓이 하나라도 있으면 False

반복 가능한 자료형이란 for문으로 그 값을 출력할 수 있는 것을 의미함
리스트, 튜플, 문자열, 딕셔너리, 집합 등

>>> all([1, 2, 3])
True
  • 리스트 자료형 [1, 2, 3]은 모든 요소가 참이므로 True
>>> all([1, 2, 3, 0])
False
  • 리스트 자료형 [1, 2, 3, 0] 중에서 요소 0은 거짓이므로 False
>>> all([])
True
  • 만약 all의 입력 인수가 빈 값인 경우에는 True를 리턴함

any

  • any(x)는 반복 가능한(iterable) 자료형 x를 입력 인수로 받으며 이 x의 요소 중 하나라도 참이 있으면 True, x가 모두 거짓일 때에만 False
  • all(x)의 반대임
>>> any([1, 2, 3, 0])
True
  • 리스트 자료형 [1, 2, 3, 0] 중에서 1, 2, 3이 참이므로 True
>>> any([0, ""])
False
  • 리스트 자료형 [0, ““]의 요소 0과 ““은 모두 거짓이므로 False
>>> any([])
False
  • 만약 any의 입력 인수가 빈 값인 경우에는 False를 리턴

chr

  • chr(i)는 유니코드(Unicode) 값을 입력받아 그 코드에 해당하는 문자를 출력하는 함수

유니코드는 전 세계의 모든 문자를 컴퓨터에서 일관되게 표현하고 다룰 수 있도록 설계된 산업 표준

>>> chr(97)
'a'
>>> chr(44032)
'가'

dir

  • dir은 객체가 자체적으로 가지고 있는 변수나 함수를 보여줌
  • 다음 예는 리스트와 딕셔너리 객체 관련 함수(메서드)를 보여 주는 예
>>> dir([1, 2, 3])
['append', 'count', 'extend', 'index', 'insert', 'pop',...]
>>> dir({'1':'a'})
['clear', 'copy', 'get', 'has_key', 'items', 'keys',...]

divmod

  • divmod(a, b)는 2개의 숫자를 입력으로 받고 a를 b로 나눈 몫과 나머지를 튜플 형태로 돌려주는 함수
>>> divmod(7, 3)
(2, 1)
  • 몫을 구하는 연산자 //와 나머지를 구하는 연산자 %를 각각 사용한 결과와 비교
>>> 7 // 3
2
>>> 7 % 3
1

enumerate

  • enumerate는 “열거하다”라는 뜻
  • 이 함수는 순서가 있는 자료형(리스트, 튜플, 문자열)을 입력으로 받아 인덱스 값을 포함하는 enumerate 객체를 돌려줌

보통 enumerate 함수는 다음 예제처럼 for문과 함께 자주 사용함

>>> for i, name in enumerate(['body', 'foo', 'bar']):
...     print(i, name)
...
0 body
1 foo
2 bar
  • 순서 값과 함께 body, foo, bar가 순서대로 출력됨 즉 위 예제와 같이 enumerate를 for문과 함께 사용하면 자료형의 현재 순서(index)와 그 값을 쉽게 알 수 있음
  • for문처럼 반복되는 구간에서 객체가 현재 어느 위치에 있는지 알려 주는 인덱스 값이 필요할때 enumerate 함수를 사용하면 매우 유용함

eval

  • eval(expression )은 실행 가능한 문자열(1+2, ‘hi’ + ‘a’ 같은 것)을 입력으로 받아 문자열을 실행한 결괏값을 돌려주는 함수
>>> eval('1+2')
3
>>> eval("'hi' + 'a'")
'hia'
>>> eval('divmod(4, 3)')
(1, 1)
  • 보통 eval은 입력받은 문자열로 파이썬 함수나 클래스를 동적으로 실행하고 싶을 때 사용

filter

  • filter란 무엇인가를 걸러낸다는 뜻으로 filter 함수도 동일한 의미를 가짐
  • filter 함수는 첫 번째 인수로 함수 이름을, 두 번째 인수로 그 함수에 차례로 들어갈 반복 가능한 자료형을 받음
  • 두 번째 인수인 반복 가능한 자료형 요소가 첫 번째 인수인 함수에 입력되었을 때 반환 값이 참인 것만 묶어서(걸러 내서) 돌려줌
#positive.py 
def positive(l): 
    result = [] 
    for i in l: 
        if i > 0: 
            result.append(i) 
    return result

print(positive([1,-3,2,0,-5,6]))

결과값: [1, 2, 6]

  • 위에서 만든 positive 함수는 리스트를 입력값으로 받아 각각의 요소를 판별해서 양수 값만 돌려주는 함수
  • filter 함수를 사용하면 위 내용을 다음과 같이 간단하게 작성할 수 있음
#filter1.py
def positive(x):
    return x > 0

print(list(filter(positive, [1, -3, 2, 0, -5, 6])))

결과값: [1, 2, 6]

  • 여기에서는 두 번째 인수인 리스트의 요소들이 첫 번째 인수인 positive 함수에 입력되었을때 반환 값이 참인 것만 묶어서 돌려줌
  • 앞의 예에서는 1, 2, 6만 양수여서 x > 0 문장이 참이되므로 [1, 2, 6]이라는 결괏값을 돌려주게 됨
  • 앞의 함수는 lambda를 사용하면 더욱 간편하게 코드를 작성할 수 있음
>>> list(filter(lambda x: x > 0, [1, -3, 2, 0, -5, 6]))
[1, 2, 6]

hex

  • hex(x)는 정수 값을 입력받아 16진수(hexadecimal)로 변환하여 돌려주는 함수
>>> hex(234)
'0xea'
>>> hex(3)
'0x3'

id

  • id(object)는 객체를 입력받아 객체의 고유 주소 값(레퍼런스)을 돌려주는 함수
>>> a = 3
>>> id(3)
135072304
>>> id(a)
135072304
>>> b = a
>>> id(b)
135072304
  • 위 예의 3, a, b는 고유 주소 값이 모두 135072304 즉 3, a, b가 모두 같은 객체를 가리킴
  • 만약 id(4)라고 입력하면 4는 3, a, b와 다른 객체이므로 당연히 다른 고유 주소 값이 출력됨
>>> id(4)
135072292

input

  • input([prompt])은 사용자 입력을 받는 함수
  • 매개변수로 문자열을 주면 다음 세 번째 예에서 볼 수 있듯이 그 문자열은 프롬프트가 됨

[ ] 기호는 괄호 안의 내용을 생략할 수 있다는 관례 표기법임

>>> a = input()
hi
>>> a
'hi'
>>> b = input("Enter: ")
Enter: hi
>>> b
'hi'

int

  • int(x)는 문자열 형태의 숫자나 소수점이 있는 숫자 등을 정수 형태로 돌려주는 함수로, 정수를 입력으로 받으면 그대로 돌려줌
>>> int('3')
3
>>> int(3.4)
3
  • int(x, radix)는 radix 진수로 표현된 문자열 x를 10진수로 변환하여 돌려줌
  • 2진수로 표현된 11의 10진수 값은 다음과 같이 구함
>>> int('11', 2)
3
  • 16진수로 표현된 1A의 10진수 값은 다음과 같이 구함
>>> int('1A', 16)
26

isinstance

  • isinstance(object, class )는 첫 번째 인수로 인스턴스, 두 번째 인수로 클래스 이름을 받음
  • 입력으로 받은 인스턴스가 그 클래스의 인스턴스인지를 판단하여 참이면 True, 거짓이면 False를 돌려줌
>>> class Person: pass
...
>>> a = Person()
>>> isinstance(a, Person)
True
  • 위 예는 a가 Person 클래스가 만든 인스턴스임을 확인시켜 줌
>>> b = 3
>>> isinstance(b, Person)
False
  • b는 Person 클래스가 만든 인스턴스가 아니므로 False를 돌려줌

len

  • len(s)은 입력값 s의 길이(요소의 전체 개수)를 돌려주는 함수
>>> len("python")
6
>>> len([1,2,3])
3
>>> len((1, 'a'))
2

list

  • list(s)는 반복 가능한 자료형 s를 입력받아 리스트로 만들어 돌려주는 함수
>>> list("python")
['p', 'y', 't', 'h', 'o', 'n']
>>> list((1,2,3))
[1, 2, 3]
  • list 함수에 리스트를 입력으로 주면 똑같은 리스트를 복사하여 돌려줌
>>> a = [1, 2, 3]
>>> b = list(a)
>>> b
[1, 2, 3]

map

  • map(f, iterable)은 함수(f)와 반복 가능한(iterable) 자료형을 입력으로 받음
  • map은 입력받은 자료형의 각 요소를 함수 f가 수행한 결과를 묶어서 돌려주는 함수
# two_times.py
def two_times(numberList):
    result = [ ]
    for number in numberList:
        result.append(number*2)
    return result

result = two_times([1, 2, 3, 4])
print(result)
  • two_times 함수는 리스트 요소를 입력받아 각 요소에 2를 곱한 결괏값을 돌려줌

결과값: [2, 4, 6, 8]

  • 위 예제는 map 함수를 사용하면 다음처럼 바꿀 수 있음
>>> def two_times(x): 
...     return x*2
...
>>> list(map(two_times, [1, 2, 3, 4]))
[2, 4, 6, 8]
  • 먼저 리스트의 첫 번째 요소인 1이 two_times 함수의 입력값으로 들어가고 1 * 2의 과정을 거쳐서 2가 됨
  • 다음으로 리스트의 두 번째 요소인 2가 2 * 2 의 과정을 거쳐 4가 됨
  • 따라서 결괏값 리스트는 이제 [2, 4]가 됨
  • 총 4개의 요솟값이 모두 수행되면 마지막으로 [2, 4, 6, 8]을 돌려줌
  • 이것이 map 함수가 하는 일

위 예에서 map의 결과를 리스트로 보여 주기위해 list 함수를 사용하여 출력함

  • 앞의 예는 lambda를 사용하면 다음처럼 간략하게 만들 수 있음
>>> list(map(lambda a: a*2, [1, 2, 3, 4]))
[2, 4, 6, 8]

max

  • max(iterable)는 인수로 반복 가능한 자료형을 입력받아 그 최댓값을 돌려주는 함수
>>> max([1, 2, 3])
3
>>> max("python")
'y'

min

  • min(iterable)은 max 함수와 반대로, 인수로 반복 가능한 자료형을 입력받아 그 최솟값을 돌려주는 함수
>>> min([1, 2, 3])
1
>>> min("python")
'h'

oct

  • oct(x)는 정수 형태의 숫자를 8진수 문자열로 바꾸어 돌려주는 함수
>>> oct(34)
'0o42'
>>> oct(12345)
'0o30071'

open

  • open(filename, [mode])은 “파일 이름”과 “읽기 방법”을 입력받아 파일 객체를 돌려주는 함수
  • 읽기 방법(mode)을 생략하면 기본값인 읽기 전용 모드(r)로 파일 객체를 만들어 돌려줌
mode 설명
w 쓰기 모드로 파일 열기
r 읽기 모드로 파일 열기
a 추가 모드로 파일 열기
b 바이너리 모드로 파일 열기
  • b는 w, r, a와 함께 사용함
>>> f = open("binary_file", "rb")
  • 위 예의 rb는 “바이너리 읽기 모드”를 의미
  • 다음 예의 fread와 fread2는 동일한 방법
>>> fread = open("read_mode.txt", 'r')
>>> fread2 = open("read_mode.txt")
  • 즉 모드 부분을 생략하면 기본값으로 읽기 모드 r를 갖게 됨
  • 다음은 추가 모드(a)로 파일을 여는 예
>>> fappend = open("append_mode.txt", 'a')

ord

  • ord(c)는 문자의 유니코드 값을 돌려주는 함수

ord 함수는 chr 함수와 반대

>>> ord('a')
97
>>> ord('가')
44032

pow

  • pow(x, y)는 x의 y 제곱한 결괏값을 돌려주는 함수
>>> pow(2, 4)
16
>>> pow(3, 3)
27

range

  • range([start,] stop [,step] )는 for문과 함께 자주 사용하는 함수
  • 이 함수는 입력받은 숫자에 해당하는 범위 값을 반복 가능한 객체로 만들어 돌려줌

인수가 하나일 경우

  • 시작 숫자를 지정해 주지 않으면 range 함수는 0부터 시작
>>> list(range(5))
[0, 1, 2, 3, 4]

인수가 2개일 경우

  • 입력으로 주어지는 2개의 인수는 시작 숫자와 끝 숫자를 나타냄
  • 단 끝 숫자는 해당 범위에 포함되지 않는다는 것에 주의
>>> list(range(5, 10))
[5, 6, 7, 8, 9]

인수가 3개일 경우

  • 세 번째 인수는 숫자 사이의 거리
>>> list(range(1, 10, 2))
[1, 3, 5, 7, 9]
>>> list(range(0, -10, -1))
[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]

round

  • round(number[, ndigits]) 함수는 숫자를 입력받아 반올림해 주는 함수

[, ndigits]는 ndigits가 있을 수도 있고 없을 수도 있다는 의미

>>> round(4.6)
5
>>> round(4.2)
4
  • 다음과 같이 실수 5.678을 소수점 2자리까지만 반올림하여 표시할 수 있음
>>> round(5.678, 2)
5.68
  • round 함수의 두 번째 매개변수는 반올림하여 표시하고 싶은 소수점의 자릿수(ndigits)

sorted

  • sorted(iterable) 함수는 입력값을 정렬한 후 그 결과를 리스트로 돌려주는 함수
>>> sorted([3, 1, 2])
[1, 2, 3]
>>> sorted(['a', 'c', 'b'])
['a', 'b', 'c']
>>> sorted("zero")
['e', 'o', 'r', 'z']
>>> sorted((3, 2, 1))
[1, 2, 3]
  • 리스트 자료형에도 sort 함수가 있음
  • 하지만 리스트 자료형의 sort 함수는 리스트 객체 그 자체를 정렬만 할 뿐 정렬된 결과를 돌려주지는 않음

str

  • str(object)은 문자열 형태로 객체를 변환하여 돌려주는 함수
>>> str(3)
'3'
>>> str('hi')
'hi'
>>> str('hi'.upper())
'HI'

sum

  • sum(iterable) 은 입력받은 리스트나 튜플의 모든 요소의 합을 돌려주는 함수
>>> sum([1,2,3])
6
>>> sum((4,5,6))
15

tuple

  • tuple(iterable)은 반복 가능한 자료형을 입력받아 튜플 형태로 바꾸어 돌려주는 함수
  • 만약 튜플이 입력으로 들어오면 그대로 돌려줌
>>> tuple("abc")
('a', 'b', 'c')
>>> tuple([1, 2, 3])
(1, 2, 3)
>>> tuple((1, 2, 3))
(1, 2, 3)

type

  • type(object)은 입력값의 자료형이 무엇인지 알려 주는 함수
>>> type("abc")
<class 'str'>
>>> type([ ])
<class 'list'>
>>> type(open("test", 'w'))
<class '_io.TextIOWrapper'>

zip

  • zip(*iterable)은 동일한 개수로 이루어진 자료형을 묶어 주는 역할을 하는 함수

여기서 사용한 *iterable은 반복 가능(iterable)한 자료형 여러 개를 입력할 수 있다는 의미

>>> list(zip([1, 2, 3], [4, 5, 6]))
[(1, 4), (2, 5), (3, 6)]
>>> list(zip([1, 2, 3], [4, 5, 6], [7, 8, 9]))
[(1, 4, 7), (2, 5, 8), (3, 6, 9)]
>>> list(zip("abc", "def"))
[('a', 'd'), ('b', 'e'), ('c', 'f')]

References

점프 투 파이썬