프로그래밍/Python

📔파워 유저를 위한 파이썬 Express 11. 내장함수, 람다식, 제너레이터, 모듈

카멜필름 2023. 7. 13. 16:43

11.1 내장 함수

import 문장으로 포함시킬 필요 없음

 

abs(): 절대값 반환

복소수인 경우 복소수의 크기 반환

 

all(): 시퀀스(리스트나 딕셔너리 등)를 받아서, 시퀀스의 모든 항목이 참이면 True를 반환, 그렇지 않으면 False

0이 아닌 값은 참으로 간주되고 0은 거짓인 것으로 간주됨

 

any(): 시퀀스 객체에 있는 한 개의 항목이라도 참인 경우 참을 반환. 그렇지 않으면 거짓 반환.

 

bin(): 정수의 이진 표현을 반환하는 데 사용됨

 

eval(): 전달된 수식을 구문 분석하고 프로그램 내에서 수식의 값 계산

파이썬 인터프리터 쉘에 정의된 전역 변수 사용 가능

exp=input("파이썬의 수식을 입력하시오: ")
>>>파이썬의 수식을 입력하시오: 2**10
eval(exp)
>>>1024
x=10
y==5
eval('x+y)
>>>15

 

sum(): 합계

 

len(): 길이 계산하여 반환

-문자열 길이

-리스트에 사용하면 리스트 안에 있는 항목의 개수 반환

-딕셔너리나 튜플에서도 항목의 개수 반환

 

list(): 리스트 생성하는 함수

 

map(): 반복 가능한 객체(리스트, 튜플 등)의 각 항목에 주어진 함수를 적용한 후 적용 결과 반환

여기에 list()를 적용하면 리슽트가 됨

def square(n):
	return n*n
    
mylist=[1,2,3,4,5]
result=list(map(square, mylist))
print(result)

>>>[1,4,9,16,25]

 

dir()함수

객체가 가지고 있는 변수나 함수를 보여줌

dir([1,2,3])

파이썬이 내부적으로 사용하는 함수는 앞에 __가 붙어 있음

dir함수는 어떤 객체에서 사용할 수 있는 함수들이 무엇인지를 알고 싶을 때 유용함

 

complex(real, imag) 함수

복소수 객체를 생성하는 함수

real+imag*j 형식의 복소수가 반환됨

complex(4, 2)
>>>(4+2j)

max(), min() 함수

가장 큰, 가장 작은 항목 반환

 

enumerate() 함수

시퀀스 객체를 입력 받아 열거형 (enumerate) 객체를 반환

열거형 객체는 첫 번째 요소로 번호, 두 번째 요소로 번호에 해당되는 값을 갖는 객체

리스트의 요소에 번호를 붙임

seasons=['Spring', 'Summer', 'Fall', 'Winter']

list(enumerate(seasons)))
>>>[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]

list(enumerate(seasons, start=1))
[(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]

 

fiilter() 함수

특정 조건을 만족하는 요소만을 뽑음

이 함수는 두 개의 인수를 취함

첫 번째: 조건을 나타내는 함수

두 번째: 반복 가능 객체

첫 번재 함수가 True값을 반환하는 요소들을 반환함

def myfilter(x):
	return x>3
    
result=filter(myfilter, (1,2,3,4,5,6))
print(list(result))

>>>[4,5,6]

 

zip() 함수

2개의 리스트를 하나로 묶어주는 함수

numbers=[1,2,3,4]
slist=['one', 'two', 'three', 'four']
list(zip(numbers, slist))
>>>[(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]

zip() 함수가 가장 많이 사용되는 부분은 for 반복문

names=["KIM", "LEE", "PARK"]
scores=[100, 99, 80]

for n, s in zip(names, scores):
	print(n, s)
    
>>>#결과
KIM 100
LEE 99
PARK 80

11.2 정렬과 탐색

sort(): 리스트를 정렬된 상태로 변경

sorted(): 반복 가능한 객체로부터 정렬된 리스트 생성

-sorted()는 기존의 리스트를 변경하는 것이 아니라 정렬된 새로운 리스트를 반환함, 기존 리스트는 전혀 변경되지 않음

sorted()="정렬된 새로운 리스트"

sorted([4,2,3,5,1])
>>>[1,2,3,4,5]

sort(): 리스트 자체를 변경함

일반적으로 sort()보다는 내장 함수인 sorted()가 더 편리함

myList=[4,2,3,5,1]
myList.sort()
myList
>>>[1,2,3,4,5]

sort()는 리스트만을 위한 메소드이지만 sorted() 함수는 어떤 반복가능한 객체도 받을 수 있음

sorted({3: 'D', '2: 'B', 5:  'B', 4: 'E', 1: 'A'})
>>>[1,2,3,4,5]

key 매개변수

정렬을 하다 보면 정렬에 사용되는 키를 개발자가 변경해주어야 하는 경우가 종종 있음

파이썬 2.4부터는 개발자가 key 매개변수로, 정렬을 하기 전에 각 요소에 대하여 호출되는 함수를 지정할 수 있음

 

sorted("The health know not of their health, but only the sick".split(),key=str.lower)

>>>
['but',
 'health',
 'health,',
 'know',
 'not',
 'of',
 'only',
 'sick',
 'The',
 'the',
 'their']

문자열을 받아서 split()로 단어들의 리스트로 변환한 후에 key를 문자열 개체의 lower() 함수로 지정함

단어들을 비교하기 전에, lower() 함수가 호출되어서 단어들을 소문자로 변경하게 됨

 

key 매개변수가 많이 사용되는 경우는 객체의 데이터 중에서 특정한 데이터를 기준으로 정렬하는 경우

ex) 학생들을 다음과 같이 튶ㄹ의 리스트로 나타낸 후에 학생들의 학번을 기준으로 정렬하는 코드를 작성하는 경우

students=[
    ('홍길동', 3.9, 20160303),
    ('김철수', 3.0, 20160302),
    ('최자영', 4.3, 20160301),
]
print(sorted(students, key=lambda student: student[2]))


>>>[('최자영', 4.3, 20160301), ('김철수', 3.0, 20160302), ('홍길동', 3.9, 20160303)]

lambda는 정렬에 필요한 함수를 나타낸 것으로 student 요소를 받아서 student[2]를 반환함

정렬의 기준: 학생들의 학번

 

 

오름차순 정렬과 내림차순 정렬

list.sort()와 내장함수 sorted()는 모두 reverse 매개변수를 받음

reverse 변수는 부울형으로 True이면 내림차순이 됨

위의 예제 내림차순으로 정렬하기

sorted(students, key=lambda student: student.number, reverse=True)

 

정렬의 안정성

파이썬 버전 2.2부터 정렬 안정성 보장됨

안정성: 동일한 키를 가지고 있는 레코드가 여러 개 있을 때 정렬 후에도 레코드들의 원래 순서가 유지되는 것을 의미함

data=[(1, 100), (1, 200), (2, 300), (2, 400)]
sorted(data, key=lambda item: item[0])

>>>[(1, 100), (1, 200), (2, 300), (2, 400)]

위의 레코드에서 (1, 100) 레코드와 (1, 200) 레코드가 정렬 후에도 위치가 변경되지 않음

대학교에서 신입생 선발할 때, 성적이 같으면 선착순으로 선발한다고 하면 반드시 정렬의 안정성이 보장되어야 함

 


11.3 람다식

 

이름이 없는 함수를 만드는 방법

lambda 키워드 사용

람다식은 여러 개의 매개 변수를 가질 수 있으나 반환값은 하나만 있어야 함

또 자신만의 이름 공간을 가지고 있음

Syntax: 람다식 정의
lambda 매개 변수들: 수식
lambda x, y: x+y;
x,y: 매개 변수, x+y: 함수의 몸체

무명 함수를 이용해 2개의 정수를 합하는 함수

f=lambda x, y: x+y
print("정수의 합: ", f(10,20))
print("정수의 합: ", f(20, 20))

기존 함수

def get_sum(x, y):
	return x+y
    
print("정수의 합: ", get_sum(10, 20))
print("정수의 합: ", get_sum(20, 20))

람다 함수에서는 return 키워드를 사용할 필요가 엇ㅂ음

항상 반환되는 수식만 써주면 됨

함수를 필요로 하는 곳에 람다 함수를 놓을 수 있으며 람다 함수를 반드시 변수에 할당할 필요도 없음

 

람다식과 콜백 함수

람다 함수는 GUI프로그램에서 이벤트를 처리하는 콜백 함수(callback handler)에서 ㅁ낳이 사용됨

이벤트가 생성되면 호출되는 함수를 전달할 때 람다식을 사용함

from tkinter import *

window=Tk()

btn1=Button(window, text="1 출력", command=lambda:print(1, "버튼이 클릭"))
btn1.pack(side=LEFT)
btn2=Button(window, text="2 출력", command=lambda:print(2, "버튼이 클릭"))
btn2.pack(side=LEFT)

quitBtn=Button(window, text="QUIT", fg="red", command=quit)
quitBtn.pack(side=LEFT)

mainloop()

map() 함수와 람다식

람다식은 내장 함수와도 함께 사용됨

list_a=[1,2,3,4,5]
f=lambda x: 2*x
result=map(f, list_a)
print(list(result))

filter() 함수와 람다식

filter(): 어떤 조건을 주어서 리스트 요소들을 필터링할 때 사용됨

list_a=[1,2,3,4,5,6]
result=filter(lambda x: x%2==0, list_a)
print(list(result))

정렬할 때, 정렬의 기준이 되는 키를 지정할 때도 람다식이 많이 사용됨

data=[(3, 100), (1, 200), (7, 300), (6, 400)]
sorted(data, key=lambda item: item[0])
print(data)

 

reduce() 함수와 람다식

reduce(func, seq) 함수는 func() 함수를 시퀀스 seq에 연속적으로 적용하여 단일 값을 반환함

하나의 요소만 남을 때까지 seq 반복

import functools
result=functools.reduce(lambda x,y:x+y, [1,2,3,4])
print(result)

 

 

11.4 이터레이터와 제너레이터

이터레이터

🍋이터레이터(iterator): 반복 가능한 객체

파이썬에는 for 루프와 함께 사용할 수 있는 여러 종류의 반복 가능한 객체(iterable)가 있으며 이들 객체는 이터레이터라고 불림

이터레이션(iteration): 반복

 

우리는 for 루프를 이용해 리스트 아느이 요소들에 대해 반복할 수 있었음

for i in [1,2,3,4]:
	print(i, end=" ")
   
>>>1 2 3 4

또 문자열의 각 문자에 대해서도 반복할 수 있었으며 딕셔너리, 파일도 마찬가지

for c in "python":
	print(c, end=" ")
    
>> p y t h o n

 

객체가 반복가능한 객체가 되려면 다음과 같은 2개의 메소드를 구현해야 함

✏__iter__(): 반복가능한 객체 자신을 반환함

✏__next__(): 다음 반복을 위한 값을 반환함. 만약 더 이상의 값이 없으면 StopIteration 예외를 발생하면 됨

 

MyCounter 클래스를 이터레이터 클래스로 정의

#이 프로그램은 이터레이터를 이용하여 카운터를 구현함

class MyCounter(object):
  #생성자 메소드를 정의함
  def __init__(self, low, high):
    self.current=low
    self.high=high
  #이터레이터 객체로서 자신을 반환
  def __iter__(self):
    return self
  
  def __next__(self):
    #current가 high 보다 크면 StopIteration 예외를 발생함
    #current가 high보다 작으면 다음 값을 반환함
    if self.current>self.high:
      raise StopIteration
    else:
      self.current+=1
      return self.current-1
c=MyCounter(1, 10)
for i in c:
  print(i, end=' ')
  
  
  >>1 2 3 4 5 6 7 8 9 10

 

제너레이터

🍋제너레이터(generators): 키워드 yield를 사용하여 함수로부터 반복 가능한 객체를 생성하는 하나의 방법

def myGenerator():
  yield 'first'
  yield 'second'
  yield 'third'

정의된 제너레이터를 for 루프에서 이터레이터로 사용 가능

for word in myGenerator():
  print(word)

앞의 이터레이터클래스를 이용하여 반복 가능한 객체를 생성하는 것이고 제너레이터함수를 이용하여 반복 가능한 객체를 생성하는 것

 

MyCounter클래스와 유사한 제너레이터 함수 정의하기

def MyCounterGen(low, high):
  while low<=high:
    yield low
    low+=1

for i in MyCounterGen(1, 10):
  print(i, end=' ')
  
>>1 2 3 4 5 6 7 8 9 10

 

11.5 연산자 오버로딩

🍋연산자 오버로딩(operator overloading): 연산자를 메소드로 정의하는 것

연산자 오버로딩을 이용하면 여러 가지 연산자들을 클래스의 메소드로 연결할 수 있음

ex) +연산자에 대응되는 메소드는 __add__(self, other)이고 ==연산자에 대응되는 메소드는 __eq__(self, other)

s1="Impossible"
s2="Dream"
s3=s1.__add__(s2)
print(s3)

>>ImpossibleDream

클래스에서 연산자 정의하기

클래스에서도 기본 연산자들을 우리 마음대로 재정의해서 사용할 수 있음

ex) 2차원 공간에서 한 점을 클래스로 정의했다고 가정

점과 점을 + 연산으로 합할 수 있으면 편리함

class Point:
  def __init__(self, x=0, y=0):
    self.x=x
    self.y=y

p1=Point(1,2)
p2=Point(3,4)
print(p1+p2)

 

기본적으로 Point 클래스 객체에 대해서는 + 연산이 정의되지 않음

하지만 만약 __add__(self, other)를 정의한다면 Point 클래스에 대해서도 + 연산자 적용 가능

class Point:
  def __init__(self, x=0, y=0):
    self.x=x
    self.y=y

  def __add__(self, other):
    x=self.x+other.x
    y=self.y+other.y
    return Point(x, y)
    #포인트 객체 끼리의 +연산 정의
p1=Point(1,2)
p2=Point(3,4)
print(p1+p2)


>><__main__.Point object at 0x7b8f21f9a770>

객체 주소가 출력됨

이것도 __str__()를 이용해서 출력 형식 변경 가능

class Point:
...
	def __str__(self):
    	return 'Point('+str(self.x)+', '+str(self.y)+')'
        
        #Point 객체를 문자열로 표현하여 반환함

 

 

11.6 모듈이란?

🍋모듈(module): 함수나 변수 또는 클래스들을 모아 놓은 파일

모듈은 파이썬의 문장들이 저장된 파일

파이썬 프로그램이 길어지면, 유지 보수를 쉽게 하기 위해 여러 개의 파일로 분할 할 수 있음

파일을 사용하면 한 번 작성한 함수를 복사하지 않고 여러 프로그램에서 사용 가능

 

모듈 작성하기

#피보나치 수열 모듈 fibo.py

def fib(n): #피보나치 수열 출력
  a, b=0,1
  while b<n:
    print(b, end=' ')
    a, b=b, a+b
  print()

def fib2(n): #피보나치 수열을 리스트로 반환
  result=[]
  a,b=0,1
  while b<n:
    result.append(b)
    a,b=b,a+b
  return result

모듈의 이름은 __name__변수로 알 수 있음

fibo.py 모듈에 들어 있는 모든 정의는 다른 모듈로 import 될 수 있음

fibo.py 사용하기 위해선

import fibo

import: 다른 사람이 작성한 파이썬 모듈을 사용할 수 있게 해주는 명령어

import문장을 실행한다고 해서 파이썬 인터프리터가 모듈 안의 함수들을 읽어 들여서 현재의 심볼 테이블에 저장하지는 않음

단지 모듈의 이름인 fibo만 심볼 테이블에 저장

모듈 안 함수 사용하기

fibo.fib(1000)
fibo.fib2(100)

만약 fibo.fib()와 같이 함수를 사용할 때마다 모듈의 이름을 적어주는 것이 귀찮다면

"from 모듈 import 함수" 문장을 사용해도 됨

이 방법을 사용하면 모듈 이름없이 해당 모듈의 함수를 사용할 수 있음

from fibo import fib
fib(1000)

*문자를 사용하는 방법

🍋*: 모듈 안의 "모든 것"

from fibo import *
fib(500)

"from fibo import *" 문장이 실행되면 모듈 아느이 모든 함수들이 심볼 테이블에 저장됨

-단점: 모듈의 모든 함수를 가져오는 것이 아니라 사용자가 정의한 함수를 가릴 수도 있음

 

⛔경고

효율성의 관점에서 각 모듈은 인터프리터 세션에서 한번만 포함됨
따라서 만약 모듈 작성자가 모듈을 변경한다면 인터프리터를 다시 실행해야 함
만약 변경된 모듈이 하나뿐이면 importlib.reload()을 사용해도 됨

 

모듈의 별칭

별칭 사용 가능

import mymodule as lib
...
lib.func(100)

위의 코드에서 lib가 모듈 mymodule의 별칭이 됨

따라서 mymodule 대신에 lib 사용 가능

 

모듈 실행하기

명령어 프롬프트 창에서 파이썬 모듈 실행하기

c> python fibo.py <arguments>

모듈의 코드는 차례대로 실행되고 __name__변수는 "__main__"으로 설정됨

따라서 모듈의 끝에 다음과 같은 코드를 덧붙이면 명령어 프롬프트에서 모듈 실행 가능

...
if __name__=="__main__":
	import sys
    fib(int(sys.argv[1]))

현재 작업 디렉토리에서 "C>python fibo.py"처럼 직접 이 파일을 실행시켰을 때는 __name__=="__main__"이 참이 되어 if 문 안의 문장들이 실행됨

C> python fibo.py 50
1 1 2 3 5 8 13 21 34

만약 단순히 파이썬 인터프리터에서 이 모듈을 포함시키면 __name__=="__main__"이 거짓이 되어 if 문 안의 문장들이 실행되지 않음

import fibo

따라서 이 방법은 파이썬 모듈을 만든 후에 모듈을 간단하게 테스트하기 위해 많이 사용함

 

 

모듈 탐색 경로

개발자가 fibo.py 모듈을 포함하라고 하면 인터프리터는 먼저 현재 디렉토리에 이러한 이름을 가지는 모듈이 있는지 검사함

만약 발견되지 않으면 sys.path 변수에 저장된 디렉토리에서 fibo.py를 찾음

sys.path는 아래와 같은 위치로 초기화됨

▶입력 스크립트가 있는 디렉토리(파일이 지정되지 않으면 현재 디렉토리)

▶PYTHONPATH 환경변수

▶설치에 의존하는 디폴트값

 

초기화 이후로는 파이썬 프로그램이 sys.path 변경 가능

현재 실행되는 스크립트가 있는 디렉토리는 탐색 경로의 맨 처음에 놓여짐

'표준 라이브러리 경로보다 먼저 탐색된다': 우리가 만든 모듈이 표준 라이브러리 모듈의 모듈을 대체할 수 있음

 

 

11.7 유용한 모듈

copy 모듈

▶얇은 복사(shallow copy): 객체의 참조값만 복사되고 객체 자체는 복사되지 않음

▶깊은 복사(deep copy): 객체까지 복사됨

 

리스트와 같은 객체를 복사할 때 단순히 리스트를 참조하는 변수만 하나 더 만든다면 얇은 복사가 됨

 

깊은 복사: copy 모듈의 deepcopy() 함수 사용

 

▶deepcopy(object)=>object는 주어진 객체의 "deep" 복사본을 생성함. deep 의미는 객체 자체가 복사된다는 의미

import copy
colors=["red", "blue", "green"]
clone=copy.deepcopy(colors)

clone[0]="white"
print(colors)
print(clone)


>>>['red', 'blue', 'green']
['white', 'blue', 'green']

 

random모듈

random 모듈: 난수를 발생할 때 사용하는 모듈

난수는 다양한 용도로 사용됨

random 모듈에서는 난수를 발생하는 다양한 함수들이 지원됨

▶randint(): 정수 범위의 난수 생성

randint(1,6)와 같이 정수 구간을 인수로 줄 수 있음

randint(1,6): 1,2,3,4,5,6 중의 하나를 랜덤하게 생성함

import random
print(random.randint(1,6))

▶random(): 0에서 1 사이의 난수 반환

만약 더 큰수를 원한다면 원하는 범위를 곱하면 됨

random.random()*100

▶choice(): 주어진 시퀀스의 항목을 랜덤하게 반환함

다음의 코드에서는 "red", "green", "blue" 중에서 하나를 랜덤하게 반환함

myList=["red", "green", "blue"]
random.choice(myList)

▶shuffle(): 리스트의 항목을 랜덤하게 섞음

myList=[[x] for x in range(10)]
random.shuffle(myList)
myList


>>[[3], [2], [0], [4], [8], [7], [6], [1], [9], [5]]

▶randrange(start, stop[, step]): range(start, stop, step) 구간으로부터 랜덤하게 요소 생성

random.randrange(0, 101, 3)

 

sys 모듈

🍋sys 모듈: 파이썬 인터프리터에 대한 다양한 정보를 제공하는 모듈

import sys
sys.prefix


>>/usr #파이썬이 설치된 경로

sys.executable

인터프리터를 종료시키려면 sys.exit() 호출

IDLE에서는 작동하지 않지만 파일로 실행시킬 때는 인터프리터를 종료시킴

 

모듈을 참조할 때 사용하는 경로를 보려면 sys.path 입력

sys.path

설치된 파이썬의 버전을 보려면 sys.version 입력

sys.version

 

time 모듈

🍋time 모듈: 시간을 얻어 와서 다양한 형식으로 표시하는 함수들을 가짐

컴퓨터에서 사용하는 시간의 형식은 다양함

import time
time.time()

time() 함수를 호출하면 이상한 숫자가 나옴

이는 컴퓨터에서 시간을 측정하는 하나의 방법으로 1970년 1월 1일 자정 이후 지금까지 흘러온 절대 시간을 초단위로 출력한 것

유용함-> 어떤 파이썬 프로그램이 실행되는데 걸리는 시간을 time()함수를 이용해서 측정 가능

start=time.time()
...
end=time.time()
print(end-start)

피보나치 수열을 계산하는데 시간이 얼마나 걸리는지 측정

import time
def fib(n):
  a,b=0,1
  while b<n:
    print(b, end=' ')
    a,b=b,a+b
  print()

start=time.time()
fib(1000)
end=time.time()
print(end-start)


>>>
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 
0.0024209022521972656

fib() 함수를 호출하기 전에 시간을 측정하여 start 변수에 저장

fib() 호출이 종료된 후에 다시 시간을 측정하여 end 변수에 저장

end에서 start를 빼면 실행 시간이 됨

 

▶asctime(): 현재 날짜와 시간을 문자열 형태로 표시

time.asctime()
>>>Thu Jul 13 07:36:24 2023

만약 우리가 특정 날짜를 asctime()에 주고 이것을 출력하려면 특정 날짜를 다음과 같이 튜플 형태로 생성해야 함

t=(2016, 4, 29, 12, 10, 30, 5, 0 , 0)
time.asctime(t)

>>Sat Apr 29 12:10:30 2016

튜플의 값들은 (연도, 월, 일, 시간, 분, 초, 요일, 0, 0) 형태로 만들면 됨

요일은 0이 월요일, 1은 화요일 ... 6은 일요일

 

time 모듈에 있는 sleep()함수는 현재 동작 중인 프로세스를 주어진 초만큼 정지시킴

따라서 현재의 프로그램을 약간 천천히 실행하고자 할 때 사용

ex) 우주선을 발사할 때 사용할 수 있는 스크립트 작성

import time
for i in range(10, 0, -1):
  print(i, end=" ")
  time.sleep(1)
print("발사!")


>>10 9 8 7 6 5 4 3 2 1 발사!

 

calendar 모듈

여러 가지 형태의 달력 출력

ex) 2016년 8월 달력 출력 코드

import calendar

cal=calendar.month(2016, 8)
print(cal)


>>
    August 2016
Mo Tu We Th Fr Sa Su
 1  2  3  4  5  6  7
 8  9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31