심파이를 가장 간단하게 실행해 볼 수 있는 방법은 live.sympy.org 에 접속하는 것이다. 이 페이지에 접속하면 심파이의 최신 버전이 임포트된 파이썬 쉘을 사용할 수 있다.


[그림 1] live.sympy.org의 접속 화면


맨 처음 접속했을 때 상단에 보면 다음과 같이 미리 실행되는 명령들이 있다.


These commands were executed:
>>> from __future__ import division
>>> from sympy import *  
>>> x, y, z, t = symbols('x y z t')
>>> k, m, n = symbols('k m n', integer=True)
>>> f, g, h = symbols('f g h', cls=Function)


 미리 실행되는 이  명령들에 의해서 심파이 모듈이 글로벌 환경에 임포트되어 있고 또한  변수 x, y, z, t 는 심파이의 대수 기호로 사용할 수 있다. 그리고 k, m, n은 정수 대수 기호 그리고 f, g, h 는 함수 기호로 바로 사용할 수 있다.


 만약 윈도를 사용하고 있고 로컬PC에서 심파이를 실행하고 싶다면 winpython을 사용하면 된다. 이 패키지는 파이썬과 필요한 모듈들이 대부분 포함되어 있으며 설치방식이 아니라 단순히 압축을 푼 후 실행하는 방식 (포터블)이라 사용하기 용이하다. 파이썬 2.x버전, 3.x 버전 각각 별도로 그리고 윈도 32bit, 64bit 버전별로 배포본이 마련되어 있다. 자기 환경에 맞는 것을 선택하여 다운로드하면 된다.


필자는 winpython 3.4.3.2 버전을 다운로드 받아서 실행하였다. 그러면 그 실행 파일의 하위 폴더에 다음과 같은 파일들이 생성되어 있다. 그 후 Spyder.exe를 실행하면 된다.


[그림 2] winpython의 설치 폴더


Spyder 가 실행된 후 Tools>Preferences 메뉴에서 다음 그림과 같은 항목을 체크한 후 ipython쉘을 실행시키면 바로 sympy를 사용할 수 있다.

[그림 3] winpython에서 sympy를 기본으로 실행시키기


이제는 로컬PC에서 ipython과 sympy를 사용할 수 있다.

[그림 4] winpython에서 ipython console을 실행시킨 화면



Posted by 살레시오
,

 다음 표는 산술/논리 연산에 관련된 내장 함수들이다.


[표 1] 산술/논리 연산에 관련된 내장 함수들

hex(n)

oct(n)

bin(n)

정수 n의 16진수 값을 구해서 ‘문자열’로 반환한다.

정수 n의 8진수 값을 구해서 ‘문자열’로 반환한다.

정수 n의 2진수 값을 구해서 ‘문자열’로 반환한다.

abs(n)

절대값을 구한다. 복소수의 경우 크기를 구한다.

pow(x,y[,z])

거듭제곱을 구한다. pow(x,y)은 x**y 와 같다.

divmod(a,b)

a를 b로 나눈 (몫, 나머지)를 구한다. 튜플 반환.

all(iterable)

any(iterable)

iterable 의 모든 요소가 True 일 경우 True를 반환.

iterable 의 하나 이상의  요소가 True 일 경우 True를 반환.

max(iterable)

max(arg1, arg2, …)

최대값을 구한다.

min(iterable)

min(arg1, arg2, …)

최소값을 구한다.

round()

반올림을 한다.


hex(), oct(), bin() 함수는 각각 ‘0x’, ‘0o’, ‘0b’ 로 시작하는 ‘문자열’로 결과를 반한한다. 이 문자열을 파이썬 값으로 변환하려면 eval()함수를 이용하면 된다.



Posted by 살레시오
,

 다음은 열거형(sequence)의 정보를 얻는 내장 함수들이다.


[표 1] 열거형의 정보를 얻는 내장 함수들

함수명

기능

len(seq)

시퀀스형을 받아서 그 길이를 반환한다.

iter(obj [,sentinel] )

next(iterator)

객체의 이터레이터(iterator)를 반환한다.

이터레이터의 현재 요소를 반환하고 포인터를 하나 넘긴다.

enumerate(iterable, start=0)

이터러블에서 enumerate 형을 반환한다.

sorted(iterable[,key][,reverse])

정렬된 *리스트*를 반환

reversed(seq)

역순으로 된 *iterator*를 반환한다.

filter(func, iterable)

iterable의 각 요소 중 func()의 반환값이 참인 것만을 묶어서 이터레이터로 반환.

map(func, iterable)

iterable의 각 요소를 func()의 반환값으로 매핑해서  이터레이터로 반환.


iter()은 seq형으로부터 이터레이터를 반환하는 함수이다. next()는 이터레이터의 현재 요소를 반환하고 이터레이터의 포인터를 그 다음 요소로 넘기는 함수이다.


enumerate()은 시퀀스로부터 enumarate형을 반환한다. 이것은 인덱스와 해당 값의 튜플을 반환하는 이터레이터를 가진다.


>>> seasons = ['spring','summer','fall','winter']
>>> list(enumerate(seasons))
[(0, 'spring'), (1, 'summer'), (2, 'fall'), (3, 'winter')]
>>> list(enumerate(seasons, start=1))
[(1, 'spring'), (2, 'summer'), (3, 'fall'), (4, 'winter')]


보통은 for 문과 같이 사용되어서 반복문 안에서 이터러블의 요소값 뿐만 아니라 그 인덱스 정보도 필요할 경우 편리하게 사용할 수 있다.


>>> seasons=['spring','summer','fall','winter']
>>> for i,v in enumerate(seasons):
 …:    print("%s:%s"%(i,v))
  
0:spring
1:summer
2:fall
3:winter


filter(func, iterable)는 함수와 이터러블을 입력으로 받아서 이터러블의 요소가 하나씩 함수에 인수로 전달될 때, 참을 반환시키는 것만을 따로 모아서 이터레이터로 반환하는 함수이다.


 다음 예를 살펴보자.


def positive(l):
   result = []
   for i in l:
       if i > 0:
     result.append(i)
   return result

>>> print(positive([1,-3,2,0,-5,6]))
[1, 2, 6]


위의 positive함수는 리스트를 입력값으로 받아서 각각의 요소를 판별해 양수값만 따로 리스트에 모아 그 결과값을 돌려주는 함수이다.


 filter()함수를 이용하면 아래와 같이 똑같은 일을 동일하게 구현할 수 있다.


>>> def positive(x):
…      return x > 0
>>> print(list(filter(positive, [1,-3,2,0,-5,6])))
[1, 2, 6]


filter() 함수는 첫 번째 인수로 함수명을, 두 번째 인수로는 그 함수에 차례로 들어갈 이터러블(리스트, 터플, 문자열 등)을 받는다. filter 함수는 두 번째 인수인 이터러블의 각 요소들이 함수에 들어갔을 때 리턴값이 참인 것만을 이터레이터로 묶어서 돌려준다. 위의 예에서는 1, 2, 6 만이 양수로 x > 0 이라는 문장이 참이 되므로 [1, 2, 6]이라는 결과 값을 돌려주게 된다.


익명함수(lambda)를 쓰면 더욱 간편하게 쓸 수 있다.


>>> list(filter(lambda x: x > 0, [1,-3,2,0,-5,6]))
[1, 2, 6]


 filter()와 유사한 map() 함수가 있다. 이것은 함수와 이터러블을 입력으로 받아서 각각의 요소가 함수의 입력으로 들어간 다음 나오는 출력값을 묶어서 이터레이터로 돌려주는 함수이다. 만약 어떠 리스트의 모든 요소의 제곱값을 갖는 새로운 리스트를 만들고 싶다면 다음과 같이 하면 된다.


>>> a = [2, 3, 4, 7, 8, 10]
>>> a2 = list(map(lambda x:x**2, a))
[4,9,16,49,64,100]


파이썬 2.7은 filter()와 map()의 결과가 리스트이므로 위 예에서 list함수를 이용하여 리스트로 변환하지 않아도 된다. 파이썬 3.x에서는 이들 함수의 반환값이 리스트가 아닌 반복형(iterable)이므로 이것을 리스트로 만들기 위해서는 list()함수를 명시적으로 사용해야 한다.



Posted by 살레시오
,

  이전 포스트에서 객체를 생성하는 것이 외형상으로 함수를 호출하는 것과 유사하다고 했는데, 사실 객체를 생성할 때 클래스의 __init__() 메소드를 호출하게 된다. 이 메쏘드는 다음과 같이 사용자가 정의할 수 있다.


class 클래스명:
def __init__(self):
메소드 본체


이 예에서 __init__(self) 메쏘드는 객체를 생성할 때 자동으로 호출되는 특수한 메소드이고 반드시 첫 번째 인자는 self 이어야 한다. 이 메쏘드 내부에 클래스 변수를 생성할 수 있다.


class Robot:
   def __init__(self):
       self.nLegs = 2
       self.nArms = 2


이제


>>> asimo = Robot()


이라고 Robot객체를 생성하면 nLegs 와 nArms 필드가 생성되고 초기화 되었음을 알 수 있다.


>>> asimo.nLegs
2
>>> asimo.nArms
2


객체의 필드를 확인하고 싶다면 내장 함수 vars()를 이용하면 된다.


>>> vars(asimo)
{'nLegs': 2, 'nArms': 2}


이 내장 함수는 사실 객체의 __dict__ 내부 필드를 반환한다. 이 내부 필드에 객체의 필드들이 딕셔너리의 요소로 저장되어 있다.


객체를 생성할 때 이름을 사용자가 입력하도록 하려면 다음과 같이 __init__() 메소드에 일반 인자를 self 뒤에 주면 된다.


class Robot:
   def __init__(self, name):
       self.nLegs = 2
       self.nArms = 2
       self.name = name


이제 객체를 생성할 때 이름을 반드시 입력해야 한다.


>>> asimo=Robot('asimo')
>>> asimo.name
'asimo'


만약 이름이 주어지지 않았을 때 ‘dummy’ 라는 이름을 주고 싶다면 다음과 같이 기본값 인자를 사용하면 된다.


class Robot:
   def __init__(self, name=’dummy’):
       self.nLegs = 2
       self.nArms = 2
       self.name = name

    

이제 객체를 생성할 때 이름을 입력하지 않아도 된다.


>>> asimo=Robot()

>>> asimo.name

'dummy'


이와 같이 __init__() 생성자 함수도 파이썬의 일반 함수처럼 가변 개수 인자, 기본값 인자, 키워드 인자 등을 적용할 수 있다.



Posted by 살레시오
,

 파이썬은 클래스를 지원하므로 객체 지향적인 프로그래밍을 할 수 있다. 사실 지금까지 다뤄온 기본 자료형도 다 클래스이다. 클래스는 새로운 자료형을 정의하는 것이고 객체(object)는 클래스의 인스턴스(instance, 클래스가 구체화된 것)를 의미한다.


클래스는 다음과 같이 정의한다.


class 식별자:
클래스 본체


보통 클래스의 식별자는 대문자로 시작한다. 예를 들어 Person, Robot, Car, Point 등이다. 클래스 본체는 이 클래스에 속하는 변수와 함수를 정의하게 된다. 특별히 클래스에 속한 변수들을 필드(field), 클래스에 속한 함수들을 일반 함수들과 구분하기 위해서 메소드(method)라고 부르며 이 둘을 통칭하여 속성(attribute)라고 한다.


이 용어들에 대해서는 숙지해 두는 것이 좋다.


  • 필드 (field) : 클래스에 내장된 변수

  • 메쏘드 (method) : 클래스에 속하는 함수

  • 속성 (attribute) : 필드와 메쏘드를 통칭하여 속성이라 한다.


가장 간단한 형태의 클래스를 다음과 같이 정의해 보자.


class Robot:
pass


이 클래스는 보면 알겠지만 본체가 없다. 이 클래스의 인스턴스를 생성하려면 다음과 같이 하면 된다.


>>> asimo = Robot()


이제 asimo 는 Robot 클래스의 객체가 되었다. 이와 같이 어떤 클래스의 객체(인스턴스)를 생성하려면 다음과 같이 한다.


변수명 = 클래스명()


마치 함수를 호출하는 것과 유사하다.



Posted by 살레시오
,

 다음은 기본 자료형의 생성과 변환에 관련된 내장 함수들이다.


[표 2] 기본 자료형의 생성과 변환에 관련된 내장 함수들

함수명

기능

object()

새로운 object (모든 객체의 base)를 생성한다.

bool(obj)

객체의 진리값을 반환한다.

int(obj)

문자열 형태의 숫자나 실수를 정수로 변환한다.

float(obj)

문자열 형태의 숫자나 정수를 실수로 변환한다.

complex(re [, img])

문자열이나 주어진 숫자로 복소수를 생성한다.

str(obj)

객체를 출력할 수 있는 문자열로 반환한다.

list(seq)

시퀀스형을 받아서 같은 순서의 리스트로 만들어 반환한다,

tuple(seq)

시퀀스형을 받아서 같은 순서의 튜플로 만들어 반환한다,

range(stop)

range(start,stop[,step])

0부터 stop-1 까지의 sequence 반환

start부터 stop-1 까지 (step은 간격) sequence 반환

set(seq)

시퀀스형을 받아서 같은 순서의 집합(set)으로 만들어 반환한다,

frozenlset()


bytes()


bytearray()


memoryview()


dict(**kwarg)

시퀀스형을 받아서 딕셔너리로 만들어 반환한다,

(음영진 부분은 seq 형이다.)


다음은 기본 자료형의 정보를 얻는 내장 함수들이다.


[표 2] 기본 자료형의 정보를 얻는 내장 함수들

함수명

기능

type(obj)

객체의 형을 반환한다.

dir(obj)

객체가 가진 함수와 변수들을 리스트 형태로 반환한다.

repr(obj)

ascii(obj)

evla()함수로 다시 객체를 복원할 수 있는 문자열 생성

repr()과 유사하나 non-ascii 문자는 escape한다.(?)

id(obj)

객체의 고유번호(int형)을 반환한다.

hash(obj)

객체의 해시값(int형)을 반환. (같은 값이면 해시도 같다.)

chr(num)

ord(str)

ASCII 값을 문자로 반환

한 문자의 ASCII 값을 반환

isinstance(obj, className)

객체가 클래스의 인스턴스인지를 판단한다.

issubclass(class, classinfo)

class가 classinfo 의  서브클래스일때 True 반환

classmethod()


staticmethod()


callable(obj)

obj가 호출 가능한 객체면 True반환 (ver 3.2에서 다시 도입)

getattr(obj, name)

setattr(obj,name,val)

delattr(obj,name)

hasattr(obj,nema)

obj의 attrubue (name) 를 얻는다.

obj의 attrubue (name) 를 설정한다.

obj의 attrubue (name) 를 삭제한다.



Posted by 살레시오
,

 파이썬의 내장 함수는 import 하지 않고 즉시 사용 가능한 함수들이다. 내장 함수명은 일종의 키워드로 간주하여야 하며 사용자의 식별자로 사용하는 것은 피하여야 한다.


 이하 표에서 대괄호 [ ..]로 표시된 것은 ‘생략 가능함’을 나타내는 것이다.


[표 1] 기본 입출력과 관련된 파이썬 내장 함수들

함수명

기능

print(x)

객체를 문자열로 표시한다.

input([prompt])

사용자 입력을 문자열로 반환한다.

help([x])

x에 대한 도움말을 출력한다.

globals()

전역 변수의 리스트를 반환한다.

locals() 혹은 vars()

vars(obj)

지역 변수의 리스트를 반환한다.

__dict__ 어트리뷰트를 반환한다. (객체의 내부 변수가 저장된 딕셔너리)

del(x) 혹은 del x

객체를 변수 공간에서 삭제한다.

eval(expr)

값을 구한다.

exec(obj)

파이썬 명령을 실행시킨다.

open(filename[,mode]))

파일을 연다


eval()함수는 파이썬 표현식을 실행해서 결과값을 얻는 함수이다.


>>> x = 1
>>> eval('x+1')
2


반면 exex()함수는 파이썬 프로그램 조각을 입력 받아서 파싱(parsing)한 후 실행시키는 함수이다. 파이썬 코드를 문자열로 넘겨줄 수도 있고 파일 객체를 넘겨줄 수도 있다.


>> a=10
>>> exec('b=a+10')
>>> b
20


open()함수는 존재하는 파일을 열거나 새로 파일을 생성하여 file객체를 반환해 주는 함수이다.


>>> f = open(‘test.txt’) # 존재하는 test.txt 파일을 연다.


위와 같이 mode 인자가 생략되면 읽기 모드인 ‘r’ 로 기본 설정된다. 모드는 다음과 같은 것이 있다.


[표 2] 내장함수 open()의 mode 옵션

mode

기능

‘r’

‘w’

‘x’

‘a’

읽기 모드로 연다 (기본값)

쓰기 모드로 연다. 기존 내용이 있다면 삭제됨

독점 모드로 파일을 생성한다. 기존 파일이 있다면 오류 발생

쓰기 모드로 연다. 기존 내용에 이어서 첨가하는 모드이다.

‘b’

‘t’

바이너리 모드(파일 내용이 bytes 객체로 반환됨)

텍스트모드(기본값, 파일 내용이 str 객체로 반환됨)

‘+’

내용을 갱신하기 위해서 파일을 연다.(읽기/쓰기)



Posted by 살레시오
,

 익명 함수(lambda function)란 말 그대로 이름이 없는 함수이며 파이썬에서는 lambda 라는 키워드로 익명 함수를 정의할 수 있다. 주로 비교적 간단한 기능의 함수가 컨테이너의 요소로 들어가는 경우 혹은 다른 함수의 인자로 함수를 넘겨줄 필요가 있을 때 사용된다.


익명 함수는 다음과 같이 생성된다.


lambda 인자1,인자2, … : 표현식


익명 함수는 보통 한 줄로 정의된다. return문도 없으며 단지 인자들과 반환값들의 관계식으로만 표현된다. 예를 들어 두 수의 합을 반환하는 익명 함수는 다음과 같다.


>>> add = lambda a, b : a+b
>>> add(1,2)
3


이 익명 함수는 다음과 같이 일반 함수를 정의하는 것과 동일하다.


>>> def add(a, b) :
…..      return a+b
>>> add(1,2)
3


그렇다면 일반 함수와 익명 함수와의 차이점은 무엇인가? 익명 함수의 기능은 일반 함수보다도 훨씬 제한적이고 익명 함수로 할 수 있는 것은 일반 함수로도 모두 할 수 있다. 그렇다면 왜 익명 함수를 사용할까?


때로는 굳이 번거롭게 일반 함수를 정의할 필요가 없는 간단한 기능만을 구현해도 되는 경우가 있다.  예를 들어서 입력 인수가 0보다 크면 True를 반환하는 함수를 생각해 보자.


>>> def pos(x):
…..    return x>0
>>> list(filter(pos, range(-5,6)))
[1,2,3,4,5]


이것을 익명 함수를 이용하면 다음과 같이 간단하게 처리할 수 있다.


>>> list( filter(lambda x:x>0, range(-5,6)) )
[1,2,3,4,5]


또는 다음과 같이 간단한 함수들을 리스트의 요소로 지정할 경우도 있을 것이다.


>>> fl = [lambda x,y:x+y, lambda x,y:x*y]
>>> fl[0](1,2)
3
>>> fl[1](3,4)
12


이와 같이 람다 함수의 용도는 보다 간결하게 원하는 기능을 수행할 수 있도록 하는 것이다.



Posted by 살레시오
,

 키워드 인자(keyword parameter)는 함수를 호출할 때 인자의 값 뿐만 아니라 그 이름까지 명시적으로 지정해서 전달하는 방법이다. 만약 기본 인자가 세 개인 다음과 같은 간단한 함수가 있다고 가정하자.


def add(a=0, b=0, c=0):
   return a+b+c


이 함수를 호출하는 방법은 다음과 같은 것들이 있다.


>>> add()
0
>>> add(11) # a에 11이 대입됨
11
>>> add(11,22) # a에 11, b에 22가 대입됨
33
>>> add(11,22,33) # a에 11, b에 22, c에 33이 대입됨
66


   ··············································································································

   ··············································································································


여기서 보듯이 인자의 순서대로 기본값 인자가 결정된다. a만, 혹은 a와 b에만 원하는 값을 대입하는 것은 문제가 없다. 그런데 만약 a와 b는 기본 인자 그대로 사용하고 c에만 다른 값을 넣어주고 싶을 때는 어떻게 해야 할까? 이런 경우 호출하는 쪽에서 변수명(키워드)를 지정하면 된다.


   ··············································································································

>> add(c=33) # c에만 33이 대입된다.

>> add(c=33, b=22) #c에 33, b에 22가 대입된다.

   ··············································································································


이와 같이 키워드 인자값을 넘겨줄 때에는 함수 정의부의 인자 순서와 상관 없이 나열할 수 있다.

기본값 인자와 마찬가지로 키워드 인자는 함수 정의시에 일반 인자(standard argument) 뒤에 와야 한다.


def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
   print("-- This parrot wouldn't", action)
   print("if you put", voltage, "volts through it.")
   print("-- Lovely plumage, the", type)
   print("-- It's", state, "!")


이 함수는 일반 인자(voltage) 하나와 세 개의 기본 인자(state, action, type)을 가지고 있다. 이 함수는 다음과 같이 호출될 수 있다.


parrot(1000)
parrot(voltage=1000)
parrot(voltage=1000000, action='VOOOOOM')
parrot(action='VOOOOOM', voltage=1000000)
parrot('a million', 'bereft of life', 'jump')
parrot('a thousand', state='pushing up the daisies')


하지만 다음과 같이 호출할 수는 없다.


parrot()                     # 일반 인자값 없음
parrot(voltage=5.0, 'dead')  #키워드 인자 뒤에 일반 인자값을 주지 못함
parrot(110, voltage=220)     # 한 인자에 두 값을 주지 못함
parrot(actor='John Cleese')  # actor라는 키워드가 없음


함수 호출할 때에도 키워드 인자는 일반 인자 뒤에 와야 한다. 또한 키워드 인자로 넘겨지는 것은 반드시 함수 정의에서 매칭되는 변수가 있어야 하며 호출하는 순서는 중요하지 않다.


만약 함수 정의부에 **kwargs 와 같은 형태의 인자가 있다면 kwargs는 딕셔너리 형태로 키워드 인자들 중에서 일반 인자가 아닌 것들을 넘겨 받는다. 만약 가변 개수 인자 *args 와 혼용하는 경우에는 반드시 이것 뒤에 와야 한다.


def f(a, *args, **kwargs):
   print('a=',a)
   print('args=',args)
   print('kwargs=',kwargs)


이 함수는 다음과 같이 호출될 수 있다.


>>> f(11)
a= 11
args= ()
kwargs= {}
>>> f(11,22,33)
a= 11
args= (22, 33)
kwargs= {}
>>> f(11,22,33,b=44,c=55)
a= 11
args= (22, 33)
kwargs= {'c': 55, 'b': 44}


이 예에서 보듯이 반드시 일반 인자(a), 가변 개수 인자(*args), 키워드 인자(**kwarg) 의 순으로 나열되어야 함을 주의하자.



Posted by 살레시오
,

 파이썬 함수의 기본값 인자(default parameter)란 함수를 호출할 때 인자의 값을 설정하지 않아도 기본값이 할당되도록 하는 기능이다. 기본값은 함수를 정의할 때 지정해준다. 예를 들어 보자.


def funcA(a=10):
   print('a='+str(a))


이 함수는 다음과 같이 두 가지 방법으로 호출할 수 있다.


>>> funcA() # a에 기본값인 10이 자동으로 저장된다.
a=10
>>> funcA(20) #a에 20이 전달된다.
a=20


이 예에서 인자 a는 기본값 인자이고 호출하는 쪽에서 값을 주지 않으면 기본적으로 10 값을 갖게 된다. 그래서 funcA()와 같이 값을 주지 않으면 10이 출력되고 funcA(20)과 같이 값을 주면 그 값이 인자 a 로 전달되는 것이다.


 다른 예를 들어 보자.


def printName(firstName, secondName='Kim'):
   print('My name is '+ firstName +' ' + secondName +'.')


이 함수도 다음과 같이 두 가지 방법으로 호출 가능하다.


>>> printName('Jang-Hyun')
My name is Jang-Hyun Kim.
>>> printName('Jang-Hyun', 'Park')
My name is Jang-Hyun Park.


기본값 인자는 값을 생략해서 호출할 수 있지만 일반 인자는 반드시 값을 지정해 주어야 한다. 따라서 printName()함수를 호출할 때 첫 문자열은 반드시 정해서 넘겨주어야 한다. 여기에서 printName()함수의 두 번째 인자를 입력하지 않으면 기본적으로 ‘Kim’으로 지정된다. 두 번째 인자를 명시적으로 지정하면 그것이 secondName 으로 지정된다.


 한 가지 주의할 점은 일반 인자와 기본값 인자가 같이 올 때에는 반드시 기본값 인자는 뒤에 와야 한다는 점이다. 즉, 아래와 같이 정의하면 오류가 발생한다.


>>> def printName(firstName='Kim', secondName):


기본값 인자가 두 개 이상일 때에서도 항상 일반 인자 뒤에 와야 한다.


>>> def add(a, b=0, c=0):
...     return a+b+c
...
>>> add(1)
1
>>> add(1,2) # b에 2가 들어간다.
3
>>> add(1,2,3) # b에 2, c에 3이 들어간다.)
6


이 예에서 보듯이 함수를 호출할 때 주는 순서 대로 기본값 인자에 값이 할당 됨을 알 수 있다.


 또 한 가지 주의할 점은 기본 인자는 최초의 호출 시에만 지정된 값으로 초기화 되고 이후의 호출에서는 그렇지 않다는 점이다. 따라서 리스트나 딕셔너리와 같은 가변(muatble) 객체를 기본 인자로 사용할 때 문제가 된다.


>>> def f(a, L=[]):
...     L.append(a)
...     return L
...
>>> f(1)
[1]
>>> f(2)
[1, 2]
>>> f(3)
[1, 2, 3]


이 예제를 보면 기본 인자 L은 최초의 호출에서만 빈 리스트로 초기화 되고 그 이후의 호출에서는 그 내용물은 유지된다. 따라서 리스트의 요소가 축적되는 것이다. (마치 C/C++에서의 static 변수와 비슷한 동작을 수행한다.)


 후속 호출에도 mutalbe 객체를 초기화하려면 다음과 같은 방법으로 코딩하면 된다.


def f(a, L=None):
   if L is None:
       L = []
   L.append(a)
   return L


이 경우 실행 결과는 다음과 같다.


>>> f(1)
[1]
>>> f(2)
[2]
>>> f(3)
[3]




Posted by 살레시오
,