yon11b

[SK 쉴더스 루키즈] 파이썬 기초 4(함수, lambda, 파일입출력, 클래스) 본문

보안/SK 쉴더스 루키즈

[SK 쉴더스 루키즈] 파이썬 기초 4(함수, lambda, 파일입출력, 클래스)

yon11b 2026. 3. 6. 13:11
반응형

함수

매개변수

print 내장함수로 보는 매개변수 지정

1. sep

print('king', 'kin', end=',', sep='\t') # tab 간격만큼 주어 출력하겠다.

2. *values: 가변매개변수: 몇 개가 들어오든 상관없이 다 받아줌

데이터들을 묶어서 튜플로 저장

튜플에서 한 개는 (1,) 이렇게 했었음!

사용자가 전달한 데이터가 바뀌면 안되기 때문에 튜플로 주는 것.

튜플은 시퀀스이기 때문에 인덱스를 이용하여 반복문을 쓸 수 있다.

e.g. 전달되는 모든 숫자 매개변수를 모두 더한 값을 반환하는 함수

def add_all(*args):
    sum=0
    for i in args:
        sum+=i
    print(sum)
add_all(1,2,3,4,5,6,7,8,9,10)

 

1. def f1(type, *args)  —> 얘만 가능!

2. def f1(*args, type)  —> 얜 안 됨

이유?

더보기

파이썬에는 매개변수를 배치하는 엄격한 순서 규칙이 있다.

  • args는 "남은 거 다 가져와!"라는 욕심쟁이 보따리
  • f1(type, *args)의 경우:
    1. 첫 번째로 들어온 값을 딱 집어서 type에 넣습니다.
    2. 그 뒤에 남은 모든 숫자들을 args 보따리에 담습니다. (깔끔하죠?)
  • f1(*args, type)의 경우 (에러 발생 가능성 높음):
    1. args가 앞에 있으면, 컴퓨터는 "어디까지가 숫자고 어디서부터가 type이지?"라고 혼란에 빠집니다.
    2. 별도로 이름을 지정해서 호출(type='+')하지 않는 이상, 컴퓨터는 모든 값을 args에 다 집어넣으려고 해서 type에 들어갈 값이 없게 됩니다.

정리: 가변매개변수는 뒤로 가는게 일반적!!

 

키워드 매개변수, kwargs

  • 별 2개(**)
    • dict 형태로 반환.
    def f1(**kwargs):
    	~~
    f1**(name='foo', age=3)
    
    => {name: 'foo', age: 3}**
    

함수의 리턴값은 언제나 하나이다.

여러 개의 값을 반환해야 한다면, list, tuple, dict 타입으로 반환하면 된다.

e.g. 두 개를 리턴하고 싶다면 튜플에 2개의 인수를 넣어서 리턴 (+우리가 대괄호[]나 소괄호() 없이 값만 나열해서 리턴하면, 파이썬은 기본값으로 튜플을 선택함)

def test():
    return 1, 2  # 사실은 return (1, 2)와 같다.
    
num1, num2 = test()  # unpacking

 

매개변수에 default 값 지정해주기

 

이건 안 되고

 

이건 된다?

 

디폴트값을 정해주는 인자는 무조건 뒤에 가야 한다.

왜냐?

더보기

컴퓨터 입장에서 add1(1, 2)를 호출했을 때를 상상해 보세요.

  • 만약 def add1(n1=0, n2): 가 허용된다면?
  • 사용자가 add1(10)이라고 하나만 넣었을 때, 컴퓨터는 멘붕에 빠집니다.
    • "이 10은 기본값이 있는 n1에 넣으라는 거야? 아니면 꼭 필요한 n2에 넣으라는 거야?"

 

함수 내부 변수, 외부 변수

이거 왜 되냐?

 

근데 이건 또 안 됨

정리: 참조는 되는데 값 변경은 안된다

할당도 되게 하는 방법: global 써서 함수 바깥에 있는 변수도 값을 바꿀 수 있도록 하자!

lambda

  • 함수를 한 줄로 간결하게 만들 때 사용
  • def와 동일한 역할
  • 함수를 매개변수로 받아서 처리하는 함수에 주로 사용
  • lambda를 쓰면 함수 이름은 정의하지 않음(익명함수)
    • 재사용을 하지 않겠다!
    • 변수로 받아서 처리함(이게 사실상 함수이름 역할을 하긴 함)
이름 = lambda arg1, arg2: 연산(결과값의 반환-> 산술, 비교/논리, 문자열)
#     def (인수1, 인수2): return도 생략한다.
add = lambda a, b: a+b
print(add(3, 4)) => 7

 

 

++pbl 3번 문제에서 쓰인 lambda x: x[1] ⇒ 여기서 x는 리스트였음

# 3.2 통계 출력 - 최고 점수 학생, 최저 점수 학생
def find_top_bottom(student_dict: dict):   
    max_std_tuple=max(student_dict.items(), key=lambda x: x[1])
    min_std_tuple=min(student_dict.items(), key=lambda x: x[1])
   
    return min_std_tuple, max_std_tuple

 

내장함수

1. filter(func, iterable)

filter(함수, 시퀀스 데이터(인수역할))

시퀀스 데이터의 요소 값을 순서대로 함수에 전달하며 함수를 호출했을 때 리턴 값이 참인 것만 묶어서 걸러내서 리턴

 

lambda를 사용한 방식

 

2. max(iterable): 시퀀스 데이터를 입력 받아 그 최댓값을 리턴
3. min(iter): 시퀀스 데이터를 입력 받아 그 최솟값을 리턴
4. sorted(iter): 입력 데이터를 정렬한 후 그 결과를 리스트로 리턴하는 함수

5. map(f, iterable): 원본 리스트의 값을 기반으로 연산한 결과를 리스트로 생성, 반환하는 함수(값을 가공한다는 점에서 filter와 차이)

list(map(lambda x: x*100, [1,2,3,4,5]))

 

 

파일 입출력

프로그램 ←——→자원

표준 입출력: input(), print()

파일 단위 입출력: open(경로, 모드)

모드

  • w(write): 기존 데이터 없애고 새로 추가
  • r(read)
  • a(append): 기존 데이터 뒤에 추가

파일 쓰기

f=open('new.txt', 'w')
f.write("hello hayeon")
f.close()

 

파일 읽기

f.readline() : 한 줄씩 읽어와서 리턴

f=open('new.txt','r')
while 1:
    line=f.readline() # 한 줄씩만 받아옴
    if not line:
        break    
    print(line)
f.close()

 

f.readline**s**() : 전체 텍스트를 읽어와서 리턴

f=open('new.txt','r')
file=f.readlines() # 전체 텍스트를 받아옴
for line in file:
    print(line)
f.close()

 

예외처리

에러가 발생해서 비정상적인 종료가 일어나는 것을 막고 흐름을 정상적으로 처리되도록 하는 것

try: **# 에러가 발생할 수도 있는 코드**
    print(5/0)
except: **# 에러 발생하면 이거 실행함**
    print('프로그램을 종료합니다.')

 

예외 종류

  1. ZeroDivisionError
  2. IndexError: 범위 벗어난 idx 접근할 때
  3. NameError: 선언하지 않은 변수 사용할 때
  4. KeyError: dict에서 접근하려고 하는 key가 dict에 없을 때
  5. FileNotFoundError
  6. TypeError: 함수 인자를 넣지 않고 호출했을 때 / 다른 자료형끼리 연산을 했을 때(e.g. 10+’10’)

try-except문

list_a=[1]
def fn1(n1):
    return
try:
    print(10/0)
    print(list_a[5])
    print(something)
    print(fn1())
except ZeroDivisionError as e:
    print('0 나누기 에러')
    **print(e)**         # [에러출력]division by zero 출력
except IndexError:
    print('idx 접근 잘못됨 에러')
except (NameError,TypeError):     # 한번에 두 개 예외 처리
    print('선언되지 않은 변수사용 에러')
    print('함수 인자 넣지 않고 호출함 에러')
except :  # except Exception as e: -> 모든 에러 처리인데 e로 치환하고 싶을 때
    print('위에서 선언한 에러들 말고 다른 에러남요')

 

try-finally문

try:
	print(10/2)
except:
	print('에러 발생')
finally: # 에러 발생 여부와 상관없이 실행되는 구문
	print('항상 실행')

예외처리를 목적으로 하는 것이 아니라 반드시 try 구문 이후에 실행되도록 하는 경우는 try-finally를 쓴다. (except를 안 쓰고)

 

try-else문

 

오류 강제 발생시키기

raise MyError()

 

pass: 아직 기능 구현은 안 하고 이름만 써놓고 싶을 때 씀

class std:
	pass

 

클래스

묶어서 사용하면 효율적이다.

e.g. 예약시간은 시간:분:초 로 이루어져있고 14시30분10초 각각은 숫자로 이루어져 있다. 이 숫자들을 묶어서 예약시간이라는 정보가 된 것이다. 이 3개를 그냥 한번에 묶어서 사용하자! ⇒ 클래스

클래스: 똑같은 무언가를 계속 만들어 낼 수 있는 설계 도면

객체: 클래스로 만든 결과물

클래스: 변수들과 함수들을 정의하는 설계도

클래스를 이용 ⇒ 정의된 변수들과 함수들의 묶음 메모리가 생성

class 클래스이름:
	변수들…
	함수들…

객체 생성: 클래스이름()

클래스에서 함수를 사용할 때는 보통 self 매개변수를 사용

self ⇒ 실행 시점의 함수를 포함하는 객체 자신을 가리키는 변수

class FourCal():
    def __init__(self, n1,n2):
        self.n1=n1
        self.n2=n2
    def plus(self):
        return self.n1+self.n2
    def minus(self):
        return self.n1-self.n2
    def mul(self):
        return self.n1*self.n2
    def div(self):
        return self.n1/self.n2
        
fc = FourCal(6,3)
print(fc.plus())
print(fc.minus())
print(fc.mul())
print(fc.div())

 

self를 해주면 따로 변수 선언없이 밖에서도 접근이 가능하다.

 

 

자바와 파이썬의 변수 선언 위치 차이(private vs public)

더보기

1. 변수 선언 위치의 차이

  • 자바 (Java): 반드시 클래스 블록({ }) 바로 아래에 사용할 변수를 미리 선언해야 합니다. 선언하지 않은 변수를 생성자나 메서드에서 this.n1 = n1;처럼 갑자기 사용할 수 없습니다.
  • 파이썬 (Python): 클래스 몸체에 변수를 미리 적어두지 않아도 됩니다. __init__ 안에서 self.n1이라고 쓰는 순간 그 즉시 객체의 변수로 생성됩니다.

2. 접근 제어 (Public vs Private)

질문하신 "객체 생성 후 바로 변수 접근" 부분에서 가장 큰 차이가 납니다.

  • 파이썬: 기본적으로 모든 변수가 공개(Public) 상태입니다. fc.n1처럼 밖에서 마음대로 읽고 수정하는 것이 파이썬스러운 방식입니다.
  • 자바: "데이터는 꽁꽁 숨겨야 한다"는 캡슐화(Encapsulation) 원칙을 중요하게 여깁니다. 그래서 보통 변수를 private으로 숨기고, 외부에서는 getN1(), setN1() 같은 Getter/Setter 메서드를 통해서만 접근하도록 설계하는 것이 관례입니다.

 

__init__: 매직 메소드(약속된 메소드)

매직 메소드란?

더보기
class FourCal:
    def __init__(self, n1, n2):
        self.n1 = n1
        self.n2 = n2

    # '+' 연산자를 썼을 때 실행될 마법 정의
    def __add__(self, other):
        return self.n1 + other.n1 # 객체끼리 더하면 n1끼리 더하도록 설정

    # 객체를 print했을 때 보일 모습 정의
    def __str__(self):
        return f"현재 숫자는 {self.n1}, {self.n2} 입니다."

**a = FourCal(10, 20)
b = FourCal(5, 5)**

**print(a)      # 출력: 현재 숫자는 10, 20 입니다. (__str__ 작동)
print(a + b)  # 출력: 15 (__add__ 작동)**

a+b를 하면 내부적으로 a.__add__(b)이 실행된다.

즉 __add__메소드는 인자를 꼭 하나 가져야 한다는 뜻이다.

따라서 def __add__(self, other) 이렇게 other 인자를 주어야 한다.

a가 self가 되는 것임. b가 other이 되고..

매직메서드는 무조건 인자로 self를 가져야 함

 

핵심 정리

1. 함수에서 가변매개변수는 뒤에 위치해야 한다.  e.g. f1(name, *args)

2. 함수에서  디폴트값을 정해주는 인자는 뒤에 위치해야 한다.  e.g. f1(n1, n2=0)

3. 함수 내부에서 외부 변수에 대한 참조는 되는데 값 변경은 안된다.

 

 

 

728x90