Python_Day.4

조현기·4일 전

Python_Day.4

변수의 범위, 람다, 내장 함수(map, filter), 파일 입출력, 그리고 클래스의 첫걸음.
함수를 "값처럼" 다루기 시작한 날이다.

학습 네 번째 날이다. 오늘 배운 내용은 이렇다.

  1. 전역 변수와 지역 변수
  2. 람다(lambda)와 함수를 변수에 담기
  3. input()과 split()
  4. 내장 함수: all, any, chr, dir, divmod, enumerate, eval, filter, map
  5. 파일 입출력
  6. 클래스: 객체, 인스턴스, __init__, self

1. 전역 변수와 지역 변수

JS에서 배운 전역 변수와 지역 변수의 개념은 Python에서도 그대로 적용된다.

a = 1
def vartest(a):
    a = a + 1

vartest(a)
print(a)          # 1

vartest 안의 a는 그 함수 안에서만 쓰이는 지역 변수라서, 함수 밖의 a 값에는 영향을 주지 않는다. 그래서 출력은 2가 아니라 1이다.

def vartest(a):
    a = a + 1

vartest(3)
print(a)          # NameError: name 'a' is not defined

이런 코드도 문제가 된다. 함수 밖 어디에도 a라는 변수가 정의되어 있지 않아서 오류가 난다. 정상적으로 출력되게 고치면 이렇다.

def vartest(a):
    a = a + 1
    return a

a = vartest(3)
print(a)          # 4

함수 안의 결과를 밖에서 쓰려면 return으로 돌려주고, 밖에서 변수에 받아야 한다. return이 없으면 함수를 호출해도 결과값이 없어서 a = vartest(3)의 a는 None이 된다.


2. 람다와 함수를 변수에 담기

lambda

# 함수명 = lambda 매개변수: 실행문
abc = lambda a, b: a * b
sub = lambda x, b: x - b
print(abc(3, 5))      # 15
print(sub(9, 4))      # 5

lambda는 이름 없이 한 줄로 만드는 간단한 함수다. 같은 함수를 def로 쓰면 이렇다.

def multi(x, y):
    return x * y

multi2 = lambda x, y: x * y
print(multi2(5, 2))   # 10

def plus(x):
    return x + 10

plus2 = lambda x: x + 10
print(plus2(11))      # 21

식 하나로 값을 돌려주는 단순한 함수는 lambda로 간결하게 쓸 수 있다. return을 따로 쓰지 않고, 콜론 뒤의 식이 곧 반환값이다. JS의 화살표 함수((x, y) => x * y)와 비슷한 역할이다.

필기에는 람다를 쓰는 이유로 "메모리 절약", "즉시 실행 함수라 정의하자마자 실행됨"이라고 적었는데, 정확하지 않다. 람다는 정의한다고 바로 실행되지 않고, 함수를 만들 뿐이다. 이유는 가독성과 간결함 정도로 보는 것이 맞고, 바로 실행하려면 (lambda x: x + 1)(3)처럼 괄호로 감싸서 호출해야 한다.

함수를 변수에 담기

def multi(x, y):
    return x * y

print(multi(4, 5))        # 20

a = multi                  # 함수 이름을 a에 할당 (a는 별칭이 된다)
print(a(4, 5))            # 20  (multi에 넣은 것과 같은 결과)
print(type(a))            # <class 'function'>

a = multi처럼 괄호 없이 함수 이름만 대입하면 a가 그 함수를 가리키게 된다. JS에서 head.onclick = on;처럼 함수를 값으로 다루던 것과 같다.

함수는 다른 함수의 매개변수로도 넘길 수 있다. (Day.8의 콜백, 고차 함수와 같은 개념이다.)

def final(x, y, func1):
    print(x, y, func1(5, 6))     # 넘겨받은 함수에 5, 6을 넣어서 호출

final(3, 5, a)                    # 3 5 30

final의 세 번째 인자로 multi(a)를 넘겼고, 안에서 func1(5, 6)이 multi(5, 6)으로 실행되어 30이 나온다.


3. input()과 split()

input()으로 받은 값은 기본적으로 모두 문자열이다.

name = input('이름은?')
score = input('학점은?')
age = input('나이는?')

print(name, score, age)
print(type(name), type(score), type(age))    # 전부 <class 'str'>

숫자로 쓰려면 변환한다.

num1 = int(input('첫번째 정수'))      # 문자열 → 정수
num2 = int(input('두번째 정수'))
print(num1 + num2)

float1 = float(input('실수를 입력'))
print(float1, type(float1))           # 정수 3을 입력하면 3.0으로 출력된다

split()

한 줄에 여러 값을 입력받아 나누고 싶을 때 split()을 쓴다.

a, b = input('숫자입력').split()      # 입력: 3 4  → ['3', '4']
a, b = int(a), int(b)                 # 각각 정수로 변환
print(a + b, type(a + b))             # 7 <class 'int'>

split()은 문자열을 기준 문자로 잘라서 리스트로 만드는 함수다. 괄호 안에 아무것도 넣지 않으면 공백(띄어쓰기, 엔터)을 기준으로 자른다.

a = input('숫자입력').split()         # 입력: 1 2 3 4 5 6 7 8
# a = ['1', '2', '3', '4', '5', '6', '7', '8']

공백이 아닌 다른 문자로 입력하면 어떻게 될까.

a = input('숫자입력').split()         # 입력: 1,2,apple,home,66,go
print(a, type(a))                     # ['1,2,apple,home,66,go'] <class 'list'>

공백이 없어서 자를 곳이 없으니 통째로 하나인 리스트가 된다. 쉼표로 자르려면 split(',')처럼 기준 문자를 써 줘야 한다.

print('1,2,apple'.split(','))         # ['1', '2', 'apple']

문자열의 split 함수는 split(sep, maxsplit) 두 파라미터를 가진다.

파라미터기본값의미
sepNone구분자. None이면 공백(띄어쓰기, 엔터)으로 자른다
maxsplit-1최대 몇 번 자를지. -1이면 제한 없이 끝까지 자른다
'a,b,c'.split(',', 1)                 # ['a', 'b,c']   (1번만 자름)
'a b c'.split(maxsplit=1)             # ['a', 'b c']
# 'a b'.split(1)                      # 에러: 첫 번째 자리는 sep이라 문자열이어야 한다

sep은 생략하고 split(',')처럼 써도 되고, maxsplit만 쓰려면 이름을 붙여서(maxsplit=1) 써야 한다. (참고: blockdmask 블로그의 split 정리)

실습: 딕셔너리에 이름과 응답 저장하기

문제: 빈 딕셔너리를 만들고, 무한 루프로 이름과 TV를 좋아하는지 입력받아 딕셔너리에 추가한다. "친구한테도 물어볼까?"에 no가 입력되면 루프를 종료하고, 마지막에 items()로 전부 출력한다.

empty = dict()
while True:
    name = input('이름을 말해봐')
    like_tv = input('TV보는 것은 좋아해?')
    empty[name] = like_tv                 # 이름을 키로, 대답을 값으로 저장
    then = input('친구한테도 물어볼까?')
    if then == 'no':
        break
print(empty.items())

필기에서는 empty['name'], empty['like'] = name, like_tv로 썼는데, 이러면 키가 'name'과 'like' 두 개로 고정되어서 반복할 때마다 값이 덮어씌워진다. empty[name] = like_tv처럼 입력받은 이름을 키로 쓰면 사람마다 하나씩 차곡차곡 쌓인다.


4. 리스트 만드는 여러 방법

1~5를 담은 리스트를 세 가지 방식으로 만들 수 있다.

# 리스트 컴프리헨션
nums = [i for i in range(1, 6)]
print(nums)                  # [1, 2, 3, 4, 5]

# list()로 형 변환
li2 = list(range(1, 6))
print(li2)                   # [1, 2, 3, 4, 5]

# 빈 리스트에 for문으로 추가
re = []                      # re = list()
for i in li2:
    re.append(i)
print(re)                    # [1, 2, 3, 4, 5]

append로 하나씩 쌓는 방식은 range(1, 6)을 바로 list()로 감싸면 되는 일이지만, append를 연습하기 위한 흐름이었다.


5. 내장 함수

미리 만들어져 있는 내장 함수들도 배웠다.

함수설명
abs(x)절댓값
all(모음)요소가 모두 참이면 True, 하나라도 거짓이면 False. 빈 값이면 True
any(모음)요소 중 하나라도 참이면 True, 모두 거짓이면 False. 빈 값이면 False
chr(i)유니코드 숫자 값을 받아 그에 해당하는 문자를 반환
dir(모음)객체가 가진 내장 함수(.append, .count 등)를 보여 줌
divmod(a, b)a를 b로 나눈 몫과 나머지를 튜플로 반환
enumerate(모음)순서(인덱스)와 값을 함께 꺼냄
eval(문자열)문자열로 된 표현식을 실행한 결과를 반환
filter(함수, 모음)함수의 반환값이 참인 요소만 걸러냄
map(함수, 모음)모든 요소에 함수를 적용
print(all([1, 2, 0]), all([]))      # False True
print(any([0, 0]), any([]))         # False False
print(chr(97))                      # a
print(divmod(7, 3))                 # (2, 1)

enumerate

for i, name in enumerate(['body', 'foo', 'bar']):
    print(i, name)
# 0 body
# 1 foo
# 2 bar

for문과 함께 쓰면 현재 요소의 순서와 값을 한 번에 알 수 있다. 값뿐 아니라 인덱스도 필요할 때 편하다.

eval

print(eval('1+2'))                  # 3
print(eval("'hi'+'a'"))             # hia
print(eval('divmod(4,3)'))          # (1, 1)

eval은 문자열 안의 식을 코드로 실행해서 결과를 돌려준다. 숫자 식뿐 아니라 문자열 연산이나 함수 호출도 된다. 바깥 따옴표를 벗겨낸 식을 계산하는 것이다. JS의 eval과 같은 역할이고, 사용자가 입력한 문자열을 그대로 넣으면 의도하지 않은 코드가 실행될 수 있으므로 조심해서 써야 한다.

filter

def positive(x):
    return x > 0

print(list(filter(positive, [1, 2, -3, -4, -5, 6])))     # [1, 2, 6]

# 람다로 바꾸면
result = list(filter(lambda x: x > 0, [1, 2, -3, -4, -5, 6]))
print(result)                                            # [1, 2, 6]

filter(함수, 모음)은 첫 번째 인자로 함수, 두 번째로 반복 가능한 데이터를 받는다. 데이터의 요소를 하나씩 함수에 넣어서 반환값이 참인 것만 남긴다. 그래서 함수는 조건식이어야 한다. for와 if를 합친 기능이다. JS Day.9에서 배운 filter와 같은 역할이다.

map

def two_times(numberList):
    result = []
    for number in numberList:
        result.append(number * 2)
    return result

print(two_times([1, 2, 3, 4]))                           # [2, 4, 6, 8]

def two_timess(x):
    return x * 2

print(list(map(two_timess, [1, 2, 3, 4])))               # [2, 4, 6, 8]
print(list(map(lambda x: x * 2, [1, 2, 3, 4])))          # [2, 4, 6, 8]

map(함수, 모음)은 요소를 하나씩 함수에 넣어서 그 결과로 바꾼다. filter가 조건(참/거짓)으로 거르는 것이라면, map은 연산을 적용해서 값을 바꾸는 것이다. for로 append하던 것을 한 줄로 줄여 준다.

def pp(x):
    return x + 20

print(pp(4))                                              # 24
print(list(map(pp, [1, 2, 3])))                           # [21, 22, 23]
print(list(map(lambda x: x + 20, [1, 2, 3])))             # [21, 22, 23]

re2 = list(map(lambda i: i, [5, 4, 3, 2, 1]))
print(re2)                                                # [5, 4, 3, 2, 1]

list1 = [1, 2, 3, 4, 5]
re3 = list(map(lambda x: x + 10, list1))
print(re3)                                                # [11, 12, 13, 14, 15]

map, filter, 리스트 컴프리헨션 비교

같은 일을 세 가지로 쓸 수 있다.

list1 = [1, 2, 3, 4, 5]

def square(x):
    return x ** 2

print(list(map(square, list1)))                 # [1, 4, 9, 16, 25]
print(list(map(lambda x: x ** 2, list1)))       # 람다로 변경
print([i ** 2 for i in list1])                  # 리스트 컴프리헨션으로 변경

# 3보다 작은 값만 (filter)
print(list(filter(lambda x: x < 3, range(1, 6))))     # [1, 2]

# 1~20 중 2의 배수만
print([x for x in range(2, 21, 2)])                    # 증감값 이용
print([x for x in range(1, 21) if x % 2 == 0])         # if 조건 이용
print(list(filter(lambda x: x % 2 == 0, range(1, 21))))   # filter 이용
하는 일map / filter리스트 컴프리헨션
모든 요소를 변환list(map(lambda x: x*2, a))[x*2 for x in a]
조건에 맞는 요소만list(filter(lambda x: x>0, a))[x for x in a if x>0]

map과 filter는 문법 구조가 같아서 하나를 익히면 나머지도 쉽다. 컴프리헨션은 같은 일을 더 짧게 쓸 수 있다.

map과 filter는 결과를 리스트가 아니라 map 객체로 돌려준다. 그래서 list()로 감싸야 값이 보인다. JS의 map, filter가 곧바로 배열을 돌려주던 것과 다르다. 이 객체는 값이 필요해질 때 계산하는 방식이라, 아무도 값을 꺼내지 않으면 함수가 실행되지도 않는다.

list(map(lambda x: print(x + 100, end=' '), range(1, 11)))
# 101 102 103 ... 110     (list()로 감싸서 값을 꺼내야 실행됨)

list() 없이 map(...)만 쓰면 아무것도 출력되지 않는다. 다만 출력만 하려는 목적이라면 for문이 더 읽기 쉽다.


6. 파일 입출력

열기 모드

모드의미
r읽기 (read)
w쓰기 (write). 파일이 없으면 생성하고, 있으면 내용을 지우고 새로 쓴다
a추가 (append). 기존 내용 뒤에 이어 쓴다

f = open('파일명', '파일열기모드')로 파일을 연다.

경로와 인코딩

  • 절대경로: 처음부터 끝까지 전부 쓴 경로(C:\Python\test.py)
  • 상대경로: 현재 파일을 기준으로 쓰는 경로(./, ../, ../../)
  • 인코딩: 문자를 숫자(바이트)로 바꾸는 것. 디코딩은 숫자를 다시 문자로 바꾸는 것
  • UTF-8: 가장 많이 쓰는 국제 표준 인코딩(유니코드)

한글과 영어는 파일에 저장될 때 숫자로 바뀌어 저장되므로, 저장할 때의 규칙과 읽을 때의 규칙이 같아야 한다. 그래서 open을 할 때 encoding='UTF-8'을 꾸준히 써 주는 것이 좋다.

읽기

f = open('./resource/news.txt', 'r', encoding='UTF-8')
print(f.encoding)          # 인코딩 확인
print(f.name)              # 파일명 확인
print(f.mode)              # 열기 모드 확인
result = f.read()          # 파일 전체 읽기
print(result)
f.close()                  # 파일을 열었으면 반드시 닫기

파일 객체는 for문으로 줄 단위로 읽을 수도 있다.

f = open('./resource/news.txt', 'r', encoding='UTF-8')
for a in f:
    print(a)               # 한 줄씩
f.close()

각 줄 끝에는 줄바꿈(\n)이 붙어 있어서, print가 또 줄바꿈을 하면 줄 사이에 빈 줄이 생긴다. print(a.strip())나 print(a, end='')로 없앨 수 있다.

with: 알아서 닫아 주는 방식

with open('./resource/news.txt', 'r', encoding='UTF-8') as f:
    c = f.read()           # f의 내용 전체를 문자열로 반환
    print(type(c))         # <class 'str'>
    print(list(c))         # 글자 하나하나를 리스트로

with를 쓰면 블록이 끝날 때 파일이 자동으로 닫힌다. 그래서 f.close()를 따로 쓰지 않아도 된다.

# read(n): n글자만 읽기
with open('./resource/news.txt', 'r', encoding='UTF-8') as f:
    c = f.read(30)         # 30글자만 읽어서 c에 저장
    print(c)

# readline(): 한 줄 읽기
with open('./resource/news.txt', 'r', encoding='UTF-8') as f:
    line = f.readline()    # 첫 줄
    print(line)
    line = f.readline()    # 한 번 더 쓰면 다음 줄
    print(line)

# readlines(): 모든 줄을 리스트로
with open('./resource/news.txt', 'r', encoding='UTF-8') as f:
    lines = f.readlines()
    print(lines)
    for i in lines:
        i = i.strip()      # 양끝의 공백과 개행문자(\n)를 제거
        print(i)
방법읽는 범위
read()전체를 문자열 하나로 (read(n)은 n글자)
readline()한 줄. 호출할 때마다 다음 줄
readlines()모든 줄을 리스트로
for a in f한 줄씩

readline()을 두 번 쓰면 첫 줄, 둘째 줄이 차례로 나오는 것은 파일에서 읽던 위치가 이어지기 때문이다.

쓰기

# 'story.txt' 파일을 생성하여 쓴다
with open('./resource/story.txt', 'w', encoding='utf-8') as f:
    f.write('hi 파이썬\n')               # 문자열 쓰기(저장)

# 이어서 추가
with open('./resource/story.txt', 'a', encoding='utf-8') as f:
    f.write('이어서 한 줄 더\n')

# 여러 줄: writelines
with open('./resource/list.txt', 'w', encoding='utf-8') as f:
    li = ['React\n', 'DB\n', 'Python\n']
    # f.write(li)      # 에러: write는 문자열만 받는다
    f.writelines(li)   # 리스트는 writelines를 이용

write()는 문자열 하나만 쓸 수 있어서 리스트를 넣으면 에러가 난다. 리스트는 writelines()를 쓴다. writelines는 줄바꿈을 자동으로 넣어 주지 않으므로 각 문자열 끝에 \n을 직접 붙여야 한다. 또 'w'로 같은 파일을 다시 열면 이전 내용이 사라지므로, 이어 쓸 때는 'a'를 쓴다.

연습 문제

# Q3. 프로그램 오류 수정하기
input1 = int(input('첫 번째 숫자를 입력하세요'))
input2 = int(input('두 번째 숫자를 입력하세요'))

total = input1 + input2
print(f'두 수의 합은 {total}입니다')

input의 결과는 문자열이라서, int()로 감싸야 숫자로 더해진다. 감싸지 않으면 '3' + '4'가 '34'로 이어 붙여진다.

# Q4. 출력 결과가 다른 것은?
print('you', 'need', 'python')    # you need python
# 쉼표로 구분한 값 사이에는 자동으로 공백이 들어간다
# Q5. 프로그램 오류 수정하기 2
f1 = open('text.txt', 'w')
f1.write('life is too short')
f1.close()                         # 닫아야 내용이 확실히 저장된다

f2 = open('text.txt', 'r')
print(f2.read())

쓰기를 마친 파일을 close()하지 않고 바로 읽으면 내용이 아직 저장되지 않았을 수 있다. 한글을 쓸 때는 encoding='utf-8'도 함께 써 준다.

# Q6. 사용자 입력 저장하기
user_input = input('저장할 내용을 입력하세요 :')
f = open('test.txt', 'a', encoding='utf-8')
f.write(user_input)
f.write('\n')
f.close()
# Q7. 파일의 문자열 바꾸기
with open('test2.txt', 'r', encoding='utf-8') as f:
    body = f.read()

body = body.replace('java', 'python')

with open('test2.txt', 'w', encoding='utf-8') as f:
    f.write(body)

파일 전체를 읽어서 replace로 바꾼 뒤, 'w'로 다시 열어서 덮어쓰는 흐름이다. replace는 원본 문자열을 바꾸지 않고 바뀐 새 문자열을 돌려주므로 body = body.replace(...)처럼 다시 대입해야 한다.


7. 클래스

객체, 클래스, 인스턴스

  • 객체(object): 파이썬에 존재하는 모든 것. 123, 'Hello', [1, 2, 3], Dog() 등
  • 클래스(class): 설계도
  • 인스턴스(instance): 클래스를 바탕으로 실제로 만들어진 제품. "a는 A 클래스의 인스턴스다"처럼 클래스와 객체의 관계를 말할 때 쓴다.
class Profile:
    def __init__(self):
        pass

a, b = Profile(), Profile()        # a와 b는 Profile의 인스턴스
print(type(a))                     # <class '__main__.Profile'>

__init__과 self

class Profile:
    name = 'default'               # 클래스 변수 (클래스 블록 안, 모든 인스턴스가 공유)

    # 초기화 함수 (self: 객체 자기 자신)
    # __init__은 객체를 만들 때 자동으로 호출되는 메소드
    def __init__(self, name, age):     # 인스턴스 변수: 각 인스턴스마다 따로 존재
        self.name = name
        self.age = age


my_name = Profile('Tom', 25)       # 객체가 생성되면 __init__이 자동 호출된다
print(my_name.name, my_name.age, type(my_name), type(my_name.name), type(type(my_name.age)))
# Tom 25 <class '__main__.Profile'> <class 'str'> <class 'type'>

p2 = Profile('Amy', 30)
print(p2.name)                     # Amy

Profile('Tom', 25)처럼 클래스 이름 뒤에 괄호를 붙이면 인스턴스가 만들어지고, 그 순간 __init__이 자동으로 호출된다. self는 만들어지는 인스턴스 자신이며, self.name = name은 "이 인스턴스의 name에 값을 저장한다"는 뜻이다. 인스턴스를 만들 때는 self 자리에 값을 넣지 않고 그 다음 매개변수부터 넘긴다.

type(type(my_name.age))가 <class 'type'>으로 나오는 것은, age의 타입이 int이고 int 자체가 type 클래스의 객체이기 때문이다. 파이썬에서는 클래스도 객체다.

print(my_name == p2)               # False  (서로 다른 객체)
print(id(my_name), id(p2))         # 주소가 다르다

print('{} {} {} {}'.format(my_name.name, my_name.age, p2.name, p2.age))
# Tom 25 Amy 30
c = my_name
print(my_name == c, id(my_name), id(c))     # True, 주소가 같음 (같은 객체)

from copy import copy
c = copy(my_name)
print(my_name == c, id(my_name), id(c))     # False, 주소가 다름

필기의 주석에는 copy한 경우를 "값은 같지만 주소가 다름"이라고 적었는데, 이 코드의 == 결과는 False다. 직접 만든 클래스는 ==를 따로 정의하지 않으면 같은 객체인지(주소)로 비교하기 때문이다. 값이 같은지로 비교하게 하려면 클래스에 __eq__ 메소드를 정의해야 한다.

클래스 변수와 인스턴스 변수

위 Profile에는 name이 두 군데 있다. 클래스 블록 안의 name = 'default'는 클래스 변수(모든 인스턴스가 공유), __init__ 안의 self.name은 인스턴스 변수(인스턴스마다 개별 존재)다.

print(Profile.name)        # default  (클래스 변수)
print(my_name.name)        # Tom      (인스턴스 변수가 우선)
print(p2.name)             # Amy

인스턴스에 같은 이름의 변수가 있으면 인스턴스 변수가 먼저 쓰이고, 없을 때만 클래스 변수를 찾아간다.

인스턴스 메소드와 self

class Test:
    def func1():                   # self 인자가 없는 함수
        print('self 없는 함수')

    def func2(self):               # self 인자가 있는 함수 → 인스턴스 메소드
        print(id(self))
        print('인스턴스 메소드임')


a = Test()
# a.func1()    # 에러
a.func2()      # 호출하면 자동으로 self(인스턴스 자신)가 전달된다

Test.func1()   # 클래스에서 직접 호출하므로 에러 없이 작동
# Test.func2() # 에러: self에 들어갈 인스턴스가 없다
Test.func2(a)  # 클래스에서 직접 부를 때는 self 자리에 인스턴스를 직접 넘긴다
  • a.func1()이 에러인 이유: 인스턴스를 통해 호출하면 파이썬이 내부적으로 func1(a)처럼 인스턴스를 첫 인자로 자동 전달하는데, func1은 받을 매개변수가 없어서 takes 0 positional arguments but 1 was given 오류가 난다.
  • Test.func2()가 에러인 이유: 클래스에서 직접 호출하면 자동 전달이 없으므로 self 자리가 비어 버린다. Test.func2(a)처럼 직접 넘겨 주면 된다.

필기에서는 self가 없는 func1을 "클래스 메소드"라고 불렀는데, 파이썬에서 클래스 메소드는 @classmethod를 붙여 만드는 별도의 것(첫 인자 cls)이다. self 없이 클래스 안에 쓴 이 함수는 그냥 인스턴스로 부를 수 없는 함수일 뿐이라, 용어를 구분해 두는 것이 좋다.


마무리

  • 함수 안의 변수는 지역 변수이고, 결과를 밖에서 쓰려면 return으로 돌려주고 받아야 한다.
  • lambda는 이름 없는 한 줄 함수이고 정의한다고 바로 실행되지 않는다. 함수는 변수에 담거나 다른 함수의 인자로 넘길 수 있다.
  • input()은 항상 문자열이고, split()은 문자열을 잘라서 리스트로 만든다(기본은 공백 기준).
  • map은 변환, filter는 걸러내기이고, 결과는 list()로 감싸야 보인다.
  • 파일은 'r'(읽기), 'w'(덮어쓰기), 'a'(추가)로 열고, with를 쓰면 자동으로 닫힌다. 인코딩은 utf-8로 맞춘다.
  • 클래스는 설계도, 인스턴스는 그로 만든 제품이다. __init__은 생성 시 자동 호출되고, self는 인스턴스 자신이다.

Tags: Python lambda map filter 파일입출력 클래스 self 변수스코프 개발자 학습기록

profile
난 뭘까

0개의 댓글