본문 바로가기
A. Development/Python

Python 프로그래밍

by 곽동현 IMCOMKING 2014. 6. 17.

# Python의 변수 호출/참조: Call by Objective Reference
대충, call by reference(포인터)랑 비슷한데, 다만 함수안에 전달될 때에는 지역변수 tag가 붙기 때문에 레퍼런스가 사라진다. 또한 List와 같이 mutable한 정보를 담는 자료구조는 indexing을 할 경우 call by reference처럼 행동한다.
http://devdoggo.netlify.com/post/python/python_objective_reference/

 


## Python에서는 + 와 += 가 다르다.
a += b 는 inplace이지만, a = a+b 는 새로운 메모리를 할당한다.
https://docs.python.org/3.2/library/operator.html#inplace-operators

 

import sys

print("This is the name of the script: ", sys.argv[0])

print("The arguments are: ", str(sys.argv))

 

 

 

# Python ArgumentParser

args.add_argument('--multi_label', type=int, choices=range(1,5), default=1, help='You can choose the number of tasks(labels). The task should be at least 1.') # 3 # number of labels

https://docs.python.org/3/library/argparse.html#choices
https://stackoverflow.com/questions/25295487/python-argparse-value-range-help-message-appearance

 

 

## Argparse에 yes/no 옵션 추가하기

args.add_argument('--download', dest='download', action='store_true')
args.add_argument('--no-download', dest='download', action='store_false')
args.set_defaults(download=True)

https://stackoverflow.com/questions/15008758/parsing-boolean-values-with-argparse

 

 

## Argparse에서 여러가지 str input받기

args.add_argument('-no','--no-download', dest='download', action='store_false')

 

## Argparse에서 2개의 int 받기

parser.add_argument("--exp", type=int, nargs=2, default=None)

 

## Argparse에서 1개 이상의 string을 받아서 list에 저장하기

parser.add_argument("--run_modes", type=str, nargs="+", default=["train", "valid", "test"])

https://docs.python.org/2/library/argparse.html#nargs

 

## 주어진 args or namespace에 대해서 Argparsing하기

parser.parse_known_args(unknown_args)

- unknown_args를 입력하지 않으면, sys.argv를 자동으로 parsing한다.

parse_args또한 동일하다.

 

 

## Namespace에 dynamic 이름의 변수 할당하기

setattr(conf, dataset_name, dataset_config)

https://stackoverflow.com/questions/34957314/dynamically-creating-namespaces-in-python

 

 

## Argparse 자체 파싱 규칙

augment-data-length 이렇게 된 argument는 parsing되고나면 저절로 augment_data_length 즉 '-'이 '_'으로 바뀌면서 변수명이 정해진다.

https://github.com/python/cpython/blob/0cd5bff6b7da3118d0c5a88fc2b80f80eb7c3059/Lib/argparse.py#L1556

 

 

# 수동으로 실행 argument 확인하기

물론 argparse를 사용하면 이를 자동으로 파싱해서 입력받는다.

import sys
print("This is the name of the script: ", sys.argv[0])
print("The arguments are: ", str(sys.argv))

https://www.pythonforbeginners.com/system/python-sys-argv

# in 조건 빠르게 탐색하기

if user in user_entry: 	~~~ 

이러한 형태의 조건문을 처리할 때, user_entry가 데이터 타입 list일때는 O(N)이 걸리지만, set일 때에는 O(1)만큼 걸린다.

# Variable 목록

locals() globals() vars()

 

# Python 변수명 자유롭게 정하기
dictionary를 이용하면 변수명을 string으로 지정할 수 있다.

report_dict = {'summary':True, 'scope':locals(), 

                    'train__loss:'+str(m):train_loss[m]}

nsml.report(**report_dict)


https://stackoverflow.com/questions/6181935/how-do-you-create-different-variable-names-while-in-a-loop

 

 

 

# Python 임의의 string으로된 코드를 실행하기

foo = eval("print('asdf')")

- 이를 응용하여 string으로부터 class obejct를 가져올 수도 있다.

- 단, 임의의 string이 위험한 코드를 실행 할 수도 있으므로 각별한 주의가 필요하다.
https://stackoverflow.com/questions/1176136/convert-string-to-python-class-object

 

## literal_eval

- 이러한 eval의 위험성 때문에 많은 제약이 추가된 literal_eval()이 존재한다.

https://bluese05.tistory.com/65

 


# Python 임의의 string으로부터 class 가져오기
archiecture = getattr(sys.modules[__name__], "name of class")

https://stackoverflow.com/questions/1176136/convert-string-to-python-class-object

 

 

# Instance로부터 해당 class의 이름 가져오기

a = A()

print(a.__class__.__name__)

https://stackoverflow.com/questions/510972/getting-the-class-name-of-an-instance

 

 

# class의 method를 가져와서 실행하기

act_rew_func = ActionReward_function()

action_f = getattr(act_rew_func, meta_conf.exp_conf.action_f)

zero_mask = action_f(None)

http://effbot.org/zone/python-getattr.htm

 

# 위의 두가지 하나로 합친 함수

str_to_class(__name__, conf.task_name)(conf)


def str_to_class(module_name, class_name):
"""Return a class instance or method from a string reference"""
try:
module_ = importlib.import_module(module_name)
try:
class_ = getattr(module_, class_name)
return class_
except AttributeError:
print('Class does not exist')
except ImportError:
print('Module does not exist')

 

# DefaultDict

dictionary에 key:value 데이터를 저장할 때, 해당 key가 없는 경우 원래는 if문을 걸어서 dict.keys()에 있는지 없는지 나누어서 처리해야한다. 이런 불편함을 해결하기위해 defaultdict를 사용하면 처음 등장하는 key를 접근해도 keyErrory를 발생시키지 않고 바로 value를 넣을 수 있게 해준다.

How does collections.defaultdict work?

 

아래 두 코드는 동일한 기능을 수행한다.

 

from collections import defaultdict nor_dict = dict()

if k in nor_dict:
    nor_dict[k].append(1)
else:
    nor_dict[k] = [1]

==>

from collections import defaultdict def_dict = defaultdict(list)
def_dict[k].append(1)

 

## DefaultDict의 초기값 설정하기
임의의 값을 return해주는 lambda를 이용한 트릭으로 가능하다. 그 원리는 KeyError상황에서 지정한 callable을 호출하기 때문이라고 한다.

 

defaultdict(lambda:int(1))


https://stackoverflow.com/questions/30356892/defaultdict-with-default-value-1

 

 

 

# Dictionary를 obejct의 attribute로 바꾸기

class MyObject(object):

    def __init__(self, _dict):

        self.__dict__.update(_dict)

https://stackoverflow.com/questions/2466191/set-attributes-from-dictionary-in-python

 

 

 

 

 

 

# bokeh에서 nodejs 경로를 못잡는문제
source activate python362

conda info

conda install -n python362 -c bokeh nodejs

 

> python 에서 import에러가 뜨면 다음을 실행하여 nodejs의 bin 주소를 PATH에 추가해준다.

import os

os.environ['PATH'] += os.path.abspath(":/home/dhkwak/.conda/envs/python362/bin/")

 

 

https://github.com/bokeh/bokeh/issues/4974

https://bokeh.pydata.org/en/latest/_modules/bokeh/util/compiler.html

 

 

 

 

 

# 함수 포인터 사용법: 매우 쉬움. 그냥 함수 이름을 변수에 저장하면 끝임.

http://thrillfighter.tistory.com/344

 

 

# Switch문 대체 하는 방법: dictionary이용

def batch_loop(self, run_type="train"):
    assert run_type in ["train", 'valid', "test"], "You should select run_type among train, valid, test."

    {
        'train': self.set_train_mode,
        'valid': self.set_valid_mode,
        'test': self.set_test_mode,
    }[run_type]()

http://gentooboy.tistory.com/212

 

 

 

# csv.reader lazy load: csv. reader는 기본적으로 lazy loading이다.
https://stackoverflow.com/questions/11109524/can-csv-data-be-made-lazy

 

 

 

 

# yield 명령어: iterables가 가능한 자료형을 메모리에 전부 올리지 않고, 동적으로 처리하기 위한 generators를 구현하는 문법. 대충 return과 비슷한 역할을 하는데, 차이점은 메모리에서 바로 해제되지 않고 계속 사용가능하다는듯..??

https://item4.github.io/2016-05-09/Generator-and-Yield-Keyword-in-Python/

https://tech.ssut.me/2017/03/24/what-does-the-yield-keyword-do-in-python/

 

 

 

 

 

# locals()

locals는 현재 함수에서 사용할 수 있는 모든 지역변수를 dict형태로 return해준다. 따라서 다음과 같은 이용이 가능하다.

 

a, b, c = 1, 2, 3

def func(a, b, c): print(a, b, c)

func(**locals())

혹은 kwargs를 사용할 경우, 

a, b, c = 1, 2, 3

def func(**kwargs):

print(kwargs["a"], kwargs["a"], kwargs["a"])

func(**locals())

 

 

그런데 이때 python compiler의 optimization에 의해 locals는 update가 불가능하다. 그렇지만 exec를 한 번 실행해주면, optimization이 실행되지 않으므로, locals()를 업데이트 하는게 가능하다.

그렇지만 이는 거의 해킹에 해당하는 기술이므로, 사용을 권하지 않는다. 그냥 locals()["변수명"]으로 사용하는 것이 가장 정상적인 방법이다.

또는 이러한 방법을 이용해서 namespace에 해당 변수를 할당하는 것을 추천한다.

 

from types import SimpleNamespace lv = SimpleNamespace(**locals())

 

# vars()를 이용해서 SimpleNamespace를 dictionary로 변환하기

conf = SimpleNamespace()

conf_dict = vars(conf)

 

# locals(), globals()

위 두가지 함수를 이용해서 함수를 호출하기 위한 namespace를 가져올 수 있다.

http://jasmine125.tistory.com/872

 

 

# sorted 기능

sort하고싶은 list를 넣고, key값을 뭘로할지 지정해주면됨. 그런데 이를 쉽게 lambda함수를 이용해서 key를 list에서 뽑아서 지정할 수 있음. 아래 예제 참고

 

 

# list를 date string에 따라서 increasing order로 정렬하기

date_code_list = sorted(date_code_list, key=lambda x: datetime.datetime.strptime(x.split("@")[0], '%Y%m%d'), reverse=False)

high_priority_intent = sorted(intents, key=lambda x: intent_to_priority[x], reverse=True)[0]

 

# N_text형태로 된 string을 숫자의 오름차순 정렬하기

exp_list = sorted(exp_list, key=lambda x: int(x.split("_")[0]))

 

* datetime에서 strptime에 들어가는 format은 다음 레퍼런스를 잠조할 것.
대문자 M은 minute를 뜻한다.

 

http://strftime.org

 

 

 

 

import dhkwak_class_and_function as dh # i need prefix dh.

from dhkwak_class_and_function import * # i don't need prefix now

 

plt.plot -> 점들을 연결해서 그리기

plt.scatter -> 점들을 각각 따로 떨어트려서 찍기

 

 

 

=================

 

# 점프 투 파이썬을 읽고, 요약 정리한 내용이다.
https://wikidocs.net/15

 

# Python의 특징 : C로 만들어진 python library를 불러와서 사용가능. 즉 Python으로 된 코드가 실제로는 C로 실행이되는것임.

 

 

 

- 8진수 변수:

a = 0123

 

- 16진수 변수:

a = 0x123

 

- 제곱 연산자:

3**4 = 81

 

- 나눗셈 연산자
3/2 = 1.5


- 나눗셈 후 소수점 내림 연산자:

3//2 = 1

ex) -3//2 = -2

 

 

# 파이썬 문자열 다루기

'' 이나 "" 두가지 방법으로 문자열 생성

 

\' 이나 \" 을 이용하여 문자열내에 특수 기호 삽입

 

""" 이나 '''을 이용하면 \n을 쓰지 않고, 그냥 엔터를 쳐서 줄바꿈을 입력할 수 있음

 

- 문자열 덧셈

'abc'+'defg' = 'abcdefg'

 

- 문자열 곱셈

'123'*2 = '123123'

ex) print('='*50)

===================...

- 문자열 리스트 인덱싱(문자열 객체는 list를 상속받고, 거기에 추가적인 함수를 구현한 듯)

a='abcdefg'

a[2]= 'c'

a[-1]= 'g'

a[0:2] = 'ab'

--> [0,2) 구간임. 

0 생략가능

end도 생략가능

ex) a[:] = 'abcdefg'

 

 

- print format으로 출력하기

print "arg_name: {}, value: {}".format(val1_name, val1)

 

- formatting하기

" %~~ " %( ) 을 이용해서 여러가지 문자열 포멧 출력

https://pyformat.info/

 

- 5자리 정수 출력하기

print("Number: {:5d}".format(id_card))

 

 

# 문자열 formatting --> %2번 사용

정수 삽입: "%d" %3

문자열 삽입: "%s" %'abc'

여러개 삽입: "%d: %s" %(3, 'abc')

 

그런데 이 때 %s의 경우, 어떠한 자료형이든지 전부 문자열로 변환해서 출력시켜준다. 따라서 형식에 자유로운 장점이 있음.

 

문자열 formatting을 할 때 %를 출력하려면, %%두번 입력을 한다. \%은 안되나?

 

- 문자열 format 정렬과 공백

"%10d" %5

전체 문자열의 길이가 10이고, 오른쪽 정렬

 

"%-10d" %5

전체 문자열의 길이가 10이고, 왼쪽 정렬

 

"%5.4f" %0.123

전체 문자열의 길이가 5이고, 소수점은 4자리까지만 출력, 오른쪽 정렬

 

# 문자열 내장 함수

'abbbc'.count(b) --> 3

'abbbc'.find(c) --> 4. 처음 나온 문자 c의 index를 알려줌. 없으면 -1 리턴

','.join('1234') --> '1,2,3,4'. 우측문자열 사이사이에 ,을 넣어줌

'abc'.upper() --> ABC

'ABC'.lower() --> abc

- 문자열 치환

'Life is too short'.replace("Life", "Leg") --> 'Leg is too short'

 

- 문자열 나누기

"Life is too short".split() --> ['Life', 'is', 'too', 'short']

만약 split함수 안에 ',' 을 넣으면, comma sepration을 하게됨

 

 

# 리스트

Python에서는 배열대신 list를 매우 자주 사용한다. C에서의 array와 동일한 기능을 쓰려면 numpy를 쓴다. (python 내장 array는 매우 비효율적임)

 

## Python List

- list() 와 [] 명령어는 다르다.

예를 들어 list(1) 은 int object is not iterable이라는 에러가 뜨지만, [1] 은 그러한 에러가 뜨지 않는다.

[https://stackoverflow.com/questions/19523563/python-typeerror-int-object-is-not-iterable](https://stackoverflow.com/questions/19523563/python-typeerror-int-object-is-not-iterable)

- 또한 list([1]) 을하면, 그냥 다시 [1]이 되지만 [[1]] 을 하면 list안에 또 list가 들어있다.

 

a = [ ] (a = list()도 가능)

b = [1, 2, 3]

c = ['Life', 'is', 'too', 'short']

d = [1, 2, 'Life', 'is']

e = [1, 2, ['Life', 'is']] --> 리스트 안에 리스트를 넣음

 

- list 수정

a = [1,2,3]

a[1:2] = 'abc'

--> [1, 'abc', 2]

 

- list 엘리먼트 삭제

del a[0] --> 0번 엘리먼트 삭제

 

- list 내장함수

문자열 리스트와 대부분의 기능 공유함.

리스트 덧셈, 반복, count() 등

 

a.append(5) --> 뒤에 5를 덧붙임

a.pop() --> 맨 앞의 원소를 꺼내옴(삭제하면서)

a.pop(index) --> 해당 인덱스를 꺼내옴

a.extend([리스트]) --> list + list 연산

a.sort() --> 오름차순 정렬

a.reverse() --> 역순

a.insert(index, element) --> 가운데에 끼워넣을수있음

a.index(값) --> 처음나온 해당 값의 인덱스 리턴

a.remove(값) --> 처음나온 해당 값의 엘리먼트를 삭제

 

- 특별한 조건 연산자

if 1 in [1, 2, 3] --> True

if 1 not in [1, 2, 3] --> False

 

 

- Python에서 어떤 조건문에 아무것도 실해하고 싶지 않을 때, pass를 사용한다

if 'money' in pocket:

    pass 

 

 

in문법을 if와 사용하면, 엘리먼트 체크의 기능이 되고, for 문과 연동하면 list에서 엘리먼트를 하나씩 가져오도록 사용할 수도 있음.

 

a = [(1,2), (3,4), (5,6)]

for (first, last) in a:

    print(first + last)

 

 

Class와 Instance의 차이

어떤 class를 정의한 다음, 해당 클래스를 initialize하면 instance가 생성된다.

 

# Method의 종류


class MyClass:
    # This part is Class definition.
    # It has same effect with classmethod, but it is always executed when the class module is loaded.
    # So it is hard to control the flow. Therefore if you need a kind of shared computation, use classmethod.
    
    def method(self):
        # instance method
        return 'instance method called', self

    @classmethod
    def classmethod(cls):
        return 'class method called', cls

    @staticmethod
    def staticmethod():
        return 'static method called'
    

https://docs.python.org/3/tutorial/classes.html

 

- Class method: 오직 class 변수만 접근한다. class 변수를 바꾸어, 모든 instance에 영향을 줄 수 있다. 

- Static method: class 혹은 instance의 아무런 변수도 필요로하지 않는다.

- Instance method: 오직 instance 변수만 접근한다.

 

* Class definition part: 이곳에 선언된 코드는 class method와 기능적으로는 완전히 동일하지만, class를 선언하는 시점에서 반드시 1회 호출이 되고 cls를 생략하고서 변수를 정의할 수 있다. Class module을 로딩하기만해도 즉시 호출되기 때문에 호출여부나 시점을 control 할 수 없으므로, class간에 서로 공유하는 정보나 연산이 필요한 경우 class method를 따로 정의해서 사용하는 것이 바람직하다.

https://www.makeuseof.com/tag/python-instance-static-class-methods/

https://www.geeksforgeeks.org/class-method-vs-static-method-python/

 

# Method 선언시

Always use self for the first argument to instance methods.

Always use cls for the first argument to class methods.

 

# Variable의 종류

- Class variable: ClassName.name으로 접근하거나, class_method안에서 cls.name으로 접근한다.

- Instance variable: instance_name.name으로 접근하거나, instance_method안에서 self.name 으로 접근한다.

https://docs.python.org/3/tutorial/classes.html#class-and-instance-variables

https://stackoverflow.com/questions/68645/are-static-class-variables-possible-in-python

 

# Special Variable

python에는 built-in 으로 제공되는 특수한 변수가 있다.

__name__ : 현재 코드가 위치한 패키지의 경로와 이름이 저장되어 있다. 단, main의 경우만 __main__으로 나타나고, 다른 패키지는 import 경로와 동일하다.

ex) if __name__ == "__main__":

main함수 실행시 동작 코드 작성

 

__file__ : 현재 코드의 절대 경로가 저장되어 있다.

ex) os.path.dirname(__file__)     으로 현재 파일의 상위 dir을 가져올 수 있다.

https://stackoverflow.com/questions/419163/what-does-if-name-main-do/20158605

 

 

# Project 내부에 속한 파일을 읽어들일 때

PROJECT_ROOT = os.path.dirname(os.path.abspath(os.path.dirname(__file__)))

프로젝트가 module로 사용될 때에는 기본 경로가 실행파일의 위치이기 때문에 프로젝트 root에 상대적인 경로로 파일을 읽어들여야만 경로 참조 시 문제가 생기지 않는다. 

 

https://stackoverflow.com/questions/14483768/python-loading-files-relative-from-project-root

 

 

 

Package Import 경로 설정

python 에서는 import를 할 때, sys.path에 등록되어 있는 경로들 중에서, 순서대로 package name을 찾는다. 따라서 만약 같은 이름을 가진 두 개의 package가 있다면 가장 먼저 sys.path에 등록되어 있는 패키지를 가져오게 된다.

 

아래의 코드를 이용해서 쉽게 path순서를 확인할 수 있따.

import sys
print(sys.path)

 

그리고나서 sys.path.insert( index , path )를 이용해서 내가 import하고자 하는 package의 경로를 넣어주면 원하는 package를 import 할 수 있다.  참고로 sys.path.append(path)의 경우 경로들의 가장 마지막에 추가된다.

 

* sys.path를 relative_path로 추가할 때, 기준이 되는 현재 경로는 다음으로 파악할 수 있다.

 

import os

os.getcwd()

1. 절대 경로 추가 방식

import sys, os
sys.path.append(os.path.abspath('/home/starlab/Webserver/emotion_predict_for_upload'))
from main_emotion_predict import emotion_predict

from 패키지명 import 오브젝트이름

이렇게하면 main_emotion_predict.py 파일에서 emotion_predict() 함수를 가져온다.

 

 

1-1. 보다 심플한 방법

import sys sys.path.insert(0, '../') import utils

-->위의 예제는 바로 자신 위에 parent 폴더에있는 uitls라는 python 파일을 참조한 것임.

 

 

2. 상대 경로 참조 방식

- 아주 심플하고 완전한 상대 경로 참조 방법

sys.path.append(os.path.join(os.getcwd(), "my_lib"))

sys.path.append(os.path.dirname(__file__), "my_lib"))

sys.path.append(os.path.abspath(os.path.dirname(__file__)))

 

 

(또는 다음과 같은 방법이 가능한데, __init__을 추가해야할듯)
from Aupair.vision import recognize_objects

# from [path] import [function or class]

 
음.. 이 path가 환경 변수 같은 것에 등록된 path인가보지?? 자동으로 업데이트되는..
 
 
 
 
- Main으로 호출 할 경우 설정

if __name__ == "__main__":# this is used when python is called from putty not other python code.

 

return ~~

 

 

 

# 파일 참조 시 경로

 

import os

print os.getcwd() # 이걸 입력해서 현재 호출되는 시점에서의 참조 경로 확인

path = os.path.join('..', '하위 폴더', '폴더 명') # os.path.join을 쓰는 이유는 윈도우/리눅스 호환성을 위해서임. 

즉 path = '../폴더명/파일명'  # 이렇게해도 리눅스에서만 쓸거면 문제 없음.

 

 

# 문제 해결

ModuleNotFoundError는 무조건 sys.path에서 해당 패키지를 찾을 수가 없을 때 발생한다.

이는 특히 다른 모듈을 하위로 가져오는 submodule이나 subtree를 사용할 때 흔히 발생하는데, 침착하게 sys.path를 잘 설정해주면 해결할 수 있다.

 

 

# 순환참조 문제: 원인을 알 수 없는 Import Error

분명히 제대로 __init__도 만들고, 제대로 import를 해줬는데도 불구하고 ImportError: cannot import name '~~~' 에러가나면? 즉 원인을 알 수 없게 ImportError가 나면? 

 

백퍼센트 순환참조 문제이다.

https://item4.blog/2017-12-03/Resolve-Circular-Dependency-on-Python-Typing/

 

 

# __init__.py

__init__.py 파일은 해당 디렉토리에 있는 다른 python 패키지나 모듈보다 항상 우선하여 실행된다. 그 역할은 해당 디렉토리의 패키지나 모듈이 필요로하는 initialization 코드를 작성하는 역할이다.

 

 

 

# Submodule Import 하기

- module: 1개의 single python file을 의미함.

- package: 다른 패키지나 모듈을 담을 수 있는 것.

 

## 주의사항

1. 순환 참조가 일어나면, "ImportError: cannot import name 'reporter'" 이런 에러가 뜨게된다. 순환 참조를 없앨것
https://stackoverflow.com/questions/9252543/importerror-cannot-import-name-x

2. 어떤 module의 하위에 있는 특정 함수만 import해도, 해당 module 전체가 import되어진다.(__init__.py에 있는 import가 모두 실행됨. __init__.py 은 모듈이나 패키지의 초기화 코드를 작성하는 용도이다. 해당 모듈/패키지가 import 되는 순간 실행된다.)

directory 마다 __init__.py 라는 비어있는 파일을 생성해주면, 해당 디렉토리를 module로써 바로 import 할 수 있다. 즉 __init__이 있어야만 단순 directory가 아니라 package로 인식된다.

https://stackoverflow.com/questions/48129733/how-to-import-a-module-from-a-subfolder-in-python3-with-empty-init-py

 

그리고 이 __init__.py에서 해당 모듈이 필요로하는 대상을 initialize 코드를 작성해주면 된다.

 

# Package 만들기

api package를 만들 때, github에 공개된 오픈소스들을 보면 항상 모든 소스코드를 포괄하는 parent package를 갖고 있다. 왜냐하면 이 공통조상이 없으면, 다른 package에서 또 다른 package의 내용을 relative import할 수 없기 때문이다. 만약 공통 조상 package가 없는 상태에서 import를 시도하면 다음과 같은 에러가 발생하고, 이 경우 sys.insert를 이용해서 직접 경로를 추가해야한다. "attempted relative import beyond top-level package"

# Relative import

python에서 package를 relative import할 경우 오직 다음 문법밖에 지원하지 않는다. 즉 "import XXX.YYY.ZZZ"방식은 지원하지않는다
from ..moduleA import foo 

이유: https://docs.python.org/3/reference/import.html#regular-packages

# Package와 submodule구조

https://stackoverflow.com/questions/54598292/python-modulenotfounderror-when-trying-to-import-module-from-imported-package

https://docs.python.org/3/tutorial/modules.html#packages

넘파이 플래튼: 1짜리 디맨젼 날림서치솔티드: 빠른 where. 정렬되었다는 가정하에빠른 where가 필요하면, 그냥 딕셔너리로 미리 인덱스 계산해서 구워두는게빠름딕셔너리.get 하면 키가없을 때 리턴예외를 처리가능함아 그러면 두 아이디를 왔다갔다할 수 있는 맵핑 딕셔너리를 만들어둬야겠다.

 

 

Stdout을 파일로 저장: Logging

stdout을 file stream에 연결하는 방법

import sys
sys.stdout = open('file', 'wt')
print('test')
sys.stdout.close()
 
위와 같은 방법으로 해버리면 아주 간단히 print로 출력된 모든 string을 해당 파일로 저장시킬 수 있다.
그러나 이렇게 하면 print로 출력되는 것은 더이상 볼수 없게 된다. 또한 stdout을 이렇게 쓰면 여러가지 불안한 문제점또한 존재한다.
 
 

logging 사용하기

logging모듈을 사용하면 stdout으로 출력할 수도 있고, 파일로 출력할 수도 있고, 또 동시에 출력할 수도 있다.
맨 앞에서 한 번 config해 놓으면 print랑 같은 방식으로 사용할 수 있고 third 파티 앱과 통합된 방식으로 쉽게 로그 관리가 가능하다. 그리고 log가 호출된 모듈(함수)위치를 알아낼 수 있음. 로깅레벨에 따라서 필터링할 수 있는 것도 장점임.(한번에 print를 안보이게 할 수 있음)
 

다음의 config를 사용하면, stdout과 파일로 동시에 출력 가능.

 

import logging

reload(logging)

logger = logging.getLogger('program_name')

logger.setLevel(logging.INFO)

fh = logging.FileHandler('logfilename.log')

fh.setLevel(logging.INFO)

ch = logging.StreamHandler(sys.stdout)

ch.setLevel(logging.INFO)

formatter = logging.Formatter('%(asctime)s %(name)s [%(levelname)s] %(message)s')

fh.setFormatter(formatter)

ch.setFormatter(formatter)

logger.addHandler(fh)

logger.addHandler(ch)

 

 

 

 

range, xrange, arange

http://stackoverflow.com/questions/135041/should-you-always-favor-xrange-over-range

range(start, stop, step) : default built-in function to make the sequential list of integer

xrange(start, stop, step) : default built-in function to get the sequential index of integer. not really make the list so it's much faster but can't get the real index value

arange(start, stop, step) : numpy api to use the range in matrix domain

http://geography.tistory.com/234

 

 

 

# Argument Passing with List or Dictionary

파이썬에서는 함수에 인자를 전달할 때, list나 dictionary를 이용해서 한 번에 인자를 전달할 수 있다.

 

def function_A(a , b, c):

    return a+b+c

 

이러한 함수가 있을 때 다음의 세가지 방식으로 호출할 수 있으며, 서로 완전히 같은 기능을 한다.

 

1) Normal

function_A(a=1, b=2, c=3)

 

2) List

arg = [1, 2, 3]

function_A(*arg)

 

3) Dictionary (단, 반드시 함수의 argument이름과 dictionary의 key이름이 같아야한다.)

arg = {"a": 0, "b": 1, "c": 2}

function_A(**arg)

 
# 이때, **은 dictionary의 포인터를 전달하는 것이고, *은 list의 포인터를 전달하는 것이다.

 

http://stackoverflow.com/questions/21986194/how-to-pass-dictionary-items-as-function-arguments-in-python

 

 

# *args, **kwargs를 이용해서 함수 인자 정의하기 

python에서 함수를 정의할 때, 입력받을 argument들을 명시적으로 fix시키지 않고 정의할 수 있는 방법이 있다.

 

*args는 함수에 인자를 list형태로 전달받는 경우로, non-keyworded argument만 처리할 수 있다.

ex) def test_args_fun(*args):

~~~

test_args_fun(1, 2, 3, key, value)

 

**kwargs는 함수에 인자를 dictionary형태로 전달받는 경우로, keyworded argument만 처리할 수 있다.

ex) def test_kwargs_fun(**kwargs):

~~~

test_args_fun(one=1, two=2, three=3, key=key, value=value)

 

 

# 투명한 함수 정의하기

입력 받은 변수 그대로를 다른 함수에 전달해주는 구현
def forward(self, *args, **kwargs):
    return self.layer(*args, **kwargs)
 

 

 

# 전역 변수 사용

 

전역 변수로 선언한 변수를 함수 내부에서 호출 시 기본적으로 인식을 하지 못한다.

이런 경우 함수 내부에 "global 변수명" 를 한 번이라도 선언하고 실행해주면, 그 뒤로는 모든 함수에서 global 변수 사용이 가능하다.

아래 링크 참조.

http://stackoverflow.com/questions/423379/using-global-variables-in-a-function-other-than-the-one-that-created-them

 

 

# Python Class

 

- 클래스 instacne를 저장하고 불러오기

http://stackoverflow.com/questions/2709800/how-to-pickle-yourself

 

핵심은 pickle을 이용해서, self.__dict__ 를 저장하고 불러온 다음, self.__dict__.update(loadings) 를 해서 객체를 업데이트 시켜버리는 것임

 

ex) 클래스가 자기 자신의 instance를 저장하고, 불러오는 예제

    def save(self):

        with open('MountainCar_demonstration.pkl' , 'wb') as f:

            pickle.dump(self.__dict__, f , pickle.HIGHEST_PROTOCOL)

    

    def load(self):

        path = os.path.join('..', 'IRL_tensorflow', 'MountainCar_demonstration.pkl')

        with open(path, 'rb') as f:

            tmp_dict  = pickle.load(f)

        self.__dict__.update(tmp_dict)

 

 

- 클래스 상속

class extention -> class MyClass(parent class):

마찬가지로 함수 overriding도 가능.

 

- 클래스 조건부상속(Conditional Inheritance)

상속을 받는 () 안에 if, else문을 이용해서 조건부 상속이 가능하다. (반드시 함수를 정의해서 할 필요는 없음)

 

def MountainCarFunction(conf):

    class MountainCarEnvironment(ModelEnvironment if conf.model_based is True else Environment):

    return MountainCarEnvironment(conf)    

 

- 내부클래스 / 내부함수

어떤 클래스의 내부에서만 선언될 클래스는 다음과 같이 inner class로 선언할 수 있다. 아래 코드는 연속된 계층구조를 맞춰서 다음과 같은 접근이 가능하다.

 

class ModelInteraction(object):

    class observation_space(object):

        def __init__(self):

            self._shape = 0

            

        @property

        def shape(self):

            return self._shape

        

        @shape.setter

        def shape(self, value):

            self._shape = value

        

    class action_space(object):

        def __init__(self):

            self._n = 0

            

        @property

        def n(self):

            return self._n

        

        @n.setter

        def n(self, value):

            self._n = value

 

        def sample(self):

            return random.randrange(1, self._n)

 

    def __init__(self):

        self.action_space = action_space()

        self.observation_space = observation_space()

 

--> 다음과 같은 접근이 가능하다!

self.interaction.observation_space.shape = 2 #action size in the model being learned

self.interaction.action_space.n = 3 # observation size in the model being learned

        

- @property

@V.setter

http://egloos.zum.com/nemonein/v/5280842

http://bigbigdata.tistory.com/69

 

- 특수 메서드

__init__ 이외에 __repr__와 같은 매우 유용한 특수 메서드가 클래스에 존재한다.

https://wikidocs.net/89

 

 

- 클래스 상속시 __init__함수의 작동방식

1) 상속받은 클래스를 생성하면 일단 기본으로 부모의 __init__이 호출된다.
2) 그런데 상속받은 클래스에 __init__함수를 따로 overriding하면, 부모의 __init__은 더이상 호출되지 않는다.
3) 만약 부모의 __init__도 호출하고 싶으면, 상속받은 클래스에서 overriding한 __init__에서 다음의 코드를 한줄 추가해서 명시적으로 부모의 __init__을 호출시켜주어야 한다..
def __init__(self):
    super(자식클래스이름, self).__init__()

# super(자식클래스, self)를 하면 자동으로 부모클래스가 지정된다. 아니면 직접 부모클래스.__init__() 이렇게 해도 동일함.

-------

 

[output] + return_states = list(output).extend(return_states_

 

# 파이썬 딕셔너리:
- 중복이 불가능한 해시테이블. 순서정보가 없이 쌍으로 이루어진 데이터를 저장하는 데 용이. 선언은 {}으로하고, 이후사용은 리스트처럼 []으로함. 마찬가지로 del이나 in사용가능. 키스, 벨류스, 아이템스 함수와 클리어 함수가 있음. 키값으로 변하지않는 데이터를넣어야하므로 리스트는 쓸수없지만, 튜플은 가능. 벨류로는 무엣이든지 가능.


HDF5 읽어서, key값을 인덱싱할 때 ['trainingX'] 이렇게 문자열로 인덱싱하는걸 딕셔너리라고 함.

딕셔너리에서 [1]을 하면, 이건 1번째 데이터에대한 인덱싱이아니라, key값이 1로 지정된것일 뿐임. 

데이터를 추가하고 싶으면 dict['새로운 key'] = value 를 치면 됨. 삭제는 del dict['삭제할 key']

주의할 점은, key가 중복되게 넣어버리면, 어떤게 살아남을 지 모른다는것.(덮어씌여지는 순서가 랜덤임)

그리고 딕셔너리에서 여러개를 동시에 읽고싶으면, key들을 list가 아니라 tuple로 만들어서 넣어야함. (list는 값이 바뀔수 있어서안된다고함)

아하. hdf5.keys()에서 이 keys()가 딕셔너리 함수였구나

https://wikidocs.net/16

 

튜플이란 리스트와 몇 가지 점을 제외하곤 모든 것이 동일하다. 그 다른 점은 다음과 같다. 핵심은 값을 수정하지 못하는 것.

-리스트는 [ 과 ] 으로 둘러싸지만 튜플은 (과 )으로 둘러싼다.

-리스트는 그 값을 생성, 삭제, 수정이 가능하지만 튜플은 그 값을 변화시킬 수 없다.

 

- 파이썬은 ||이없다. 대신 or를 써야한다.

https://wikidocs.net/20

 

 

파이썬에서 메모리 강제 삭제

del ~~~ 하면 바로 메모리에서 날아감.

 

- 아이파이썬 단축키

 

# Tap : automatic completion

# ctrl + / : comment

 

 

아이파이썬 다큐멘테이션

? vgg_model.compile

 

esc b : below에 cell 셍성

esc a : above에 cell 셍성

 

아이파이썬 interact 바 두개 쓰기

 

interact(plot, z1=(0, 1, 0.1), z2=(0, 1, 0.1))

 
 
float is not callable

이 에러는 변수명하고 함수명이 똑같을때 발생한다.

 

------

 

- for 문에서 count 쉽게하기 : enumerate를 사용한다.

 

            for i, layer in enumerate(self.layers):

                x = layer(x)

                if type(layer) is Flatten:

                    x = tf.concat(1, [x , input_list[1]]) 

                

 

-

 

파이썬은 {} 대신 tab을 영역으로 사용함.

변수의 타입을 지정하지 않음. 자바스크립트처럼 알아서 변수 타입을 지정함.

 

파이썬은 기본적으로 모든 변수가 지역변수임. 그런데 global 을사용해서 여기서 선언한 지역변수를

다른데서도 참조할 수 있는 기능이있음

 

파이썬은 걍 실행시킨 파일의 위에서부터 쭉 실행됨.

그래서 함수정의가 위에서 선언되어야 아래에서 사용가능.

근데 전역변수 선언은 아래에 해도되는듯.

 

cnt ++은 안됨. cnt += 1 은 됨

=====

for cnt in range(0,10):

print(cnt)

 

====== 주석달기

한글 주석은 쓰지말라는듯 /  # -*- coding: utf-8 -*-  / 쓰러면이걸 파일 맨위에 선언하고하라는듯함.

# : 한줄짜리

" ~ " : 한줄짜리

""" ~ """ : 여러줄짜리

 

======= 함수 정의

def 함수명(인자, 인자) :

내용

return 반환변수

 

------ 리스트

리스트는 기본적으로 배열임.

근데 배열에 좀더 기능이 이것저것 추가된것임.

리스트의 리스트는 걍 2차원 배열임

 

리스트에서 특정 아이템을 삭제하려면?

    for cnt in range(0,kinect_nframes):

        del kinect_frames[cnt][1

 

 

- 예외처리

try :
    ~~~
except:       /        except 특정에러 as e :   (e는 에러 메시지를 의미)

    ~~~

https://wikidocs.net/30

 

 

- print 이어 붙여서 출력하기

print "arg_name: ", val1_name, "value: ", val1

 

 

- 3가지 주요 자료형 선언 방법

instance_list = []

instance_tuple = ()

 

instance_dictionary = {}

 

# Dictionary 합치기(겹치는 key에 있어서는 new_dict가 old_dict를 덮어쓴다.)
merged_dict = dict(old_dict, **new_dict)

https://code.tutsplus.com/ko/tutorials/how-to-merge-two-python-dictionaries--cms-26230

 

 

- tuple에서의 extend

(0 , )+ tuple(1,2,3) => (0, 1, 2, 3)

 

- List 를 tuple로 바꾸기

tuple([ 1, 2, 3 ]) 하면

[1, 2, 3] -> (1, 2, 3) 으로 바뀜

 

- List 의 expend 와 append의 차이

append는 list안에 list를 추가하는 것이고

extend는 list의 원소를 가져와서 기존 list에 추가하는 것임.

즉 extend의 결과는 항상 1개의 list이지만

append를 하면 list안에 list가 존재하게 된다.

 

http://stackoverflow.com/questions/252703/python-append-vs-extend

 

----- 제곱

7 ** 3 하면 7의 3이 나옴

 

걍 함수밖에서 , 0번째 탭에 실행시키면 자동실행됨

 

 

파이썬에서의 매틀랩 unique에 해당하는 함수는 set(X)임

 

 

eda,kinect,cert=0,0,0

변수는 이런식으로 선언하고 초기화. 아니면

window_size, step_size,  time_lag, EDA_m1,  EDA_m2,  EDA_m3,  EDA_m4,   EDA_median=[0]*8

 

eda,kinect,cert=0 이렇게 하면, 런타임 에러뜸

 

if(조건) :

#꼭 : 을 써줘야하네

   

 

다른 py파일에 있는 함수 쓰려면 그냥 import 한다음 XXXX.~ 찍어서 쓰면됨

 

 

 

 

형변환은 (type)~~ 하면됨

 

str에서 split 함수 쓰면 배열에다가 문자열을 쪼개서 집어넣어줌.

ex) str(ConfigFile.getStepsize()).split('.')[0] / 하면 점 앞에숫자만 쓴다는것임

http://hy3na.tistory.com/91

 

 

 

파이썬에서 static을 쓰려면 클래스를 선언해야함.

는  안되네 걍 global 선언

global도 희안하게, 선언은 걍해주고, 실제가져다 쓸때 global을 붙여서 쓰네

 

static = global로 해결은 잘안됨

static 은 클래스로 해결해야함.

------

global 은 걍 c에서 전역변수 선언해놓은거를 함수안에서

"사용할때는" global을 먼저 선언하고 사용해라라는 규칙임.

 

그래서 밖에다가 일단 전역변수 선언 후, 함수맨위에서 사용할

전역 변수들에 global을 한번씩 써주고 사용하면됨.

 

결론 -> 전역변수를 함수안에서 사용할때 global로 한번 명시해놓고 써라!

무조건 global해야됨. 안그러면 지역변수로 새로 생성해서 써버리네

 

 

class Myclass:

x=10

 

myInstance = Myclass() //로 인스턴스 생성

myInstance = Myclass //하면 인스턴스가아니라 클래스 obj가 나온다고함.

 

 

메서드 선언할때는 self가필요하네..

http://openlook.org/blog/2008/12/13/why-self-in-python-is-attractive/

https://wikidocs.net/28

 

클래스라는 것은 뽑기의 틀(별모양, 하트모양)과 비슷하다. 

별모양의 틀(클래스)로 찍으면 별모양의 뽑기(인스턴스)가 생성되고

하트모양의 틀(클래스)로 찍으면 하트모양의 뽑기(인스턴스)가 나오는 것이다.

 

즉, 클래스란 똑같은 무엇인가를 계속해서 만들어 낼 수 있는 틀

인스턴스란 클래스에 의해서 만들어진 뽑기를 뜻하는 것이다.

 

클래스 선언 ex)

class configfile:

    window_size=0

    step_size=0

    time_lag=0

    EDA_m1=0

    

    def __init__(self, window_size):

self.window_size = window_size

 

    def Read_config_file(self):

        self.index_start,index_end = 0,0

        self.config_buffer=[0]*100

        self.count_line = 0

                       

 

## self 란,

self란 자기자신의 instance를 가리키는것.

기본적으로 메서드 첫번째에 선언되어야함.

그리고 class내부의 변수를 사용할때는 꼭 self.으로 사용해야함

 

-- 생성자

    def __init__(self, window_size):

self.window_size = window_size

요런식으로 c 생성자처럼 사용함.

 

def __del__(self, )는 소멸자

 

--- 

클래스를 걍 

    fr = ReadData.FileReader() 이렇게 생성만해도, 

알아서 클래스의 맨위에서부터 쭉 실행이됨 ㅋㅋ.

 

 

클래스를 걍선언해놓는건 만으로도 쫙 위에서부터 실행하네

아니 그냥 모든 파일의 위에서부터 다실행 하는 듯.. 매우 C스럽다

 

걍 클래스가 한번 임포트 되기만해도, 위에서부터 실행시켜버림

그래서 제어를 하려면, 무조건 생성자 안에다가 넣어야되나?

근데 그러면 또 클래스의 변수를 접근할 수가 없네

 

 

 

 

 

 

- Python list comprehension : i 번째 원소를 list에서 반복적으로 연산하여 저장할 수 있음.

list에서의 Permutation Indexing 을 위의 기능을 이용해서 구현할 수 있다.

 

예제 1)

np.random.seed(1234)

permuted_index = np.random.permutation(len(full_path))

labels = labels[permuted_index] # numpy는 걍 이렇게 하면됨. 매틀랩 처럼.

 

from random import shuffle

shuffled_full_path = [full_path[i] for i in permuted_index] # list에서는 list comprehension을 써야함.

 

예제 2)

        threshold = 0.000001

        reward_feature = [threshold if val < threshold else val for index, val in enumerate(reward_feature)]

 

예제 3)

>>> l = [22, 13, 45, 50, 98, 69, 43, 44, 1] >>> [x+1 if x >= 45 else x+5 for x in l] [27, 18, 46, 51, 99, 70, 48, 49, 6]

 

## Dictionary comprehension
- list comprehension하고 거의 비슷한 방법으로 사용가능

 

report_dict = { key:item.astype(np.float64) if item.dtype=='int64' else item for item, key in zip(report_dict.values(), report_dict.keys())}

https://www.datacamp.com/community/tutorials/python-dictionary-comprehension

 

 

## List comprehension의 응용

1) 단순히 list를 생성하는 목적이 아니라, for loop의 one line command로써도 아주 잘 사용 가능하다. 특히 tuple( print(a), print(b) )로 여러개의 명령어를 묶으면 한줄에 여러개 실행이 가능하다.

https://stackoverflow.com/questions/7688725/multiple-actions-in-list-comprehension-python

 

2) 또는 if 문에 다음과 같은 trick을 써서 time delay를 줄 수도 있다.
[print(a) for s in sessions if time.sleep(1)==None]

 

 

 

 

- List repeat

bounds = [0, 256] * 100

 

- Bound check

if action in range(self.action_size+1) is True:  # 이때 반드시 range +1을 해주어야 제대로 체크됨. 정수만됨

    return action

else:

    raise error

이상하게 버그가 있는듯.. 그냥 if 문 사용하는게 안전해보임.

--

 

array[-1]

과 같이 음수 인덱스는 반대방향 인덱스를 의미한다. 즉 [-1]은 맨 마지막 인덱스이고, [-2]는 맨마지막에서 왼쪽 인덱스이다.

--

Numpy 에서 4d zeros만들기

4d_zeros = numpy.zeros((1,2,3,4))

괄호를 두번 쳐줘야한단다.

 

http://stackoverflow.com/questions/29042182/creating-a-4d-matrix-full-of-zeros-in-python-numpy

--

 

 

- matplotlib로 opencv로 그린 이미지를 IPython에 출력하기

 

%matplotlib inline
import cv2 import numpy as np import matplotlib.pyplot as plt
img = cv2.imread('/Users/ayang/Pictures/ForTest/test.jpg') img = cv2.cvtColor(img, cv2.cv.CV_BGR2RGB)

#plt.imshow(img) # the order of RGB is not same with opencv

plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))

 

 

https://gist.github.com/ayang/6474956
http://www.pyimagesearch.com/2014/11/03/display-matplotlib-rgb-image/

 

#matplotlib 에서 quiver 사용시에는 매우 조심해야한다.

pylab.quiver(x, y, u, v, angles='xy', scale_units='xy', scale=10)

다음 format이 무조건 default 호출이어야한다.

http://stackoverflow.com/questions/12079842/quiver-plot-arrow-aspect-ratio

 

 

 

-------------------------

Python

 

- Lambda function : 람다함수는 일종의 인라인 인스턴트 함수이다.
즉 어떠한 기능을 수행할 때 함수를 코드상에서 바로 구현해서 실행시켜버리는 인스턴트 함수 정의임.

 

- String operator : + 는 공백 없이 string을 붙이고 , 는 공백을 포함해서 붙인다.

print('one', 'two') 

>> one two

print('one' + 'two')

>> onetwo

http://stackoverflow.com/questions/2033242/concatenation-operator-or

 

- Super Overhead

파이썬에서 list 에다가 for loop을 돌면서 매 iteration마다 append를 하고, 이걸로 np.mean 같은걸 계산하면 정말 속도저하가 엄청나게 심각하다. 이런식으로 코딩을 하면 np.mean 계산 속도가 list의 길이와 비례해서 선형적으로 무한히 증가한다.

 

 

- collection

https://docs.python.org/2/library/collections.html#collections.namedtuple

 

여러개의 데이터 타입을 하나의 객체로 묶어서 사용할 수 있게 한다. dictionary와 매우비슷한데 보다 추상적임

 

 

numpy.random.permutation : 순서를 뒤섞은 객체를 return함

numpy.random.shuffle : input으로 넣은 대상의 순서를 뒤섞어줌(return이 없다)

 

 

 

 

from ~~~ import ~~~ 구문을 if문 아래에서 가져올 수 있음.

 

flag사용법

 

flag에서 conf를 어떻게 정의한거지?

--> 아, flags.DEFIN으로 정의한 모든것을 가져오는구나

 

 

tmp_list = []

tmp_tuple = ()

tmp_dictionary = {}

 

- assert : Should be True 여야하는 조건을 체크한다.

 

크리티컬한 문제가 생길 수 있는 부분에 적극 활용할 것, 

제시한 조건은 언제나 항상 성립해야함. 만약 필수 조건이 성립하지 않으면, 우측의 에러 메시지를 발생시킴.

그런데 다음과 같이 괄호를 잘못 사용하면 안됨. 괄호를 사용해버리면 파이썬 문법적으로 항상 False가 나와서 에러가 뜨지 않음.......... 그냥 

 

assert(2 + 2 == 4, "Houston we've got a big problem")

http://stackoverflow.com/questions/5142418/what-is-the-use-of-assert-in-python

 

그래서 assert를 쓸 때는 다음과 같이 항상 괄호 없이 사용할 것!!!

 

assert 2 + 2 == 4, "Houston we've got a big problem"
 

- assert의 의미 : assert if the condition is false

즉 해당 조건이 만족되지 않으면, 에러를 발생 시킴

 

다음 둘은 서로 동일함.

assert condition

 

if not condition:

    raise AssertionError()



 

## 삼항연산자: python에서는 if else 구문을 이용해 다음과 같은 삼항연산이 가능하다.
comparison = (True) if a == b else (False)

 

 

## 변수 연속할당
A = B = C 

이런식으로 변수 대입/할당이 가능

 

- reversed(range(self.history_length)) : 역순으로 세기

 

 

- python tuple to list/list to tuple

list(tuple instacne)

tuple(list instacne)

 

Python Class

 

- 클래스 instacne를 저장하고 불러오기

http://stackoverflow.com/questions/2709800/how-to-pickle-yourself

 

핵심은 pickle을 이용해서, self.__dict__ 를 저장하고 불러온 다음, self.__dict__.update(loadings) 를 해서 객체를 업데이트 시켜버리는 것임

 

ex) 클래스가 자기 자신의 instance를 저장하고, 불러오는 예제

    def save(self):

        with open('MountainCar_demonstration.pkl' , 'wb') as f:

            pickle.dump(self.__dict__, f , pickle.HIGHEST_PROTOCOL)

    

    def load(self):

        path = os.path.join('..', 'IRL_tensorflow', 'MountainCar_demonstration.pkl')

        with open(path, 'rb') as f:

            tmp_dict  = pickle.load(f)

        self.__dict__.update(tmp_dict)

 

 

- 클래스 상속

class extention -> class MyClass(parent class):

마찬가지로 함수 overriding도 가능.

 

그리고 클래스 상속을 한다음, 만약 부모 클래스가 __init__에서 무언가 기능을 하고 있다면, 반드시 자식 클래스의 __init__에서 super의 __init__을 호출해주어야만 함. 안그러면 아무런 동작도 하지 않는 게 됨. 파이썬은 보여지는 코드가 전부 다임. 그 이상 숨겨진 동작은 하지 않음.

 

- 클래스 조건부 상속

1. class newClass(A if os.name == 'nt' else B):
2. RLAgent = DistributedAgent if m_conf.e_conf.distributed else CentralizedAgent

3. class RLAgent(eval(Config.AGENT_TYPE)):

Config.AGENT_TYPE = "DistributedAgent" if e_conf.distributed else "CentralizedAgent"

import RLAgent # 반드시 import 를 나중에 해주어야함.

 

사용해보니, 3번 방식이 가장 편리함.

 

https://stackoverflow.com/questions/17599850/dynamically-choosing-class-to-inherit-from


- 클래스의 조건부 리턴(조건부 상속 목적으로 사용하면 안됨)

https://spyhce.com/blog/understanding-new-and-init
클래스가 어떤 객체를 반환할지는 __init__에서 결정할 수가 없다. 그래서 __new__ 함수를 이용해서 어떤 클래스를 실제로 사용할 결정할 수가 있다.(상속이 아니다. 그냥 다른 class를 가져와서 반환하는 것이다.)(단, 이 경우 object를 먼저 상속 받아야함)

 

__new__ 함수는, 어떤 방식으로 __init__을 할지를 결정하는 method이다. 객체를 생성하게 되면 언제나 __new__가 제일 먼저 호출되고 ,보통 그 다음에 __init__이 호출된다. 따라서 이 __new__함수를 통해서 __init__에 대한 동작 규칙을 정의할 수 있다. 이를 통해서 signleton 패턴 또한 쉽게 구현가능하다. 간단히 설명하면 객체 생성이 요청되었을 때, __new__를 정상적으로 호출해서 __init__을 호출 시킬지, 아니면 그냥 이를 무시하고 기존에 생성해둔 객체를 리턴할지 정하는 것이다.

 

class Singleton(object):

    def __new__(cls):

        if not hasattr(cls, 'instance'):

            cls.instance = super(Singleton, cls).__new__(cls)

        return cls.instance

 

https://medium.com/@chs99051868/python-design-pattern-singleton-963f4a796d7f

 

또한 아래와 같이 상황에 맞는 class를 type을 생성시키는 것도 가능하다.

 

즉 __new__는 어떤 방식으로 객체를 생성(__init__ 등)할지를 정의하는 함수이다.

 

class Test(object)

        def __new__(cls, conf, observation_dims):

            if conf.model_based is True:

                return Model_Environment(conf, observation_dims)

            else:

                return Environment(conf, observation_dims)

 

http://stackoverflow.com/questions/17599850/dynamically-choosing-class-to-inherit-from

 

- 클래스의 조건부 상속

조건부 상속을 하려면 아래의 링크처럼, 상속을 받는 calss A()이 괄호안에 if, else 문을 사용해야한다.

 

http://stackoverflow.com/questions/32598363/conditional-class-inheritance-in-python

 

 

 

- 클래스의 메서드를 외부에서 정의한 함수로 Overriding하기

먼저 다음과 같이 오버라이딩 하고 싶은 함수를 전역함수로 정의한다.

 

def custom_function(   해당class  , argument1, argument2 ...    ):

    return ~~~

 

그리고 나서 해당 클래스의 메서드에 function pointer를 대입한다.

 

ClassA.original_function = custom_function

 

이때 중요한 점은 임의로 정의한 함수의 첫 번 째 인자는 클래스 메서드의 self를 대체하는 변수라는 것이다. 그래서 마치 self 처럼 사용할 수가 있다.

 

 

 

- 클래스에 static 변수 선언하기

self를 안붙이고, class내부에 선언하면 된다고 함.

 

http://stackoverflow.com/questions/68645/static-class-variables-in-python

 

 

 

# 파이썬은 금지된 규칙이 거의 없다.

심지어 부모 클래스에서 자식 클래스의 method를 호출할 수가 있네.....; 단, 호출시 자식클래스로 생성한 객체에서만 호출 가능. 즉 부모 클래스는 오직 추상 클래스로만 사용되고 있어야함.

http://stackoverflow.com/questions/25062114/calling-child-class-method-from-parent-class-file-in-python

 

 

'A. Development > Python' 카테고리의 다른 글

Python Function Result Caching by Joblib.Memory  (0) 2020.07.24
Matplotlib 사용 팁  (0) 2018.11.27
Python 프로그래밍  (0) 2014.06.17

태그

,

댓글0