0차원 자료형

int형

float형

complex형

1차원 자료형

str형

문자열 \옵션

print('나는\n고경수') # 한줄띄우기
나는
고경수
print('나는\t고경수') # 탭
나는	고경수
print('\\') # 이스케이프
\
print('나는\\n고경수')
나는\n고경수
print('나는\'고경수\'')
나는'고경수'
print("나는'고경수'")
나는'고경수'

문자열 메소드

.replace()

S = 'xxxxSPAMxxxxSPAMxxxx'
S.replace('SPAM','EGGS')
'xxxxEGGSxxxxEGGSxxxx'
S.replace('SPAM','EGGS',1)
'xxxxEGGSxxxxSPAMxxxx'

.find()

S = 'xxxxSPAMxxxxSPAMxxxx'
where=S.find('SPAM')
S[where]
'S'

.join()

'-'.join(['a','b','c'])
'a-b-c'
S='spammy'
S[3:5]='xx'
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-178-5854ec3fa955> in <module>
      1 S='spammy'
----> 2 S[3:5]='xx'

TypeError: 'str' object does not support item assignment

mm을 xx로 바꾸고 싶은데 문자열은 불변리스트라서 바꿀 수 없다.

전략: 문자열을 잠시 가변객체인 리스트로 바꾼뒤 리스트에서 자유롭게 편집하고 그 다음에 다시 문자열로 만들자.

L=list(S)
L
['s', 'p', 'a', 'x', 'x', 'y']
L[3:5]
['x', 'x']
L[3:5]=['x','x']
L
['s', 'p', 'a', 'x', 'x', 'y']
S=''.join(L)
S
'spaxxy'

.split(',')

s='bob,hacker,40'
s.split(',')

문자열 포맷팅

표현식 (문자열에서 %연산자 사용)
'addr: %s to %s' % ('seoul','jeonju')

잘못된 사용예시1 (리스트는 안됨)

'addr: %s to %s' % ['seoul','jeonju']
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-190-8a70b358fe3b> in <module>
----> 1 'addr: %s to %s' % ['seoul','jeonju']

TypeError: not enough arguments for format string

잘못된 사용예시2 (묶지않아도 안됨)

'addr: %s to %s' % 'seoul','jeonju'
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-192-0c8ecede52e2> in <module>
----> 1 'addr: %s to %s' % 'seoul','jeonju'

TypeError: not enough arguments for format string

% 연산자는 왼쪽에 문자열 오브젝트, 그리고 오른쪽에는 명시적인 튜플이 있어야 연산이 진행된다.

연산자라는 포인트를 이해하면 아래와 같은 문법도 가능함을 알 수 있다.

s = 'addr: %s to %s' 
s % ('seoul','jeonju')
'addr: seoul to jeonju'
.format 메서드
'이름:{},나이:{},성별:{}'.format('고경수','24','남')
'이름:고경수,나이:24,성별:남'
f-string 메서드
s = '고경수'
n = 25

print(f'이름={s}, 나이={n}')
이름=고경수, 나이=25

파이썬 3.6부터 사용할 수 있는 기능.

  1. 문자열 맨 앞에(따옴표앞) f를 붙인다.
  2. 사용하고 싶은 변수, 값을 중괄호 안에 넣는다.
  3. 출력한다.

list형

메소드

del a[0]
a.append('a')
a.index('a')
a.remove('a')

리스트컴프리헨션

  • 리스트를 매우 효율적으로 만드는 테크닉
  • for문에 비하여 가지고 있는 장점: (1) 코드가 간단하다. (2) 빠르다.
x=[2**i for i in [0,1,2,3,4,5]]
x
[1, 2, 4, 8, 16, 32]
[i+j for i in ['stat','math'] for j in '12345']
['stat1',
 'stat2',
 'stat3',
 'stat4',
 'stat5',
 'math1',
 'math2',
 'math3',
 'math4',
 'math5']
[i+j for i in 'XY' for j in '123']
['X1', 'X2', 'X3', 'Y1', 'Y2', 'Y3']

리스트의 중첩

a=[[11,12,13], 
   [21,22,23], 
   [31,32,33]]
a
[[11, 12, 13], [21, 22, 23], [31, 32, 33]]
a[0][0]
11
a[0][1]
12
0 1 2
0 11 12 13
1 21 22 23
2 31 32 33
  • 2차원 배열의 느낌!!!

  • 1차원 배열을 사실상 다차원배열로 확장할 수 있는 아이디어를 제공

tuple형

  • 리스트와 비슷하다.
  • 차이점1: [ ] 대신에 ( )를 사용한다.
  • 차이점2: 불변형이다. (값을 바꿀 수 없음)
  • 차이점3: 하나의 원소로 이루어진 튜플을 만들때는 쉼표를 붙여야 함.
a=(1,)
a
(1,)
a + (2,)
(1, 2)
  • 차이점4: (의미가 명확할때) 튜플의 괄호는 생략가능하다.
a=1,2
a
(1, 2)

의미가 명확할때 생략해야함

1,2 + 3,4,5 
(1, 5, 4, 5)

튜플 언패킹

name,age,sex,height,weight = 'Tom',20,'M',180,70
name
'Tom'
weight
70

[예제3]: 임시변수 사용없이 두 변수의 값을 교환

a=10
b=20
a,b=b,a
a
20
b
10

[예제4]: 함수의 입력으로 튜플을 넣을때

def cal(a,b):
    print(str(a) + '+' + str(b) + '=' + str(a+b))
    print(str(a) + '-' + str(b) + '=' + str(a-b))
    print(str(a) + '*' + str(b) + '=' + str(a*b))
    print(str(a) + '/' + str(b) + '=' + str(a/b))
input=[3,4]
cal(input) # 리스트로는 불가능하다.
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-61-3191852bf0a7> in <module>
      1 ### 우리가 원하는 형태
      2 input=[3,4]
----> 3 cal(input) # 리스트로는 불가능하다.

TypeError: cal() missing 1 required positional argument: 'b'
cal(input[0],input[1])
3+4=7
3-4=-1
3*4=12
3/4=0.75
input=(3,4)
input
(3, 4)
cal(*input) # 튜플 언패킹으로는 가능하다.
3+4=7
3-4=-1
3*4=12
3/4=0.75
  • 함수를 호출할때 인수앞에 *를 붙여 튜플을 언패킹할 수 있다.

[예제6]: 플레이스홀더

idlist=[('guebin', '202112345','M','Korea'), 
        ('iu', '202154321','F','Korea'), 
        ('hodong', '201812321','M','Korea')]
for name,studentid,sex,nat in idlist: 
    print(name)
guebin
iu
hodong
for name , _ , _ , _ in idlist: 
    print(name)
guebin
iu
hodong

set형

A={'a','b','c','d'}
B={'c','d','e','f'}
A.union(B)
{'a', 'b', 'c', 'd', 'e', 'f'}
A|B
{'a', 'b', 'c', 'd', 'e', 'f'}
A.intersection(B)
{'c', 'd'}
A & B
{'c', 'd'}
A.difference(B)
{'a', 'b'}
A-B
{'a', 'b'}
a=set('hello')
a
{'e', 'h', 'l', 'o'}
for i in a:
    print(i)
o
l
e
h

순서가 좀 이상하다 $\to$ 집합은 원래 순서가 없다. $\to$ 인덱싱이 불가능하다. $\to$ 슬라이싱도 불가능

  • 집합 컴프리헨션
C={2**x for x in [1,2,3,4]}
C
{2, 4, 8, 16}

dict형

mydict={'a':[1,2,3],'b':[3,4,5]}
mydict['a']
[1, 2, 3]
mydict['a']+mydict['b']
[1, 2, 3, 3, 4, 5]
mydict[0] # 인덱싱 불가능
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-88-857b2cc4f569> in <module>
----> 1 mydict[0] # 인덱싱 불가능

KeyError: 0
  • 딕셔너리 컴프리핸션
X={x:x**2 for x in [1,2,3,4]}
X
{1: 1, 2: 4, 3: 9, 4: 16}

numpy

[$\ast$] 넘파이(numpy)를 왜 써야 하는가? (1)

욕심: (1,2,3)+(2,3,4)=(3,5,7)를 계산하고 싶다.

import numpy as np 
a=np.array((1,2,3))
b=np.array([2,3,4])
a+b
array([3, 5, 7])

[$\ast$] 넘파이의 호환성

list - tuple - np.array사이에는 호환성이 좋음

list(np.array(tuple(a)))
[1, 2, 3]

[$\ast$] 넘파이(numpy)를 왜 써야하는가? (2)

넘파이를 사용하면 벡터연산과 행렬연산을 쉽게 할 수 있다.

예를들어 아래와 같은 문제가 있다고 하자.

$\begin{cases} w+2x+3y+4z=1 \\ 2w+2x+y=9 \\ x-y=4 \\ 3w+x-y+3y=7 \end{cases}$

매트릭스 형태로 위의 식을 표현하면 아래와 같다.

$\begin{bmatrix} 1 & 2 & 3 & 4 \\ 2 & 2 & 1 & 0 \\ 0 & 1 &-1 & 0 \\ 3 & 1 &-1 & 3 \end{bmatrix} \begin{bmatrix} w \\ x \\ y \\z \end{bmatrix}=\begin{bmatrix} 1 \\ 9 \\ 4 \\7 \end{bmatrix}$

양변에 $\begin{bmatrix} 1 & 2 & 3 & 4 \\ 2 & 2 & 1 & 0 \\ 0 & 1 &-1 & 0 \\ 3 & 1 &-1 & 3 \end{bmatrix}$의 역행렬을 취하면

$\begin{bmatrix} w \\ x \\ y \\z \end{bmatrix}=\begin{bmatrix} 1 & 2 & 3 & 4 \\ 2 & 2 & 1 & 0 \\ 0 & 1 &-1 & 0 \\ 3 & 1 &-1 & 3 \end{bmatrix}^{-1}\begin{bmatrix} 1 \\ 9 \\ 4 \\7 \end{bmatrix}$

from numpy.linalg import inv
A=[[1,2,3,4],[2,2,1,0],[0,1,-1,0],[3,1,-1,3]]
b=[1,9,4,7]
Aarr=np.array(A)
barr=np.array(b)
inv(Aarr) @ barr 
array([ 2.,  3., -1., -1.])
  • 인덱싱 (슬라이싱 포함)
A=np.array([[11,12,13,14,15],[21,22,23,24,25],[31,32,33,34,35]])
A
array([[11, 12, 13, 14, 15],
       [21, 22, 23, 24, 25],
       [31, 32, 33, 34, 35]])

[예제1] (3,1)에 접근하여 보자!

A[2][0]
31
A[2,0] # list와의 차이점
31

[예제4] 1행중에서 1,3,5열에 접근해보자.

A[0,[0,2,4]] #방법 1
array([11, 13, 15])
A[0][[0,2,4]] #방법 2
array([11, 13, 15])
b=(0,2,4)
A[0,b]
array([11, 13, 15])

[$\ast$] 인덱싱의 종류 ($\star\star\star$)

  1. 기본인덱싱: 인덱스, 슬라이싱을 활용
    • 예1: A[1,1]
    • 예2: A[1,0:2]
  2. 팬시인덱싱(응용인덱싱): 인덱스를 정수배열로 전달, np.ix_함수를 활용한 인덱싱, 부울값 인덱싱
    • 예1: A[0,[0,2,4]] , 정수배열 인덱싱
    • 예2: A[np.ix_(a,b)] , np.ix함수를 활용한 인덱싱
    • 예3: c[c>0] , 부울값인덱싱
  • numpy를 배우는 방법

인터넷+자동완성+contextual help

pandas

dict와 호환성이 좋은 새로운 자료형이 있는데, 그것이 바로 pandas이다.

근본적인 차이: list는 번호로, dict는 keyword로 접근한다.

  • 인덱싱, 슬라이싱 vs 맵핑 note: 리스트는 키워드로 정보검색이 불가능하다. note: 딕셔너리는 인덱스로 정보검색이 불가능하다.
d={'새로이':[30,600,4.0],
   "이서":[20,950,4.2],
   "일권":[28,950,2.3],
   "현이":[28,650,3.8]}
import pandas as pd
pd.DataFrame(d) ## 판다스자료형 = 데이터프레임을 선언하는 방법
새로이 이서 일권 현이
0 30.0 20.0 28.0 28.0
1 600.0 950.0 950.0 650.0
2 4.0 4.2 2.3 3.8
df=pd.DataFrame(d).T
df
0 1 2
새로이 30.0 600.0 4.0
이서 20.0 950.0 4.2
일권 28.0 950.0 2.3
현이 28.0 650.0 3.8

note: 이서의 정보를 알고 싶다면? (딕셔너리 느낌)

df.loc['이서']
0     20.0
1    950.0
2      4.2
Name: 이서, dtype: float64

note: 칼럼이름을 정하고 싶다면?

df.columns=['age','toeic','gpa']
df
age toeic gpa
새로이 30.0 600.0 4.0
이서 20.0 950.0 4.2
일권 28.0 950.0 2.3
현이 28.0 650.0 3.8
df.loc[:,'gpa']
새로이    4.0
이서     4.2
일권     2.3
현이     3.8
Name: gpa, dtype: float64

note: 2-3번째 칼럼을 불러오자! (넘파이느낌)

df.iloc[:,1:3]
toeic gpa
새로이 600.0 4.0
이서 950.0 4.2
일권 950.0 2.3
현이 650.0 3.8

note: 토익점수를 불러오고 싶다면?

df.loc[:,'toeic']
새로이    600.0
이서     950.0
일권     950.0
현이     650.0
Name: toeic, dtype: float64

note: age~toeic까지의 정보를 얻고 싶다면?

df.loc[:,'age':'toeic']
age toeic
새로이 30.0 600.0
이서 20.0 950.0
일권 28.0 950.0
현이 28.0 650.0

note: 새로이~일권까지의 정보를 얻고 싶다면?

df.loc['새로이':'일권',:]
age toeic gpa
새로이 30.0 600.0 4.0
이서 20.0 950.0 4.2
일권 28.0 950.0 2.3

note: 토익점수가 800보다 높은사람을 부르고 싶다면?

df.query('toeic>800')
age toeic gpa
이서 20.0 950.0 4.2
일권 28.0 950.0 2.3

note: 나이가 23보다 많고 토익점수가 800보다 높은 사람을 부르고 싶다면?

df.query('age>23 & toeic>800')
age toeic gpa
일권 28.0 950.0 2.3

Class

  • 많은 교재에서 정의를 회피함
  • 비유적 설명 , 다른 대상을 가져와서 설명
    • 클래스는 과자틀과 비슷하다. 클래스란 똑같은 무엇인가를 계속 만들어 낼 수도 있는 설계도면이고 객체란 클래스로 만든 피조물을 뜻한다. (점프투파이썬)
    • In object-oriented programming, a class is an extensible program-code-template for creating objects, providing initial values for state (member variables) and implementations of behavior (member functions or methods).`
  • 직접적 설명
    • 복제를 위한 확장가능한 프로그램 코드의 유닛

좀더 정리하여 말하면,

(1) 개념의 인지

(2) 복사하고 싶은 속성을 추림

(3) 복사가능한 어떤 틀을 만듬 (=클래스를 정의)

(4) 틀에서 인스턴스를 만든다 (=클래스에서 인스턴스를 만든다)

class MooYaHo(): ### MooYaHo라는 이름을 가진 클래스 선언 
    title="농심 무파마" ### 클래스안에서 정의된 변수1 
    img=Image.open('mooyaho1.jpg').resize((200,200)) ### 클래스안에서 정의된 변수2
    don="그만큼 맛있으시단거지" ### 클래스안에서 정의된 변수3
    def memeshow(self): ### 클래스안에서 정의된 함수*  
        print(self.title)
        display(self.img)
        print(self.don)

규칙1: 클래스내에서 함수를 선언하면 반드시 첫번째 인자는 self를 넣어야 한다. --> self가 뭘까?

규칙2: 클래스 내에서 정의한 변수 (예를들면 title, img, don)를 사용하려면

  • self.title, self.img, self.don
  • MooYaHo.title, MooYaHo.img, MooYaHo.don

클래스에서 인스턴스를 찍어내는 방법

  • 함수사용법과 비슷
  • 클래스 이름을 쓰고 콘텐츠를 구체화시키는 과정에서 필요한 입력1, 입력2를 ()에 넣는다.
  • MooYaHo의 경우는 따로 입력이 없으므로, 그냥 MooYaHo하고 입력을 비워둔다. 즉 MooYaHo()로 생성

성능1: 인스턴스에서 .을 찍고 접근할 수 있는 여러 자료들을 정의할 수 있다.

성능2:인스턴스에서 .을 찍고 쓸 수 있는 자체적인 함수(=method라고 함)를 정의할 수 있다.

  • 출력만 살짝 바꾸어서 MooYaHo2를 만들고 싶다.

--> MooYaHo의 모든 내용은 그대로 가져오고, 그 살짝만 다시 조정하면 된다.

#### 이런식으로 할 필요 없다.

class MooYaHo2(): ### MooYaHo라는 이름을 가진 클래스 선언 
    title="농심 무파마" ### 클래스안에서 정의된 변수1 
    img=Image.open('mooyaho1.jpg').resize((200,200)) ### 클래스안에서 정의된 변수2
    don="그만큼 맛있으시단거지" ### 클래스안에서 정의된 변수3
    def memeshow(self): ### 클래스안에서 정의된 함수*  
        print('☆☆☆☆☆☆['+self.title+']☆☆☆☆☆☆')
        display(self.img)
        print('형돈:'+self.don)
class MooYaHo2(MooYaHo): 
    choi='무야~~~~~호~~~!!!'
    def memeshow(self): ### 클래스안에서 정의된 함수*  
        print('☆☆☆☆☆☆['+self.title+']☆☆☆☆☆☆')
        display(self.img)
        print(self.choi)
        print('형돈:'+self.don)

__str__

__repr__

__init__

  • 상속

  • 객체임베딩(객체 내장)

Name Space

  • 전역 변수 > 클래스 변수 > 메소드 변수 > 인스턴스 변수

연산자 오버로딩

- 연산자 오버로드 핵심아이디어

  • 클래스가 일반 파이썬 연산을 재정의하는 것
  • 여기에서 연산은 단순히 더하기 빼기를 의미하는게 아니라, print(), +, [0] 와 같은 파이썬 내장문법을 모두 포괄하는 개념이라 이해하는 것이 옳다.

if문

a=11
if a<5: 
    print('a=....1,2,3,4')
elif a>10: 
    print('a=11,12,13,....')
else: 
    print('a=5,6,7,...,10')
a=11,12,13,....
a=2
if a==1: 
    print('a=1')

if만 있어도 작동한다.

for문

for i in [1,2,3,4]:
    print(i)

for i in (1,2,3,4):
    print(i)

for i in '1234':
    print(i)

1
2
3
4

- 의문

for i in ???: 
    print(i)

에서 물음표 자리에 올 수 있는 것이 무엇일까?

??? 자리에 올 수 있는 것은 dir()하여 __iter__()라는 메서드가 있는 object이다.

a=1
dir(a)

['__abs__',
 '__add__'
 .
 .
 .
 .
 .
 .
 `to_bytes']

int클래스의 인스턴스는 __iter__()가 없다!

- list, pd.DataFrame, np.array 는 모두 __iter__() 함수가 있다. 따라서 iterable한 오브젝트이다.

iterable한 오브젝트는 iterator로 만들 수 있는 특징이 있다.

iterable한 오브젝트를 어떻게 iterator로 만드는가?

L=[[1,2,3],[3,4,5]]
import pandas as pd
df=pd.DataFrame(L)
dfiter1=df.__iter__()
dfiter2=iter(df)
dfiter1?
Type:        generator
String form: <generator object RangeIndex.__iter__ at 0x000001A97812A350>
Docstring:   <no docstring>

- dfiter1은 generator라는 클래스에서 만들어진 인스턴스 오브젝트이다.

dir(dfiter1)
['__class__',
 '__del__',
 '__delattr__',
 '__dir__',
 '__doc__',
 '__eq__',
 '__format__',
 '__ge__',
 '__getattribute__',
 '__gt__',
 '__hash__',
 '__init__',
 '__init_subclass__',
 '__iter__',
 '__le__',
 '__lt__',
 '__name__',
 '__ne__',
 '__new__',
 '__next__',
 '__qualname__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__subclasshook__',
 'close',
 'gi_code',
 'gi_frame',
 'gi_running',
 'gi_yieldfrom',
 'send',
 'throw']
dfiter1.__next__()
0

for 문의 작동원리

for i in L:
    print(i)

(1) iter함수를 사용해서 L을 iterator로 만든다.

(2) iterator에서 .__next__()함수를 호출하고 결과를 i에 저장한뒤에 for문 블락안에 있는 내용(들여쓰기 된 내용)을 실행한다.

(3) StopIteration 에러가 발생하면 for 문을 멈춘다.

Liter=iter(L)
Liter.__next__()
[1, 2, 3]
Liter.__next__()
[3, 4, 5]
Liter.__next__()
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-228-6220b29182a4> in <module>
----> 1 Liter.__next__()

StopIteration: 

range()

- for문의 정석은 아래와 같이 range()를 사용하는 것이다.

for i in range(5):
    print(i)
0
1
2
3
4

- range(5)의 정체는 그냥 iterable object이다.

- 그래서 언제든지 iterator로 바꿀 수 있다.

a = range(5)
aiter=iter(a)
aiter.__next__()
0
aiter.__next__()
1

. . .

aiter.__next__()
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-238-b0a1ab28475b> in <module>
----> 1 aiter.__next__()

StopIteration: 

- ???? 자리에 iterator 자체가와도 무방할것 같다.

- 확인

L=iter([1,2,3,4])
for i in L:
    print(i)
1
2
3
4

with

f=open('test.txt')
a=f.read()
print(a)


hello
hello2
hello3


f.closed
false
f.close()
f.closed
True

f가 닫힌 상태에서는 더 이상 읽을 수가 없다.

파일을 닫지 않는다고 해서 큰 문제는 없어보이지만 그냥 닫는것이 좋다.

  • motivation

- 생각해 보니까 파일을 열면 항상 닫아야 한다.

이처럼 쌍(시작-끝)으로 수행되는 처리가 반복적으로 발생하는 경우가 있는데 그때마다 .close() 메소드 따위를 쓰는 것이 번거롭게 느껴진다.

예를들면 파일을 열었으면 적당한 동작뒤에 알아서 닫아졌으면 좋겠다는 것이다.

이러한 모티브에서 구현된 것이 with문 이다.

with open('test.txt') as g: 
    print(g.read())


hello
hello2
hello3

g.closed
True

잘 닫아졌다.

- 기본사용법

with의 사용법은 직관적으로 이해가 가능하지만 그래도 다시한번 살펴보자.

with blabla as variable: 
    yadiyadi
    yadiyadi2

(1) with blabla as variable에서 blabla가 실행된다.

(2) blabla의 실행결과로 어떠한 특별한 오브젝트가 만들어지는데 그 오브젝트를 우리가 variable로 부르기로 한다.

(3) 탭으로 들여쓰기된 부분, 즉 yadiyadi, yadiyadi2 가 순서대로 실행된다.

(4) 탭으로 들여쓰기된 부분이 실행되고 난 뒤에 g.closed() 따위의 미리 약속된 어떠한 코드가 실행되는것 같다.

- 동작원리

비밀은 __enter____exit__ 메소드에 있다.

(for문 복습) for i in ...: 에서 ...에 올 수 있는 오브젝트는 __iter__ 메소드가 정의되어 있어야 한다. 이러한 오브젝트를 iterable한 오브젝트라고 한다.

(with문) with ... as variable: 에서 ...의 실행결과로 생성되는 오브젝트는 __enter____exit__ 메소드가 정의되어 있어야 한다.

  • 이중 __enter__는 with문이 시작되면 자동으로 실행된다.
  • 이중 __exit__는 with문이 끝나면 자동으로 실행된다.

- 예제

class MooYaHo:
    def __init__(self):
        print('init')
    def __enter__(self):
        print('무야호')
    def __exit__(self,exc_type,exc_value,traceback): # self 이외의 3가지 변수는 예외처리에 관련된 변수인데 여기서는 다루지 않음. 
        print('그만큼 신나시는거지')
with MooYaHo() as a: 
    print('.')
init
무야호
.
그만큼 신나시는거지

함수

  • 함수도 객체다
def myadd(a,b):
    return a+b 
myadd(1,2)
3
?myadd
Signature: myadd(a, b)
Docstring: <no docstring>
File:      c:\users\owner\파이썬입문\<ipython-input-250-e383cb6c2c80>
Type:      function

- Type이 function이다?

- myadd 는 function class의 instance이다.

- 결국 myadd 역시 하나의 오브젝트에 불과하다.

higher-order function

myadd(1,2)
3

myadd의 입력 1,2는 int class의 인스턴스 오브젝트였음.

즉 문법의 논리로 보면 함수의 입력에 들어갈 수 있는것은 오브젝트이면 된다.

그런데 함수 자체도 오브젝트이다 $\to$ 함수도 함수의 입력으로 쓸 수 있다?

- 예제1

def calc(fun,a,b):
    return fun(a,b)
calc(myadd,-3,3)
0

이처럼 함수자체를 입력으로 받거나 출력으로 보내는 함수를 higher-order function이라고 한다.