| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
- 객체지향
- RDBMS
- 힙정렬
- 에이전트
- UMAP
- TTS
- 소프트웨어 개발
- 알고리즘
- LangGraph
- 캐글
- 정보처리기사
- python 기초
- CNN
- 데이터 시각화
- 데이터엔지니어
- 머신러닝
- CLIP
- 트랜스포머
- 자연어처리
- 랭그래프
- python기초
- dementional reduction
- ASR
- Python
- RNN
- 딥러닝
- Transformer
- SQL
- 기초
- 생성형 인공지능
- Today
- Total
수달이네 기술 블로그
6. 함수2(Call-by-value,reference, 람다식, 튜플, 모듈 등...) 본문
🔍Call-by-value(pass-by-value)
이전 글에서 말했던 call by value와 call by reference를 좀더 자세하게 살펴보려 한다.
def modify(n):
print("함수 내 연산 전 주소", id(n))
n=n+1
print("함수 내 연산 후 주소", id(n))
k = 10
print("k=",k) #10
print("메인 내 연산 전 주소", id(k))
modify(k)
print("메인 내 연산 후 주소", id(k))
print("k=",k) #10
# k= 10
# 메인 내 연산 전 주소 3116073445968
# 함수 내 연산 전 주소 3116073445968
# 함수 내 연산 후 주소 3116073446000
# 메인 내 연산 후 주소 3116073445968
# k= 10
위 코드에서 보면 위와 아래의 print가 동일하게 10이 출력되는 이유를 살펴보면
주소값을 보면 알 수 있다.
그 이유는 함수 내에서 변환이 일어나기 전엔 main내에서 매개변수로 참조된 주소값이 동일했다. 그러나,
값이 변경되려 하자 새로운 주소값으로 이전된 것을 볼 수 있으며,
해당 주소값을 리턴하지 않았기 때문에 해당 주소값은 그대로 찾을 수 없게 되고, 원래 주소의 원래 값만 출력된다.
문자열도 마찬가지이며 함수가 아니더라도 확인할 수 있는데,
msg = "Happy Birthday"
print(id(msg))
msg += "To You"
print(id(msg))
#1341205684656
#1341205984160
위에서 보면 원래 주소값에서 연산을 가하자 새로운 주소값으로 바뀐 것을 볼 수 있다.
위의 모든 이유는 정수, 문자열, 튜플 등은 변경할 수 없는 객체(immutable object)이다.
따라서 해당 객체는 객체단위에서 변경하는 것이 불가하므로 새로운 주소값이 전달된다.
이것을 call-by-value라 한다.
🔍Call-by-reference(call by objective)
위와 반대로 변경할 수 있는 객체(mutable object)들이 존재하는데 그중 하나가 list객체이다.
def modify2(li):
print("함수 내 연산 전 주소", id(li))
li += [100, 200]
print("함수 내 연산 후 주소", id(li))
lists = [1,2,3,4,5]
print(lists)
print("메인 내 연산 전 주소", id(lists))
modify2(lists)
print("메인 내 연산 후 주소", id(lists))
print(lists)
# [1, 2, 3, 4, 5]
# 메인 내 연산 전 주소 2364829478976
# 함수 내 연산 전 주소 2364829478976
# 함수 내 연산 후 주소 2364829478976
# 메인 내 연산 후 주소 2364829478976
# [1, 2, 3, 4, 5, 100, 200]
위처럼 리스트의 경우 변경할 때 새로운 객체를 생성하지 않고 기존의 객체에 추가된다.
그 이유는 리스트들이 값의 주소를 가질 뿐, 값 자체를 가진 것이 아니기 때문이다.
또 다른 mutable object로는 딕셔너리 타입이 존재한다.
dic = {"name" : "MariBlossom", "age" : 25, "height":174}
print(dic)
print(dic["name"])
print(dic["age"])
print(dic["height"])
# {'name': 'MariBlossom', 'age': 25, 'height': 174}
# MariBlossom
# 25
# 174
파이썬에선 기본 기능으로 딕셔너리를 제공하는데
콜론을 기준으로 왼쪽은 key, 오른쪽은 value가들어가며,
key값을 기준으로 value와 dictionary자체의 리스트들은 변경가능하다.
따라서
def modify2(dic):
print("함수 내 연산 전 주소", id(dic))
dic["kg"] = 80
print("함수 내 연산 후 주소", id(dic))
dic = {"name" : "MariBlossom", "age" : 25, "height":174}
print(dic)
print("메인 내 연산 전 주소", id(dic))
modify2(dic)
print("메인 내 연산 후 주소", id(dic))
print(dic)
# {'name': 'MariBlossom', 'age': 25, 'height': 174}
# 메인 내 연산 전 주소 2581181967360
# 함수 내 연산 전 주소 2581181967360
# 함수 내 연산 후 주소 2581181967360
# 메인 내 연산 후 주소 2581181967360
# {'name': 'MariBlossom', 'age': 25, 'height': 174, 'kg': 80}
위처럼 함수에서 변화해도 주소값이 변경되지 않는다.
🔍지역변수, 전역변수
파이썬에서는 지역변수가 선언된 함수에서 벗어나면 사용할 수 없다.
그러나 전역변수를 사용하고 싶다면 global키워드를 사용하여 전역변수를 함수 내에서 사용할 수 있는데,
def sub():
print(s)
s = "바나나 좋아!"
print(s)
s = "사과가 좋아"
sub()
print(s)
#UnboundLocalError: local variable 's' referenced before assignment
위의 경우는 지역변수에러가 나며,
def sub():
global s #전역변수 선언
print(s)
s = "바나나 좋아!"
print(s)
s = "사과가 좋아"
sub()
print(s)
# 사과가 좋아
# 바나나 좋아!
# 바나나 좋아!
위처럼 global로 따로 선언해주어야 전역변수로 사용할 수 있다.
그러나 전역변수를 사용하는 프로그램은 가독성 상 좋지 않은 프로그램이다!
list객체 또한 마찬가지이다!
위에서 말했듯 list는 변경 가능한 객체이다. 그러나,
def sub(mylist):
#리스트가 함수로 전달
mylist = [1,2,3,4]
print("함수 내의 리스트", mylist)
mylist = [5,6,7,8]
sub(mylist)
print("함수 외의 리스트", mylist)
# 함수 내의 리스트 [1, 2, 3, 4]
# 함수 외의 리스트 [5, 6, 7, 8]
위와 같이 함수 내에서 mylist로 새로 할당을 해버리면, 원래 주소가 아닌 새로운 주소에서 덮어씌워진다.
그렇기 때문에 mylist자체의 값은 유지된다.
따라서
def sub(mylist):
#리스트가 함수로 전달
for x in range(len(mylist)):
mylist[x] -= 4
print("함수 내의 리스트", mylist)
mylist = [5,6,7,8]
sub(mylist)
print("함수 외의 리스트", mylist)
# 함수 내의 리스트 [1, 2, 3, 4]
# 함수 외의 리스트 [1, 2, 3, 4]
위처럼 할당이 아닌 변경을 해주면 아래에도 함수 밖에서도 적용이 됨을 확인할 수 있다.
🔍튜플과 여러값 반환
다른 프로그래밍 언어에서는 함수는 항상 하나의 값만 반환한다.
하지만 파이썬에선 여러값을 반환하는 것 처럼 보이게 할 수 있는데, 튜플을 사용한 개념이다.
def sub():
return 1,2,3
a,b,c = sub()
print(a,b,c)
#1 2 3
위에서 보면 return 1,2,3이라는 말도 안되는 식이 통하는 것을 볼 수 있다.
이것은 사실 자세히 보면 return (1,2,3)이라고 작성된 것이라 볼 수 있으며,
이것은 튜플이라는 객체로 반환되어, a,b,c변수에 하나하나 풀어서 저장되는 방식이다.
그렇기 때문에 아래의 식도 적용이 된다.
x = 10
y = 11
print(x,y)
x,y = y,x
print(x,y)
#10 11
#11 10
리스트와 튜플의 다른점은
1. 리스트는 [대괄호]로 둘러싸지만, 튜플은 (소괄호)로 둘러싼다
2. 리스트는 mutable object지만 튜플은 immutable object이기 때문에 값을 변환할 수 없다.
🔍무명함수(람다식)
무명함수(람다식)은 이름은 없고 몸체만 있는 함수를 말한다.
sum = lambda x, y: x + y
print(sum(10, 20))
위처럼 lambda라는 키워드를 통해 선언하고 사용할 수 있으며,
구조는 lambda 인수:수식으로 구성된다.
특징으로는
1. 키워드 안에선 print()같은 함수를 호출할 수 없으며 오직 계산만이 가능하다.
2. 람다 함수도 함수처럼 전역변수를 참조할 수 없고 자신만의 이름공간을 가지고 있다.(인수로 들어온 이름 사용)
3. 람다 함수에서는 변수에 값을 할당할 수 없다.
4. 람다 함수는 항상 반환되는 수식만 쓸수 있기 때문에 return 키워드가 필요없다.
5. 함수처럼 메모리를 갖는다.(함수 객체)
6. 람다함수는 리스트로도 생성할 수 있는데,
L = [lambda x: x**2,
lambda x: x**3,
lambda x: x**4,
lambda x: x**5]
for f in L:
print(f(5))
# 25
# 125
# 625
# 3125
위와 같이 사용할 수 있다.
람다함수는 코드안에서 함수를 포함하는 곳 어디든지 사용할 수 있다.
🔍모듈과 함수를 사용한 프로그램 설계
모듈이란 함수나 변수들을 모아둔 파일을 칭한다.(.py파일)
모듈안의 함수들은 import로 다른 모듈에 포함될 수 있다.
모듈 중에서 __main__모듈은 최상위 수준에서 실행되는 스크립트를 의미한다.
__name__란?
인터프리터가 실행 전에 만들어두는 내장 전역 변수이다.
이 변수는 직접 실행된 모듈에 __main__이라는 값을 가지게 되며, 직접 실행되지 않고, import된 모듈은 파일 명을 가지게 된다.
한마디로 if __ name__ == “__main__”라는 조건문을 넣어두면 직접 실행시켰을때만 실행되는 코드를 작성하면 된다.
위의 기능은 함수들을 디버깅 해볼 때 사용할 수 있을 것이다.
def readList():
nlist = []
flag = True
while flag:
number = int(input("Enter a number: "))
if number < 0:
flag = False
else:
nlist.append(number)
return nlist
def processList(nlist):
nlist.sort()
return nlist
def printList(nlist):
for i in nlist:
print(i)
def main():
nlist = readList()
nlist = processList(nlist)
printList(nlist)
if __name__ == '__main__':
main()
# Enter a number: 30
# Enter a number: 50
# Enter a number: 10
# Enter a number: 20
# Enter a number: 90
# Enter a number: -1
# 10
# 20
# 30
# 50
# 90
위와 같은 식으로 메인을 실행시킬 수 있다.
대부분 대형 프로그램의 코드들은 매우 길다. 이것을 함수없이 작성한다면 가독성이 떨어지며, 디버깅이 힘들다.
이걸 해결하기 위해 코드를 최대한 작은 조각으로 분리해서 여러개의 함수로 나누어 작성해야한다
'언어 > Python' 카테고리의 다른 글
| 8. 리스트2(리스트 관련 함수들, 리스트 함축...) (6) | 2025.08.26 |
|---|---|
| 7. 리스트(list 자료형의 기능, 함수 등..) (5) | 2025.08.25 |
| 5. 함수 (0) | 2025.08.23 |
| 4. 자주 쓰이던 함수 (0) | 2025.08.22 |
| 3. 반복문 (0) | 2025.08.21 |