Date : 2023-07-11

Topic : Lambda 표현식, closure, 파일 입출력


Note

람다 표현식(Lambda Expression)

: lambda에 매개변수를 지정:(콜론) 뒤에 반환값(return value)으로 사용할 식을 지정

lambda 매개변수들: 식

  • 람다 표현식으로 만들면 함수 객체가 나오는데, 이 상태로는 함수 호출X
  • 람다 표현식은 이름이 없는 함수를 만들기 때문임. (익명 함수라고도 함. Anonymous function)
# 함수 정의
def plus_ten(x):
    return x+10

plus_ten(1)
  • lambda로 만든 익명 함수를 호출하려면 다음과 같이 람다 표현식을 변수에 할당
# 위 함수를 람다 표현식으로
plus_ten=lambda x: x+10
plus_ten(1)
  • 람다 표현식은 변수에 할당하지 않고 람다 표현식 자체를 바로 호출할 수 있음.
    • 람다 표현식을 ()(괄호)로 묶은 뒤, 다시 ()를 붙이고 인수를 넣어서 호출

(lambda 매개변수들: 식)(인수들)

(lambda x: x + 10)(1)	# 11
  • 람다 표현식 안에서는 변수를 만들 수 없다.
    • 변수 없이 식 한 줄로 표현할 수 있어야 함.
    • 변수가 필요한 코드일 경우 def로 함수를 작성하는 것이 좋음.
(lambda x:y=10; x+y)(1)
>>> syntaxerror: invalid syntax
  • 람다 표현식 바깥에 있는 변수는 사용할 수 있음.
    • 매개변수 x와 람다 표현식 바깥에 있는 y를 더해서 반환.
y=10
(lambda x: x+y)(1)	# 11

 

  • 람다 표현식을 인수로 사용하기
# 1.이렇게 정의된 함수 plus_ten을
def plus_ten(x):
    return x+10

list(map(plus_ten, [1,2,3]))	# [11,12,13]
# 2.plus_ten 대신 람다 표현식을 직접 대입
list(map(lambda x:x+10, [1,2,3]))	# [11,12,13]

 

  • 람다 표현식에 조건부 표현식 사용하기
    • if, else 사용 시 :(콜론) 사용X
    • elif 사용X - 조건식을 연속으로 사용해줘야 함

lambda 매개변수들: 식1 if 조건식 else 식2

True면 if 조건식 실행, 아닐 경우 else 식2 실행

lambda 매개변수들: 식1 if 조건식1 else 식2 if 조건식2 else 식3

                   elif 대신 조건식을 연속으로 ( ↑ elif와 같은 기능 )

  • 그러나 어렵지 않은 코드를 lambda로 표현하여 복잡하고 가독성이 떨어진다면 def 함수 권장

map, filter, reduce

  • map에 여러 객체 넣기 : 람다 표현식에 매개변수에 개수에 맞게 반복 가능한 객체도 콤마로 구분해서 넣어주면 됨.
a=[1,2,3,4,5,6,7,8,9,10]
list(map(lambda x: str(x) if x % 3 == 0 else x, a))	# 3의 배수를 문자열로 출력, 아니면 그대로x
# [1,2,'3',4,5,'6',7,8,'9',10]
a=[1,2,3,4,5]			# 2.반복 가능한 객체도 콤마로 구분해서 넣어줌
b=[2,4,6,8,10]
list(map(lambda x,y: x*y,a,b))	# 1.표현식의 매개변수 개수(x,y 2개)에 맞게
# [2, 8, 18, 32, 50]
  • filter 사용하기 : 반복 가능 객체에서 특정 조건에 맞는 요소만 가져오는데, filter에 지정한 함수의 반환값이 True일 때만 해당 요소를 가져옴

filter(함수, 반복 가능한 객체)

# 1.함수 f를
def f(x):
    return x>5 and x<10	# 5보다 크고 10보다 작은 x

a=[8,3,2,10,15,7,1,9,0,11]
list(filter(f,a))	# [8,7,9]	# 참인 요소만 출력
# 2.람다 표현식으로 만들어서 filter에 넣기
list(filter(lambda x: x>5 and x<10, a))	# [8,7,9]
  • reduce : 반복 가능한 객체의 각 요소를 지정된 함수로 처리한 뒤 이전 결과와 누적해서 반환하는 함수

reduce(함수, 반복 가능한 객체)

def f(x, y):
	return x + y

a = [1, 2, 3, 4, 5]
from functools import reduce
reduce(f, a)	# 15
# 저장된 요소를 순서대로 더한 뒤 누적된 결과를 반환
a=[1,2,3,4,5]
from functools import reduce	# 내장함수X, functools에서 reduce를 불러와야 함
reduce(lambda x,y: x+y, a)	# 지정된 함수 x+y를 a의 요소로 누적

※ 그러나 reduce는 코드가 조금만 복잡해져도 가독성이 안좋아지기 때문에, 반복문으로 처리할 수 있는 경우라면 for, while문으로 처리하는 것이 좋다. ↓

#의미하는 바를 한 눈에 알아볼 수 있다.
a = [1, 2, 3, 4, 5]
x = a[0]
for i in range(len(a) - 1):	# len(a)=5이므로 range(4)
     x = x + a[i + 1]		# a[0] + (a[1]+a[2]+a[3]+a[4])

x	# 15

클로저 (closure) 사용하기

  • 변수 사용 범위
    • 전역 변수(global variable): 함수 포함하여 스크립트 전체에서 접근할 수 있는 변수
    • 전역 범위(global scope): 전역 변수에 접근할 수 있는 범위
x=10    	# 전역 변수
def foo():
    print(x)    # 전역 변수 출력	## 10

foo()
print(x)    	# 전역 변수 출력	## 10
  • 지역 변수(local variable): 변수를 만든 함수 안에서만 접근 가능(함수 바깥에서 접근X)
  • 지역 범위(local scope): 지역 변수를 접근할 수 있는 범위
def foo():
	x=10	# foo의 지역 변수
    print(x)    # foo의 지역 변수 출력

foo()
print(x)    	# 에러. foo의 지역 변수 출력 불가
x=10    	# 전역 변수
def foo():
    x=20    	# x는 foo의 지역 변수
    print(x)    # foo의 지역 변수 출력

foo()
print(x)    	# 전역 변수 출력

'''op
20
10
'''

# 이때 지역 변수x와 전역 변수x는 서로 다른 x
  • global 키워드 : 함수 안에서 전역 변수의 값을 변경하려면 global 전역변수 사용.
    • 함수 안에서 변수를 global로 지정하면 전역 변수를 사용
    • 전역 변수가 없을 때, 함수 안에서 global을 사용하면 해당 변수는 전역 변수
x=10    	# 전역 변수
def foo():
    global x    # 전역 변수x를 사용하겠다고 설정
    x=20    	# x는 전역 변수
    print(x)    # 전역 변수 출력

foo()
print(x)    	# 전역 변수 출력

'''op
20
20
'''
# 전역변수x가 없는 상태
def foo():
    global x    # x를 전역 변수로 만듦
    x=20    	# x는 전역 변수
    print(x)    # 전역 변수 출력

foo()
print(x)    	# 전역 변수 출력

 

  • 함수 안에서 함수 만들기
def 함수이름1():
	코드
    def 함수이름2():
    	코드
# 동작 순서chk
# print_hello > print_message 순으로 실행
def print_hello():		#2
    hello='Hello, world!'	#3
    def print_message():	#5
        print(hello)		#6
    print_message()		#4

print_hello()			#1(함수 호출), 7

 

  • 지역 변수 변경하기
# 안쪽 함수B에서 바깥쪽 함수A의 지역 변수x를 변경해보기
def A():
    x=10    	# A의 지역 변수x
    def B():
        x=20    # x에 20 할당(B의 지역 변수x)

    B()
    print(x)    # A의 지역 변수x 출력

A()		# 10
  • 현재 함수 바깥쪽에 있는 지역 변수의 값을 변경하려면 nonlocal 키워드 사용
    • nonlocal 지역변수
    • nonlocal: 현재 함수의 지역 변수가 아니라는 뜻(바깥쪽 함수의 지역 함수 사용)
      - 현재 함수의 바깥쪽에 있는 지역 변수를 찾을 때 가장 가까운 함수부터 먼저 찾는다.
def A():
    x=10            # A의 지역 변수x
    def B():
        nonlocal x  # 현재 함수 바깥쪽에 있는 지역 변수 사용
        x=20        # A의 지역 변수 x에 20 할당

    B()
    print(x)        # A의 지역 변수x 출력

A()			# 20
# 실행 순서 이해하고 주석 달기
def A():
    x=10
    y=100
    def B():
        x=20
        def C():
            nonlocal x	# 가장 가까운 함수의 변수 x 사용 (x=20)
            nonlocal y	# 가장 가까운 함수의 변수 y 사용 (y=100)
            x=x+30
            y=y+300
            print(x)
            print(y)
        C()
    B()

A()

# 50	## print(x)
# 400	## print(y)
  • global로 전역 변수 사용하기 : 함수가 몇 단계든 상관 없이 global 키워드를 사용하면 무조건 전역 변수를 사용하게 됨

- 파이썬에서 global을 제공하지만 함수에서 값을 주고받을 때는 매개변수와 반환값을 사용하는 것이 좋다. 특히 전역 변수는 코드가 복잡해졌을 때 변수의 값을 어디서 바꾸는지 알기가 힘드므로 전역 변수는 가급적이면 사용하지 않는 것을 권장

x = 1
def A():
    x = 10
    def B():
        x = 20
        def C():
            global x    # 전역 변수 x = 1을 사용
            x = x + 30
            print(x)
        C()
    B()
 
A()	# 31

 

  • 클로저(closure) 사용하기 : 함수를 둘러싼 환경(지역 변수, 코드 등)을 계속 유지하다가, 함수를 호출할 때 다시 꺼내서 사용하는 함수
    • 프로그램의 흐름을 변수에 저장할 수 있음
      • 지역 변수와 코드를 묶어서 사용하고 싶을 때 활용
      • 클로저에 속한 지역 변수는 바깥에서 직접 접근할 수 없으므로 데이터를 숨기고 싶을 때 활용
    • 함수를 반환할 때는 함수 이름만 반환해야 하며 ()(괄호)를 붙이면 안됨 (↓return mul_add)
# 함수 바깥쪽 지역 변수 a,b를 사용하여 a*x+b를 계산하는 함수 mul_add를 만든 뒤
# 함수 mul_add 자체를 반환함
def calc():
    a=3
    b=5
    def mul_add(x):
        return a*x+b    # 함수 바깥쪽 지역 변수 a,b를 사용하여 계산
    return mul_add	# mul_add 함수를 반환

c=calc()		# calc() 함수 호출 후 반환값을 c에 저장
print(c(1),c(2),c(3),c(4),c(5))	# 8 11 14 17 20

c에 저장된 함수가 클로저

  • lambda로 클로저 만들기 ( 함께 사용하는 경우 多 )
def calc():
    a=3
    b=5
    return lambda x: a*x+b  # mul_add 함수를 람다 표현식으로 변경 후 그 자체를 반환
 
c=calc()
print(c(1),c(2),c(3),c(4),c(5))

파일의 입출력 과정

표준입력장치(키보드 등) input() → print() 표준출력장치(모니터)

이 둘을 합쳐서 콘솔(Console)

 

  • read() / readline() / readlines()는 파일 내용을 읽음
  • write() / writelines()는 파일 내용을 쓰기

 

파일 입출력 기본 과정

  1. file open
    • open() 함수에서 파일명을 지정하고 읽기인지, 쓰기인지 지정
    • open() 함수의 마지막 매개변수를 모드(Mode)라고 함
      • 읽기용: 변수명=open("파일명", "r")
      • 쓰기용: 변수명=open("파일명", "w")
  2. file read & write
  3. file close
# 파일 경로 찾아서 열기
#inFp=open("C:\Users\bb2_b\data1.txt", "r", encoding="utf-8")
inFp=open("data1.txt", "r", encoding="utf-8")
inStr=inFp.readline()
print(inStr, end="")
inStr=inFp.readline()
print(inStr, end="")
inStr=inFp.readline()
print(inStr, end="")
inStr=inFp.readline()
print(inStr, end="")
inFp.close()

'''op: 저장된 txt파일 내용이 입력됨
박우정
파이썬
python
'''
inFp=None
inStr=""
inFp=open("data1.txt", "r", encoding="utf-8")
while True:			# 무한 루프를 통해 텍스트가 몇 줄인지 몰라도 사용 가능
    inStr=inFp.readline()	# 한 줄 읽고 다시 루프
    if inStr=="":		# 더 이상 읽을 내용이 없으면(EOF) break
        break
    print(inStr, end="")

inFp.close()
inFp=None
inList=[]

inFp=open("data1.txt", "r", encoding="utf-8")
inList=inFp.readlines()
print(inList)
inFp.close()
# ['박우정\n', '파이썬\n', 'python']

< 실습 >

  • 파일명으로 파일 읽기
inFp=None
inList=[]
inStr=""
strName=input("file name: ")	# 확장자까지 입력! data1.txt
inFp=open(strName, "r", encoding="utf-8")
inList=inFp.readlines()
for inStr in inList:
    print(inStr, end="")
    
inFp.close()

'''op:
file name: data1.txt
박우정
파이썬
python
'''
  • 파일에 출력해보기
outFp=None
outStr=""

outFp=open("data1.txt", "w", encoding="utf-8")

while True:
    outStr=input("내용 입력: ")
    if outStr != "":			# 공백이 아닌 내용이 입력되면 써짐
        outFp.write(outStr+'\n')
    else:				# 공백+'\n' 시 종료
        break
        
outFp.close()
print("--- 정상적으로 파일에 써졌음 ---")	# data1.txt 파일을 열어보면 입력한 내용이 출력됨

Tkinter 라이브러리

: GUI 프로그램을 만들기 위해 -

  • 메인 창(Tk 객체) 생성
  • 위젯 생성하고 창에 배치
  • 메인 루프 실행

 

  • Tkinter 라이브러리 맛보기 - 코랩 안되고 내 GUI를 사용하는 프로그램 사용해야함!! (ex:주피터 노트북)
import tkinter as tk
root=tk.Tk()

lbl=tk.Label(root, text="Educoding", underline=3)
lbl.pack()

txt=tk.Entry(root)
txt.pack()

btn=tk.Button(root, text="OK", activebackground="red", width=5)
btn.pack()

root.mainloop()

이렇게 창이 생성된다.

  • 버튼 만들기
# coding: uft-8

# Tkinter 라이브러리 임포트
import tkinter as tk
# tk 객체 인스턴스 생성
root=tk.Tk()

def func():
    print('Pushed')

txt=tk.Entry(root)
txt.pack()

# 버튼 생성
btn=tk.Button(root, text="Push!", command=func)
# 버튼 배치
btn.pack()

print("실행 준비")	# 코드를 실행하면 출력창에 "실행 준비"가 프린트 되고
# 루트 표시
root.mainloop()		# 'Push!' 버튼을 누르면 'Pushed'가 출력된다.
print("실행 종료")	# 창을 닫으면 실행 종료가 뜬다.

'''op:
실행 준비	# 코드 실행
Pushed		# 버튼을 다섯 번 눌렀다.
Pushed
Pushed
Pushed
Pushed
실행 완료	# 창 닫음
'''

실행 모습

 

  • if 조건문으로 버튼을 스위치처럼 사용하기 ( 클릭할 때마다 표시된 메시지가 반복해서 달라진다.)
# coding: uft-8

# Tkinter 라이브러리 임포트
import tkinter as tk
# tk 객체 인스턴스 생성
root=tk.Tk()

bAct=False
print(type(bAct))	# boolean인지 타입 체크

# 버튼 눌렀을 때 처리
def func():
    global bAct
    # Label 표시 변경
    if bAct:		# 조건문 설정으로 switch 역할
        label.config(text='Apple')
    else:
        label.config(text='Orange')
    bAct=not(bAct)

# 레이블 생성
label=tk.Label(root, text="Apple")

# 레이블 배치
label.pack()

# 버튼 생성
btn=tk.Button(root, text="Push!", command=func)	# command
# 버튼 배치
btn.pack()

print("실행 준비")
# 루트 표시
root.mainloop()
print("실행 완료")

버튼을 누르면
label 표시가 변경된다(Apple -> Orange)

  • 버튼을 누른 다음 특정 동작을 하면 표시가 돌아오도록 프로그램을 변경
# coding: uft-8

# Tkinter 라이브러리 임포트
import tkinter as tk
# tk 객체 인스턴스 생성
root=tk.Tk()

# 버튼을 눌렀을 때 처리
def func():
    # Label 표시 변경
    label.config(text="Pushed")

# 마우스 커서가 버튼을 벗어났을 때 이벤트 추가
def func_event(ev):
    # Label 표시 변경
    label.config(text="Pushed")

# 레이블 생성
label=tk.Label(root, text="Push Button")

# 레이블 배치
label.pack()

# 버튼 생성
btn=tk.Button(root, text="Push!", command=func) #command

# 버튼 배치
btn.pack()

# 마우스 커서가 버튼을 벗어났을 때 이벤트 추가
btn.bind('<Leave>', func_event)

print("실행 준비")
# 루트 표시
root.mainloop()
print("실행 완료")
  • 버튼 만들기 - event object
import tkinter as tk
root=tk.Tk()
def func():
    label.config(text='Pushed')
    
def func_event_click(ev):
    disp=str(ev.x)+'/'+str(ev.y)
    label.config(text=disp)
    
label=tk.Label(root, text="Push Button")
label.pack()
button=tk.Button(root, text='Push', command=func)
button.pack()

button.bind('<Button-1>', func_event_click)

root.mainloop()
  • 라디오 버튼 만들기
# radio button
import tkinter as tk
def Action1():
    lbl.config(text='Option 1')
def Action2():
    lbl.config(text='Option 2')

root=tk.Tk()
    
lbl=tk.Label(root, text="EduCoding", underline=3)
lbl.pack()

rbvar=""
rb1=tk.Radiobutton(root, text='Option 1', variable=rbvar, value='a', indicatoron=0, command=Action1)
rb1.pack()
rb2=tk.Radiobutton(root, text='Option 2', variable=rbvar, value='b', indicatoron=0, command=Action2)
rb2.pack()
# indicatoron이 0이면 버튼 형태, 1이면 단추 형태 (형식은 라디오버튼이다)

root.mainloop()

+ Recent posts