본문 바로가기

개발공부/Python

[파이썬 입문 3] 연산자

1. 연산자

앞의 챕터에서 이미 몇가지 연산자를 살펴보았다.
값을 부정하는 not 연산자와 값을 대입할 때 사용하는 = 연산자를 살펴보았다.
또, 문자열과 변수를 + 연산자로 연결했었다.

이처럼 파이썬에는 다양한 연산자가 있는데, 이것들을 어떻게 사용하는지 살펴보자.

1-1. 산술 연산자

연산자(operator)는 프로그래밍에서 연산할 때 사용하는 기호이다.
일반적으로 수학에 나오는 연산 기호를 파이썬에서도 연산자로 사용한다.

먼저 사칙연산 기호부터 살펴보자.
사칙연산 기호는 수를 연산하는데 사용하기때문에 산술 연산자라고 한다.

산술 연산자는 이미 숫자 자료형에서 수식을 다룰 때 이미 만나본 적 있다.

코딩을 할때는 곱하기를 할때는 * 를 사용하고, 나누기를 할때는 / 를 사용한다.
(더하기는 +, 빼기는 - 로 우리가 알고 있는 것과 같다.)

print(1+ 1)
print(3 - 2)
print(5 * 2)
print(6 / 3)

# 출력 결과
# 2
# 1
# 10
# 2.0

위 코드는 print()문에 산술 연산자를 이용한 결과이다.
출력 결과를 보면 나누기 결과는 정수 2가 아닌 실수 2.0으로 표시된다.
(정수와 정수의 나눗셈 결과로 정수가 나오기를 바란다면 / 대신 // 과 같이 // 연산자를 사용하는 방법이 있다.)

그럼 조금 더 어려운 연산들을 만나보자.

print(2 ** 3)
print(10 % 3)
print(10 // 3)

# 출력 결과
# 8
# 1
# 3

위 코드의 첫번째 연산자 **는 연산자 앞의 수를 뒤의 수만큼 거듭제곱하라는 뜻이다.
그래서 2^3의 결과인 8이 나오게 되는것이다.

두번째 연산자 %는 연산자 앞의 수를 뒤의 수로 나눈 나머지를 구하라는 뜻이다.
따라서 10을 3으로 나누면 몫이 3이고 나머지가 1이기 때문에 결과값이 1로 나오는 것이다.

세번째 연산자 //는 연산자 앞의 수를 뒤의 수로 나눈 몫을 구하라는 뜻이다.
따라서 10을 3으로 나누면 몫이 3이기때문에 결과값이 3으로 나온것이다.
즉, 우리가 원하는 정수 형태의 결과를 얻을 수 있다.

1-2. 비교 연산자

수학에는 등호와 함께 값의 크기를 비교할 때 사용하는 부등호(>, <, <=, >=)가 있다.
파이썬에서도 같은 기호로 비교 연산을 수행하며 이들을 비교 연산자라고 부른다.

: 왼쪽이 오른쪽보다 크다.

  1. < : 왼쪽이 오른쪽보다 크다.

= : 왼쪽이 오른쪽보다 크거나 같다.

  1. <= : 왼쪽이 오른쪽보다 작거나 같다.
print(10 > 3)
print(4 >= 7)
print(10 < 3)
print(5 <= 5)

# 출력 결과
# True
# False
# False
# True

위 코드처럼 비교 연산자는 산술 연산자와 달리 값을 계산하지 않고 값을 비교한다.
값을 비교해서 맞으면 True를, 아니면 False를 출력한다.

이전의 글에서 파이썬에서 등호(=)는 같다는 의미가 아닌 값을 대입한다는 의미로 사용한다고 했다.
그렇다면 같다는 의미를 하고 싶을땐 어떻게 해야할까?

같다는 의미를 하고 싶을때는 등호를 2번 연속으로 써서 == 형태로 표시한다.
또, 다르다는 의미를 나타내고 싶을 때는 등호 앞에 !를 붙여 != 형태로 표시한다.

print(3 == 3)
print(4 == 2)
print(3 + 4 == 7)
print(1 != 3)

# 출력 결과
# True
# False
# True
# True

이처럼 == 와 != 도 식이 맞는지 틀리는지에 따라서 True 혹은 False로 출력한다.

1-3. 논리 연산자

논리 연산자는 수식, 조건 등이 참인지 거짓인지 판단할 때 사용한다.
이전에 배운 not연산자를 포함해 파이썬에서 사용하는 논리 연산자는 다음과 같다.

  1. and : 연산자 왼쪽과 오른쪽이 모두 참이면 참
  2. or : 연산자 왼쪽과 오른쪽 중 하나라도 참이면 참
  3. not : 값이 참이면 거짓, 거짓이면 참

논리 연산자를 사용하면 비교 연산자와 마찬가지로 판단 결과에 따라 True 또는 False를 출력한다.

print((3 > 0) and (3 > 5))
print((3 > 0) or (3 > 5))
print(not(1 != 3))

# 출력 결과
# False
# True
# False

첫번째 줄의 3 > 0은 True, 3 > 5는 False이며, True and False는 False 이므로 결과가 False로 나온것이다.
두번째 줄의 3 > 0은 True, 3 > 5는 False이며, True or False는 True이므로 결과가 True로 나온것이다.
세번째 줄의 1 != 3은 True, not True는 False이므로 결과가 False로 나온것이다.

1-3-1. 단축 평가

논리 연산자에서 and와 or는 앞의 연산 결과에 따라 뒤의 연산이 수행되지 않을 수도 있는데,
이를 단축 평가(short circuit evaluation) 라고 한다.
and 연산자는 앞뒤 연산이 모두 참일 때 True가 된다.
그래서 앞의 연산이 이미 False라면 뒤의 연산은 결과가 참이건 거짓이건 상관없으므로 수행되지 않는다.
or 연산자는 앞뒤 연산 중 하나라도 참일 때 True가 되는데 앞의 연산이 이미 True라면 뒤의 연산은 하지 않아도 상관없으므로 수행되지 않는다.

print(5 > 4 > 3)
print(4 > 5 > 3)

# 출력 결과
# True
# False

첫번째 줄에서 5 > 4는 참이므로 다음 수식을 확인한다. 이후, 4 > 3도 참이므로 결과는 True가 된다.
두번째 줄에서 4 > 5는 거짓이므로 뒤의 연산 결과에 상관없이 False가 된다.
따라서 뒤의 수식을 수행하지 않고 결과를 출력한다.

2. 연산자의 우선순위

2 + 3 x 4 = ? 이 수식의 결과값은 무엇일까? 20일까?
정답은 14이다.
우리는 모두 왜 이런 결과가 나오는지 알 것이다.
사칙연산에서 곱하기와 나누기를 먼저 계산해야한다는 것을 알기 때문이다.

(2 + 3) x 4 = ? 그렇다면 이 수식의 결과값은 무엇일까?
정답은 20이다.
곱하기와 나누기보다 소괄호 안의 계산을 먼저 해야한다는 것을 알고 있기 때문이다.

수학의 연산 기호와 마찬가지로 파이썬 연산자도 우선 순위가 있다.
앞의 수식을 파이썬 코드로 작성해서 결과를 살펴보도록 하자.

print(2 + 3 * 4)
print((2 + 3) * 4)

# 출력 결과
# 14
# 20

파이썬 연산자의 우선순위 때문에 두 수식의 연산 결과가 다르게 나온다.
이처럼 연산자를 사용할 때는 우선순위에 따라 연산 순서가 달라지므로 연산자의 우선순위를 잘 확인해야 한다.

파이썬에서 사용하는 주요 연산자의 우선순위는 다음과 같다.
위에서 아래로 갈수록 우선순위가 낮다.

우선순위 높음
[], {}, () : 리스트, 딕셔너리, 세트, 튜플
** : 거듭제곱
*, /, //, % : 곱셈, 나눗셈, 정수 나눗셈, 나머지
+, - : 덧셈, 뺄셈
not, in, <, <=, >, >=, !=, == : 부정, 비교 연산자
and, or : 논리 연산자
= : 대입 연산자
우선순위 낮음

3. 변수로 연산하기

변수와 연산자를 함께 사용해보자.
수식을 number라는 변수에 넣고 변수의 값을 출력해보자.

number = 2 + 3 * 4
print(number)

# 출력 결과
# 14

현재 변수 number의 값은 14이다.
여기에 2를 더하려면 어떻게 해야할까?

number = 2 + 3 * 4
print(number)
number = 2 + 3 * 4 + 2
print(number)

# 14
# 16

이렇게 표현할 수 있을 것이다.
하지만 변수를 활용해서 다시 한번 적어보자.

3-1. 변수를 이용하여 코드 줄이기

number = 2 + 3 * 4 + 2에서 마지막 + 2를 제외하고는 number이기 때문에
number = number + 2로 적을 수 있을것이다.
그럼 결과를 출력해서 확인을 해보자.

number = 2 + 3 * 4
print(number)
number = number + 2
# number = (2 + 3 * 4) + 2
print(number)

# 14
# 16

16이 잘 출력되는 것을 확인할 수 있다.

여기서 코드를 한번 더 줄일 수 있는데, 대입 연산자와 산술 연산자를 합친 복합 대입 연산자(augmented assignment operator)를 사용하면 된다.

3-2. 복합 대입 연산자(augmented assignment operator)

  1. += : 연산자 왼쪽 값에 오른쪽 값을 더한 후 왼쪽 값에 대입
    number = number + 2 -> number += 2
  2. -= : 연산자 왼쪽 값에서 오른쪽 값을 뺀 후 왼쪽 값에 대입
    number = number - 2 -> number -= 2
  3. *= : 연산자 왼쪽 값에 오른쪽 값을 곱한 후 왼쪽 값에 대입
    number = number * 2 -> number *= 2
  4. /= : 연산자 왼쪽 값을 오른쪽 값으로 나눈 후 왼쪽 값에 대입
    number = number / 2 -> number /= 2
  5. **= : 연산자 왼쪽 값을 오른쪽 값으로 거듭제곱한 후 왼쪽 값에 대입
    number = number ** 2 -> number **= 2
  6. //= : 연산자 왼쪽 값을 오른쪽 값으로 나눈 후 몫을 왼쪽 값에 대입
    number = number // 2 -> number //= 2
  7. %= : 연산자 왼쪽 값을 오른쪽 값으로 나눈 후 나머지를 왼쪽 값에 대입
    number = number % 2 -> number %= 2

이제 앞의 코드를 복합 대입 연산자를 이용하여 더 줄여보도록 하자.

number = 2 + 3 * 4
print(number)
# number = (2 + 3 * 4) + 2
# number = number + 2
number += 2
print(number)

# 14
# 16

이렇게 만들어주면 코드가 더 짧아지고, 변수 덕분에 반복 연산도 할 수 있다.

4. 함수로 연산하기

4-1. 숫자 처리 함수

파이썬에서는 다음과 같이 숫자 연산을 할 수 있는 여러 함수를 제공한다.

  1. abs(x) : x의 절대값
  2. pow(x, y) : x를 y만큼 거듭제곱한 값
  3. max() : 가장 큰 값
  4. min() : 가장 작은 값
  5. round(x, d) : x를 반올림한 값, d는 표시할 소수점 이하 자릿수. d가 없으면 소수점 이하 첫째 자리에서 반올림한 정수

위의 함수를 이용하여 예시를 확인해보자.

print(abs(-5))
print(pow(4, 2))
print(max(5, 12))
print(min(5, 12))
print(round(3.14))
print(round(4.678, 2))

# 5 <- -5의 절대값은 5이므로
# 16 <- 4를 제곱하면 16
# 12 <- 5와 12중 큰 값은 12
# 5 <- 5와 12 중 작은 값은 5
# 3 <- 3.14를 소수점 아래 첫째자리에서 반올림한 정수
# 4.68 <- 4.678을 소수점 아래 두번째 자리에서 반올림한 정수

4-2. math 모듈

숫자 연산을 수행하는 함수는 다음과 같이 math 모듈에도 있다.

  1. floor() : 내림
  2. cell() : 올림
  3. sqrt() : 제곱근

모듈(module)은 어떤 기능을 하는 코드를 모아 놓은 파이썬 파일을 의미한다.
직접 만들 수도 있고 파이썬에 이미 만들어져 있는 모듈을 가져와서 사용할 수도 있다.
프로그램에 모듈의 기능을 가져다 쓰려면 사용하기 전에 다음 형태의 구문을 추가해야 한다.

4-2-1. 모듈 사용을 위한 구문 추가

from 모듈명 import 기능

기능 부분에 * 을 넣으면 모듈 안 모든 기능을 가져다 쓰겠다는 의미가 된다.
그래서 math 모듈에 속한 함수를 모두 사용하고 싶다면 다음과 같이 작성하면 된다.

from math import *
# math모듈의 모든 기능을 가져다 쓰겠다는 의미

result = floor(4.99)
# 4.99의 내림
print(result)

result = ceil(3.14)
# 3.14의 올림
print(result)

result = sqrt(16)
# 16의 제곱근
print(result)

# 4
# 4
# 4.0

모듈의 기능을 가져다 쓸 때 다르게 작성하는 방법도 있다.

import 모듈명

하지만 위와 같이 사용하는 경우 기능 앞에 기능이 속한 모듈명을 점(.)으로 연결해서 적어야한다.

import math

result = math.floor(4.99)
print(result)

result = math.ceil(3.14)
print(result)

result = math.sqrt(16)
print(result)

# 4
# 4
# 4.0

4-3. random 모듈

파이썬에서 제공하는 함수 중에 무작위로 숫자를 뽑아주는 random() 함수가 있다.
random() 함수는 random 모듈에 속하므로 코드를 다음과 같이 사용한다.

from random import *

print(random())
print(random())
print(random())

# 첫번째 출력 결과
# 0.5473008986159673
# 0.2274957276970535
# 0.7486482492854758

# 두번째 출력 결과
# 0.8200784083662084
# 0.7331168907981708
# 0.021269221448708908

출력 결과를 보면 모두 0이상 1미만의 수를 출력한다.
그리고 실행할 때마다 매번 다른 수가 출력되고 있는것을 알 수 있다.
이처럼 random() 함수는 0 이상 1미만에서 난수를 뽑는 기능을 한다.

위의 예제에서 뽑아낸 난수를 활용하기에는 숫자가 복잡해 보인다.
하지만 다음과 같이 조금만 변형하면 얼마든지 활용하기 좋은 난수를 뽑아낼 수 있다.

from random import *

print(random() * 10)
print(int(random() * 10))
print(int(random() * 10) + 1)

# 4.39049007145354
# 8
# 9

random() * 10은 0이상 1 미만이 아닌, 0이상 10미만에서 난수를 생성해준다.
int(random() * 10)는 0 이상 10 미만의 정수에서 난수를 생성한다.
int(random() * 10) + 1는 1 이상 11 미만의 정수에서 난수를 생성한다.

예를 들어 1부터 45까지 정수 범위안에서 로또 번호를 뽑으려고 한다면
int(random() * 45) + 1을 해주면 1 이상 46미만의 정수에서 난수를 생성한다.

하지만, 매번 이렇게 범위를 계산하려면 조금 피곤하고 복잡해질것이다.
고맙게도 random모듈에는 원하는 범위안에서 난수를 뽑을 수 있는 함수들이 있다.

  1. randrange(시작 숫자, 끝 숫자) : 주어진 범위 안에서 정수인 난수 생성(끝 숫자 미포함)
  2. randint(시작 숫자, 끝 숫자) : 주어진 범위 안에서 정수인 난수 생성(끝 숫자 포함)

둘의 차이점은 randint의 경우 끝 숫자를 포함한다. 즉, 끝 숫자 미만이 아닌 끝 숫자 이하의 범위를 뜻한다.

randrange(1, 46)과 randint(1, 45)의 범위가 같다,

  • randrange(1, 46) : 1이상 46미만의 범위에서 정수인 난수 생성
  • randint(1, 45) : 1이상 45미만의 범위에서 정수인 난수 생성

오답노트

num = 3
가
print(num)

'가'에 들어갈 코드로 알맞은것은?

  1. num += 2
  2. num *= 2
  3. num + 3
  4. num == 2

틀린이유 : 3 + 3이라고 생각해서 1번을 처음에 골랐음.(3을 두번 더한다고 생각해서...바보다)
하지만 다시 생각해보니 2번이였슴

 

실습문제

# 코딩 스터디 모임을 만들었다. 월 4번 모이는데, 3번은 온라인으로, 1번은 오프라인으로 모이기로 했다.
# 조건에 맞는 오프라인 모임 날자를 정하는 프로그램을 작성해보자

# 1. 날자를 무작위로 뽑는다.
# 2. 월별 일수가 다르므로 최소 일수인 28일 이내로 설정한다(28일까지만 선정)
# 3. 매월 1~3일은 스터디를 준비해야 하므로 제외한다.
# 4. 실행 결과는 다음과 같은 형태로 나와야 한다. 단, 날짜는 무작위이므로 책과 결과가 다를 수 있다.
# 오프라인 스터디 모임 날짜는 매월 00일로 선정됐습니다.

from random import *

date = randint(4, 28)
print("오프라인 스터디 모임 날짜는 매월 " + str(date) + "일로 선정됐습니다.")

 

셀프체크

cel = 30 # 섭씨 온도만 바꿔주면 된다.
fah = (cel * 9 / 5) + 32

print("섭씨 온도 : " + str(cel))
print("화씨 온도 : " + str(fah))