1월, 2019의 게시물 표시

Python - Collection의 defaultdict 에 관한 공부

default dict는 dictionary를 생성할 때 아주 유용한 모듈. d = defaultdict(any_def, (기본값으로 쓸)key=value) d[any_key] => d[any_key]를 호출하면 1) 이미 any_key에 해당하는 value 값이 있을 땐 값을 return 2) any_key 값이 없을 땐 새로이 any_key라는 key를 배정하면서 'any_def' 실행의 결과값을 value로 set함 EXAMPLE )))) def hello(): return "world" d = defaultdict(hello, a=[1,2,3]) d() ==> d = {a: [1,2,3]} d["depth1"] ==> d = {a:[1,2,3], "depth1" : "world"} d["depth1"] = "depth1_value" ==> d = {a:[1,2,3], "depth1" : "depth1_value"}

Python 함수의 기본값은 상수 혹은 None이어야 한다

파이썬에서 함수 선언부는 런타임에 한 번만 실행된다. 따라서 함수에 기본값을 넣을 때는 주의해야 한다.  (그냥 반드시 상수를 넣자고 생각하는 게 맘 편하고, 오류가 더 적을 것 같다) 문제 있는 코드 1) from datetime import datetime def log (msg , dt=datetime.now()): print ( "{}: {}" .format(dt , msg)) def는 한 번 실행되고 그 이후엔 메모리에 상주하기 때문에 이 때 dt는 항상 같은 값(log 함수가 만들어진 시점의 time)만 출력된다. 따라서 아래와 같이 변해야한다. 개선 된 코드 1) def log2 (msg , dt= None ): dt = dt or datetime.now() print ( "{}: {}" .format(dt , msg)) 기본값은 None을 가리킨다. 함수 실행시 keyword argument로 dt값이 있으면 dt값을 쓰고 dt값이 없으면 datetime.now()를 호출한다. 다음으로는 Mutable한 객체가 함수의 기본값일 때 생기는 문제이다. 문제 있는 코드 2) my_list = [ 1 , 2 , 3 ] def log3 (msg=my_list): print (msg) 이 경우엔 my_list의 refence가 넘어가는거라 my_list가 변경이 되면 msg의 기본값도 변하게 된다. 예를들어 그냥 log2()를 실행하면 [1,2,3]을 출력하지만 my_list.append(4)를 실행한 후에 log2()를 실행하면 [1,2,3,4]가 출력된다. 이는 기본 값이 Mutable한 객체이기 때문에 발생하는 문제다. 개선 된 코드 2) 따라서 [1,2,3]을 출력하고 싶으면 아래와 같이 하거나 def log3 (msg=[ 1 , 2 , 3 ]): print (msg) 혹은 Immu...

Python 함수의 parameter에 관하여

먼저 중요한 것은 아니지만 용어 설명을 하면 Argument : 함수 바깥의 scope에서 함수에 전달 된 인자 Parameter : 함수 안쪽의 scope에서 함수에가 전달 받은 인자 코드로 봐야 이해가 쉽다. def func ( a , b ): << a , b는 parameter print (a , b) x= 10 y= 20 func(x , y) << x , y는 argument 근데 어쨌든 이름만 약간씩 다를 뿐이지 변수들이 pointing하고 있는 것은 똑같다. 그러니 대충 개념만 알아두고 argument, parameter 너무 신경쓰지 말고 call 하자! 어쨌든 알쏭달쏭했던 파이썬 함수의 parameter에 *가 있으면 알쏭달쏭했는데 이번 기회에 공부했고 결과물이 아래있다. def func (a , b , *c): print (a , b , c) # 최소 두 개의 인자 (a, b) 는 받고 나머지 인자들은 모두 선택적으로 취한다 . def func (a , b= 10 , *c): print (a , b , c) # 최소 한 개의 Positional arg(a)는 무조건 받고 선택적으로 b 를 받는다 . # 두 번째 인자는 b 에 할당하지만 값이 없으면 b 는 자동으로 2 가 된다 . # b 는 디폴트로 냅둔 채 a 와 c 배정 하는 것은 불가능하다 . # 이 땐 func(1, 10, ...)와 같이 b를 명시적으로 할당 해주어야 한다. # func(1, 20, b=3) < 이렇게 해도 안 된다. (b에게 두 개의 값을 가리키라고 하는 것이기 때문) def func (a , * , b , c): print (a , b , c) # 딱 한 개의 Positional arg를 받고 이를 a 에 할당한다 . # 그 뒤에 인자를 두 개 더 할당 받는데 이는 반드시 b,c 키워드 인자이다 . # * 의 의미는 여기까지가 position...

Python Extended Unpacking

# Extended Unpacking 기억하면 좋을 것 Left Hand Side(LHS)에서 *의 의미는 보통 우측변에 있는 Iterable을 리스트로 묶어서 취하는 것. Right Hand Side(RHS)에서 *의 의미는 해당 Iterable의 값을 unpack 하는 것. s = [1,2,3,4] *c, = s    # c = [1,2,3,4] --> s를 리스트로 묶어서 취함 c = *s     # c = [*s] --> s를 unpack함 l = [1,2,3,4,5] a, *b = l # can apply to all iterable even dict/set l1 = [1,2,3] l2 = [4,5,6] l = [*l1, *l2] set s1 = "abc" s2 = "cde" l = {*s1, *s2} # "a","b","c","d","e" s1 = {1,2,3} s2 = {3,4,5} s3 = {5,6,7} s4 = {7,8,9} s = {*s1, *s2, *s3, *s4} dict d1 = {"key1":1, "key2":2} d2= {"key2":3, "key4":4} {*d1, *d2} ==> {'key2', 'key4', 'key1'} {**d1, **d2} ==> {'key1': 1, 'key2': 3, 'key4': 4} {**d2, **d1} ==> {'key2': 2, 'key4': 4, 'key1': 1} 키가 겹치는 경우 나중에 쓰이는 놈의 밸류가 오버로드 된다. Nested Unpack a,b,(c,d) = [1,2,...

Python 진수 변환기 만들기

파이썬에는 10진수를 2진수, 8진수, 16진수로 바꿔주는 builit-in function들이 있다. (bin, oct, hex) 하지만 2, 8, 16진수 외 진수 변환기는 없기 때문에 나머지는 직접 구현해야 한다. 숫자와 알파벳을 이용하여 진수 변환기를 구현해본다. 먼저 1) N진수의 각 자리 수가 가질 수 있는 최대값은 N-1이다. 예를 들어, 2진수는 각 자리 수의 Max값은 죽었다 깨나도 1이다. 10진수의 경우에 각 자리 수의 Max값은 죽었다 깨나도 9라는 것이다. 그래서 0~Z를 (알파벳의 case 고려하지 않았을 때) 우리가 최대로 표현할 수 있는 N진수는 36진수가 된다. 실제 진수 변환기 코드는 아래와 같다. def rebase_from10 (number , base): digit_map = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" if base < 2 or base > 62 : raise ValueError ( "Value must be in range of 2 and 62" ) sign = - 1 if number < 0 else 1 number *= sign digit = [] while number > 0 : number , modular = divmod (number , base) # number 를 base 로 나눴을 때 몫과 나머지를 구하고 몫은 을 다시 number 변수에 할당한다 . digit.insert( 0 , modular) # base 를 digit 의 0 번째 index 에 insert 한다 . ( 이유는 10 진수를 N 진법으로 변환했을 때 계산식을 찾아보시길 ) if sign - 1 : return "-" + "" .join([di...

Python의 Integer operation (div, mod, //, % 에 관하여)

Integer Operation 중 기본적인 연산은 우리의 예상결과와 다르지 않다. Int + Int = Int (type : Int) Int - Int = Int (type : Int) Int * Int = Int (type : Int) 하지만 신기한 건 Int / Int = Int (type : Float)이 된다. (나머지 없이 몫이 정수라 할 지라도) 나머지 관련 메소드, 연산에 대해 좀 더 알아보자. 보통 많이들 쓰는 연산자인 // 와 %는 실무 코딩에서도 꽤 유용하게 쓰인다. 하지만 // 를 그저 "어떤 수를 다른 수로 나눈 몫" 이라고만 알면 반만 알고 있는 것이다. 또한, %를 그저 "어떤 수를 다른 수로 나누었을 때 나머지" 라고만 알면 이것 또한 반만 알고 있는 것이다. //의 정확한 의미를 풀어 설명하자면 The floor of a real number a is the largest integer <= A 이다. (여기서 A는 Numerator(즉, 나눠지는 수(분자)이다.) 몫 보다는 floor가 맞는 표현이다. 그렇다면 %는? 바로 Numerator와 divider * floor의 Gap을 메꾸어 주는 녀석이라고 알아야 한다. 이 말은 사실 양수만 놓고보면 그냥 우리가 알던 몫, 나머지와 다를 바 없는 것 같지만 음수가 껴있다면 이야기가 달라진다. ( -13/4의 //값은 -3일 것 같지만 -4이고, %값은 -1이다) 그래서 양수던 음수던 어떤 경우에도 다음 식은 항상 만족한다. a = b * (a // b) + a % b a, b가 각각 양수이던 음수이던 항상 위의 식은 만족한다.

Python 변수 값 비교하기 (is, ==의 차이) / Value Comparison

Value Eqaulity 변수를 비교하는 방법은 두 가지가 있다. 그런데 비교하기 앞서 "비교한다" 의 의미부터 명확히 할 필요가 있다. 두 객체를 비교할 때, 메모리 주소와 상관없이 값만 비교하거나 혹은 값은 물론 메모리 주소까지 같은지 비교할 수 있다. 첫째로, 값만 비교 하는 연산자는 == / != 이다. 이 연산자는 자료형, 메모리주소는 따지지도 않고 그냥 값이 같으면 True를 리턴한다. 예를들어 a = 10.0 b= 10+0j 라고 할 때 a는 float, b는 complex 자료형이더라도 값은 10이므로 a == b는 True를 리턴한다. 반면에 is / is not 연산자는 값은 물론 메모리 주소까지도 비교 하고 이 두 가지가 모두 같아야만 True를 리턴한다. 위의 예시에서 a is b는 다른 자료형이므로 당연히 False가 return된다. 추가로, None 객체에 대해 알아보자. None은 값이 Empty인 객체라고 이해하면 쉽다. id(None)을 해보면 메모리 주소가 있고 type(None)은 Nonetype 리턴된다. 애플리케이션의 생애주기에서 모든 None값은 Shared Reference이다. 따라서 모든 None으로 지정 된 값은 같은 메모리주소를 가리킨다. (Empty인 값을 굳이 매번 새로 만들어서 메모리 낭비하는 일은 바람직하지 않으니 당연한 노릇이다.) 예시) a = None; b= None; c = None일 때 a is b is c는 True를 리턴한다.

Python 코드최적화 1. Peephole optimization

파이썬은 인터프리터 언어이지만 컴파일을 거친다. 개발자가 실행한 코드는 한 줄 한 줄 런타임에 컴파일 되고 해석된다. 미리 컴파일 되지 않으면 매 번 소스코드 한 줄을 해석할 때마다 같은 연산을 반복해야할 수 있고, 만약 어떤 연산을 하는 코드가 반복적으로 있다면 해당 코드를 실행할 때마다 연산을 다시해야하기 때문에 느려지게 될 것이다. 따라서 파이썬은 컴파일 할 때 특정 조건에 만족하는 항목들은 미리 계산(pre-calculate) 해두고 이를 상수로 갖고 있는다. 조건은 크게 얘기하면 Immutable한 객체의 연산 이라고 할 수 있고 조금 더 디테일 하게 들어가면 아래와 같다. 1) Numeric Calculation (숫자 계산) Ex) 24 * 60, 300 * 12, 30000* 12000 2) 연산결과의 length가 20이 넘지 않는 Immutable 객체의 Sequence 연산 Yes) "Hello" + "World"       "abc" * 5        (1,2) * 5 No) " ab"*11 (이건 22글자가 되기 때문에 탈락)       (1,2) * 11 (마찬가지로 22개가 되기 때문에 탈락) def my_func (): a = 3000000 * 12000 / 27 b = ( 1 , 2 ) * 5 c = "abc" d = "ab" * 11 e = "the quick brown fox" * 5 f = [ "a" , "b" ] * 3 g = [ "a" , "a" , "a" , "a" , "a" , "a" , "a" , "a" , "a...