Ubuntu 설치 USB 부팅 Linux / ROS

1. 먼저 Ubuntu USB 부팅 드라이브를 만들어야 함. -> rufus 사용 -> https://rufus.ie/ko/

Ubuntu iso 파일은 https://ubuntu.com/download/desktop 에서 필요한 버전을 다운 받음.
LTS (Long-Term Support)를 다운 받는 것이 좋으며 만약 ROS를 사용하고자 한다면 
사용하고자 하는 ROS distribution에 따른 Ubuntu 버전을 까는 것이 좋다.
ROS distribution은 B부터 C, D, E, F, ~ 순서대로 릴리즈 되고 있는데 다음을 참고하면 됨.

ROS Indigo - Ubuntu 14.04 LTS
ROS Kinetic - Ubuntu 16.04 LTS
ROS Melodic - Ubuntu 18.04 LTS
ROS Noetic - Ubuntu 20.04 LTS
   
파티션 방식은 GPT, 대상 시스템은 UEFI로 (최신 컴퓨터는 대부분 UEFI 지원, 옛날 컴퓨터에 우분투 깔려고 하면 파티션 방식이 MBR일 수도 있으니 확인 필요)


2. 부팅 디스크를 만들었으니 바이오스 세팅을 하고 우분투를 깔면 됨.
다음 그림들이 델 컴퓨터의 부팅 옵션 화면과 바이오스 화면임. 

3. Storage에 보면 RAID로 설정되어 있는데 이것을 AHCI로 바꿔줌. 
4. 이제 우분투 부팅 USB를 넣고 깔면 됨.
윈도우와 듀얼부팅이라면 설치할 곳은 미리 윈도우의 디스크관리에서 마련해놓고 ext4 journaling file system 으로 마운팅 포인트는 / 로 함.
그대로 쭉 설치

5. 우분투 설치를 다 마치고 나면 윈도우는 바이오스에서 RAID로 해야 정상 작동하고 우분투는 AHCI로 해야 정상 작동함.
이렇게 되면 매우 귀찮으므로 RAID로 윈도우를 실행시킨 뒤 cmd 창을 관리자 권한으로 켜고
bcdedit /set safeboot minimal

그리고 재부팅해서 바이오스에서 RAID를 AHCI로 바꾸고 윈도우를 실행시키면 Safe mode가 실행이 됨.
다시 cmd 창을 관리자 권한으로 켜고 이번에는
bcdedit /deletevalue safeboot

입력하면 AHCI로 윈도우를 실행시킬 수 있음.     

함수, 파일 입출력, 클래스, 모듈, 패키지, 예외처리 Python


* 매개변수와 인수
매개변수(parameter)와 인수(arguments)는 혼용해서 사용되는 헷갈리는 용어이므로 잘 기억해 두자. 매개변수는 함수에 입력으로 전달된 값을 받는 변수를 의미하고 인수는 함수를 호출할 때 전달하는 입력값을 의미한다.

def add(a, b):  # a, b는 매개변수
    return a+b

print(add(3, 4))  # 3, 4는 인수


* 여러 개의 입력값을 받는 함수 만들기
def add_many(*args): 
    result = 0 
    for i in args: 
        result = result + i 
    return result 
add_many 함수는 입력값이 몇 개이든 상관이 없다. *args처럼 매개변수 이름 앞에 *을 붙이면 입력값을 전부 모아서 튜플로 만들어 주기 때문이다. 만약 add_many(1, 2, 3)처럼 이 함수를 쓰면 args는 (1, 2, 3)이 되고, add_many(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)처럼 쓰면 args는 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)이 된다.


* 키워드 파라미터 kwargs
키워드 파라미터를 사용할 때는 매개변수 앞에 별 두 개(**)를 붙인다.
입력값이 모두 딕셔너리로 만들어진다. 즉 **kwargs처럼 매개변수 이름 앞에 **을 붙이면 매개변수 kwargs는 딕셔너리가 되고 모든 key=value 형태의 결괏값이 그 딕셔너리에 저장된다.

def print_kwargs(**kwargs):
    print(kwargs)
>>> print_kwargs(a=1)
{'a': 1}
>>> print_kwargs(name='foo', age=3)
{'age': 3, 'name': 'foo'}


* 함수의 결과값은 언제나 하나이다
def add_and_mul(a,b): 
    return a+b, a*b
>>> result = add_and_mul(3,4)
이 함수를 위과 같이 호출하면 어떻게 될까? 
결괏값은 a+b와 a*b 2개인데 결괏값을 받아들이는 변수는 result 하나만 쓰였으니 오류가 발생하지 않을까? 당연한 의문이다. 하지만 오류는 발생하지 않는다. 그 이유는 함수의 결괏값은 2개가 아니라 언제나 1개라는 데 있다. add_and_mul 함수의 결괏값 a+b와 a*b는 튜플값 하나인 (a+b, a*b)로 돌려준다.
따라서 result 변수는 다음과 같은 값을 갖게 된다.
result = (7, 12)
만약 2개의 결과값으로 받고 싶다면 다음과 같이 함수를 호출하면 된다.
>>> result1, result2 = add_and_mul(3, 4)
이렇게 호출하면 result1, result2 = (7, 12)가 되어 result1은 7이 되고 result2는 12가 된다.


* 특별한 상황일 때 함수를 빠져나가고 싶다면 return을 단독으로 써서 함수를 즉시 빠져나갈 수 있다. return으로 함수를 빠져나가는 방법은 실제 프로그래밍에서 자주 사용한다.


* 매개변수에 초기값 미리 설정하기
def say_myself(name, old, man=True):
위 함수를 보면 매개변수가 name, old, man=True 이렇게 3개다. 그런데 낯선 것이 나왔다. man=True처럼 매개변수에 미리 값을 넣어 준 것이다. 이것이 바로 함수의 매개변수 초깃값을 설정하는 방법이다. 함수의 매개변수에 들어갈 값이 항상 변하는 것이 아닐 경우에는 이렇게 함수의 초깃값을 미리 설정해 두면 유용하다.
만약 위의 함수를 호출할때 인수를 2개만 넣어서 호출해도 초기값이 정해져 있으므로 문제없이 호출되며 3번째 인수를 True로 입력한 것과 결과값이 동일하게 나온다.
초기값을 설정해 놓은 매개변수 뒤에 초기값을 설정해 놓지 않은 매개변수를 사용할 수 없다. 즉 매개변수로 (name, old, man=True)는 되지만 (name, man=True, old)는 안 된다는 것이다. 초기화시키고 싶은 매개변수를 항상 뒤쪽에 놓는 것을 잊지 말자.


* 함수 안에서 선언한 변수의 효력 범위, 함수 안에서 함수 밖의 변수를 변경하는 방법
함수 안에서 새로 만든 매개변수는 함수 안에서만 사용하는 "함수만의 변수"이다. 동일한 이름의 변수가 함수 안밖에 있어서 함수 안에서의 변화를 함수 밖에서 영향을 받지 않는다.
1. return 사용하기 -> 여전히 함수 안의 a 매개변수는 함수 밖의 a와는 다른 것이다.
2. global 명령어 사용하기 -> 함수 안의 a 매개변수는 함수 밖의 a와 같다.
함수 안의 global a 문장은 함수 안에서 함수 밖의 a 변수를 직접 사용하겠다는 뜻이다. 하지만 프로그래밍을 할 때 global 명령어는 사용하지 않는 것이 좋다. 왜냐하면 함수는 독립적으로 존재하는 것이 좋기 때문이다. 외부 변수에 종속적인 함수는 그다지 좋은 함수가 아니다. 그러므로 가급적 global 명령어를 사용하는 이 방법은 피하고 첫 번째 방법을 사용하기를 권한다.


 * lambda
lambda는 함수를 생성할 때 사용하는 예약어로 def와 동일한 역할을 한다. 보통 함수를 한줄로 간결하게 만들 때 사용한다. 우리말로는 "람다"라고 읽고 def를 사용해야 할 정도로 복잡하지 않거나 def를 사용할 수 없는 곳에 주로 쓰인다.
def add(a, b):
    return a+b
-> add = lambda a, b: a+b
위에서 정의된 두 함수는 완전히 동일하다. lambda 예약어로 만든 함수는 return 명령어가 없어도 결과값을 돌려준다.


* 사용자 입력
input(), input("질문 내용"): input은 입력되는 모든 것을 문자열로 취급한다.


* print
1. 문자열 띄어쓰기는 콤마로 한다, 콤마(,)를 사용하면 문자열 사이에 띄어쓰기를 할 수 있다.
2. 한 줄에 결괏값 출력하기
for i in range(10):
    print(i, end=' ')
결과: 0 1 2 3 4 5 6 7 8 9


* 파일로 출력 - write 함수 사용 
f = open("새파일.txt", 'w') # 파일 객체 = open(파일 이름, 파일 열기 모드)
for i in range(1, 11):
    data = "%d번째 줄입니다.\n" % i
    f.write(data) # print로 모니터 화면에 출력하는 대신 파일 객체 f의 write 함수를 사용한 것 
f.close() # 열려 있는 파일 객체를 닫아 주는 역할을 한다. 사실 이 문장은 생략해도 된다. 프로그램을 종료할 때 파이썬 프로그램이 열려 있는 파일의 객체를 자동으로 닫아주기 때문이다. 하지만 close()를 사용해서 열려 있는 파일을 직접 닫아 주는 것이 좋다. 쓰기모드로 열었던 파일을 닫지 않고 다시 사용하려고 하면 오류가 발생하기 때문이다.

파일열기모드
1. 'r': 읽기모드, 파일을 읽기만 할 때 사용
2. 'w': 쓰기모드, 파일을 내용을 쓸 때 사용 (파일을 쓰기 모드로 열면 해당 파일이 이미 존재할 경우 원래 있던 내용이 모두 사라지고, 해당 파일이 존재하지 않으면 새로운 파일이 생성된다. )
3. 'a': 추가모드, 파일의 마지막에 새로운 내용을 추가 시킬 때 사용


* 파일로부터 입력 - readline, readlines, read 함수 사용 
f = open("C:/doit/새파일.txt", 'r') 파일이름에 경로를 지정할 수도 있다.
while True:
    line = f.readline() 무한 루프 안에서 f.readline()을 사용해 파일을 계속해서 한 줄씩 읽어 들인다.
    if not line: break 만약 더 이상 읽을 줄이 없으면 break를 수행한다(readline()은 더 이상 읽을 줄이 없을 경우 빈 문자열('')을 리턴한다).
    print(line)
f.close()

lines = f.readlines() -> readlines 함수는 파일의 모든 줄을 읽어서 각각의 줄을 요소로 갖는 리스트로 돌려준다.
data = f.read() -> 파일의 내용 전체를 문자열로 돌려준다. 따라서 이 예의 data는 파일의 전체 내용이다.


* 파일에 새로운 내용 추가하기
쓰기 모드('w')로 파일을 열 때 이미 존재하는 파일을 열면 그 파일의 내용이 모두 사라지게 된다. 하지만 원래 있던 값을 유지하면서 단지 새로운 값만 추가해야 할 경우도 있다. 이런 경우에는 파일을 추가 모드('a')로 열면 된다.


* with문과 함께 사용하기
with open("foo.txt", "w") as f:
    f.write("Life is too short, you need python")
위와 같이 with문을 사용하면 with 블록을 벗어나는 순간 열린 파일 객체 f가 자동으로 close되어 편리하다.


* sys 모듈로 매개변수 주기
파이썬에서는 sys 모듈을 사용하여 매개변수를 직접 줄 수있다. sys 모듈을 사용하려면 아래 예의 import sys처럼 import 명령어를 사용해야 한다.
import sys
args = sys.argv[1:]
for i in args:
    print(i)
위 예는 입력받은 인수를 for문을 사용해 차례대로 하나씩 출력하는 예이다. sys 모듈의 argv는 명령 창에서 입력한 인수를 의미한다. 즉 다음과 같이 입력했다면 argv[0]은 파일 이름 sys1.py가 되고 argv[1]부터는 뒤에 따라오는 인수가 차례로 argv의 요소가 된다.
C:\>python sys1.py  aaa     bbb     ccc
               argv[0] argv[1] argv[2] argv[3]
aaa
bbb
ccc


* 클래스와 객체
과자 틀 → 클래스 (class)
과자 틀에 의해서 만들어진 과자 → 객체 (object)
여기에서 설명할 클래스는 과자 틀과 비슷하다. 클래스(class)란 똑같은 무엇인가를 계속해서 만들어 낼 수 있는 설계 도면이고(과자 틀), 객체(object)란 클래스로 만든 피조물(과자 틀을 사용해 만든 과자)을 뜻한다.
클래스로 만든 객체에는 중요한 특징이 있다. 바로 객체마다 고유한 성격을 가진다는 것이다. 과자 틀로 만든 과자에 구멍을 뚫거나 조금 베어 먹더라도 다른 과자에는 아무 영향이 없는 것과 마찬가지로 동일한 클래스로 만든 객체들은 서로 전혀 영향을 주지 않는다.
클래스로 만든 객체를 인스턴스라고도 한다. 그렇다면 객체와 인스턴스의 차이는 무엇일까? 이렇게 생각해 보자. a = Cookie() 이렇게 만든 a는 객체이다. 그리고 a 객체는 Cookie의 인스턴스이다. 즉 인스턴스라는 말은 특정 객체(a)가 어떤 클래스(Cookie)의 객체인지를 관계 위주로 설명할 때 사용한다. "a는 인스턴스"보다는 "a는 객체"라는 표현이 어울리며 "a는 Cookie의 객체"보다는 "a는 Cookie의 인스턴스"라는 표현이 훨씬 잘 어울린다

a = Cookie() 
a는 객체, a는 Cookie의 인스턴스

클래스로 만든 객체의 객체변수는 다른 객체의 객체변수에 상관없이 독립적인 값을 유지한다.
일반 함수와는 달리 메서드(클래스 안에서 구현된 함수)의 첫 번째 매개변수 self는 특별한 의미를 가진다.
파이썬 메서드의 첫 번째 매개변수 이름은 관례적으로 self를 사용한다. 객체를 호출할 때 호출한 객체 자신이 전달되기 때문에 self를 사용한 것이다.
메서드의 첫 번째 매개변수 self를 명시적으로 구현하는 것은 파이썬만의 독특한 특징이다


* 사칙연산 클래스 만들기
class FourCal:
def __init__(self, first, second): # 생성자(Constructor): 객체가 생성될 때 자동으로 호출되는 메서드를 의미
            self.first = first # __init__ 메서드의 init 앞뒤로 붙은 __는 언더스코어(_) 두 개를 붙여 쓴 것이다.
            self.second = second # __init__ 메서드도 다른 메서드와 마찬가지로 첫 번째 매개변수 self에 생성되는 객체가 자동으로 전달된다는 점을 기억하자.
def setdata(self, first, second):
            self.first = first
            self.second = second
def add(self):
            return self.first + self.second
def mul(self):
            return self.first * self.second
        def sub(self):
            return self.first - self.second
        def div(self):
            return self.first / self.second

>>> a = FourCal(4, 2)
>>> a.add()
>>> a.mul()
>>> a.sub()
>>> a.div()


* 클래스 상속 (보통 상속은 기존 클래스를 변경하지 않고 기능을 추가하거나 기존 기능을 변경하려고 할 때 사용한다. 기존 클래스가 라이브러리 형태로 제공되거나 수정이 허용되지 않는 상황이라면 상속을 사용해야 한다.)
class MoreFourCal(FourCal):
def pow(self):
            return self.first ** self.second
>>> a = MoreFourCal(4, 2)
>>> a.pow()


* 메서드 오버라이딩 (Method Overriding)
class SafeFourCal(FourCal):
     def div(self):
         if self.second == 0:  # 나누는 값이 0인 경우 0을 리턴하도록 수정
             return 0
         else:
             return self.first / self.second
SafeFourCal 클래스는 FourCal 클래스에 있는 div 메서드를 동일한 이름으로 다시 작성하였다. 이렇게 부모 클래스(상속한 클래스)에 있는 메서드를 동일한 이름으로 다시 만드는 것을 메서드 오버라이딩(Overriding, 덮어쓰기)이라고 한다. 이렇게 메서드를 오버라이딩하면 부모클래스의 메서드 대신 오버라이딩한 메서드가 호출된다.


* 객체변수, 클래스변수
객체변수는 다른 객체들에 영향받지 않고 독립적으로 그 값을 유지한다. 객체변수와는 성격이 다른 클래스 변수도 있다.
클래스 변수는 클래스 안에 함수를 선언하는 것과 마찬가지로 클래스 안에 변수를 선언하여 생성한다.
클래스 변수는 클래스로 만든 모든 객체에 공유된다는 특징이 있다.
id() 함수를 통해 알아보면 모두 동일한 id를 가지며 즉, 모두 같은 메모리를 가리키고 있는 얘기이다.
실무 프로그래밍을 할 때도 클래스 변수보다는 객체변수를 사용하는 비율이 훨씬 높다.

 
* 모듈
모듈이란 함수나 변수 또는 클래스를 모아 놓은 파일이다. 모듈은 다른 파이썬 프로그램에서 불러와 사용할 수 있게끔 만든 파이썬 파일이라고도 할 수 있다. 우리는 파이썬으로 프로그래밍을 할 때 굉장히 많은 모듈을 사용한다. 다른 사람들이 이미 만들어 놓은 모듈을 사용할 수도 있고 우리가 직접 만들어서 사용할 수도 있다. 
다음과 같은 mod1.py라는 이름의 모듈을 만들어 저장하였다.
# mod1.py
def add(a, b):
    return a + b
def sub(a, b): 
    return a - b

import는 현재 디렉터리에 있는 파일이나 파이썬 라이브러리가 저장된 디렉터리에 있는 모듈만 불러올 수 있다. 파이썬 라이브러리는 파이썬을 설치할 때 자동으로 설치되는 파이썬 모듈을 말한다.
set PYTHONPATH=C:\mymod -> PYTHONPATH 환경 변수를 사용하는 방법
sys 모듈을 이용해 경로를 추가해 줄 수도 있다.
import sys
sys.path.append("C:/mymod")

import mod1 -> 이를 통해 mod1이라는 이름의 모듈을 불러올 수 있다. (import mod1.py가 아니다.)
>>> print(mod1.add(3, 4))
>>> print(mod1.sub(3, 4))

from mod1 import add, sub  -> 이를 통해 인스턴스 없이 모듈 이름을 붙이지 않고 바로 해당 모듈의 함수 add와 sub를 쓸 수 있다. 
from mod1 import *    -> 이를 통해 인스턴스 없이 모듈 이름을 붙이지 않고 바로 해당 모듈의 함수를 모두 쓸 수 있다.
>>> add(3, 4)
>>> sub(3, 4)


* if __name__ == "__main__": 의 의미
# mod1.py 
def add(a, b): 
    return a + b
def sub(a, b): 
    return a - b
if __name__ == "__main__":
    print(add(1, 4))
    print(sub(4, 2))

if __name__ == "__main__"을 사용하면 C:\>python mod1.py처럼 직접 이 파일을 실행했을 때는 __name__ == "__main__"이 참이 되어 if문 다음 문장이 수행된다. 반대로 대화형 인터프리터나 다른 파일에서 이 모듈을 불러서 사용할 때는 __name__ == "__main__"이 거짓이 되어 if문 다음 문장이 수행되지 않는다.

파이썬의 __name__ 변수는 파이썬이 내부적으로 사용하는 특별한 변수 이름이다. 만약 C:\>python mod1.py처럼 직접 mod1.py 파일을 실행할 경우 mod1.py의 __name__ 변수에는 __main__ 값이 저장된다. 하지만 파이썬 셸이나 다른 파이썬 모듈에서 mod1을 import 할 경우에는 mod1.py의 __name__ 변수에는 mod1.py의 모듈 이름 값 mod1이 저장된다.


* 패키지
패키지(Packages)는 도트(.)를 사용하여 파이썬 모듈을 계층적(디렉터리 구조)으로 관리할 수 있게 해준다. 예를 들어 모듈 이름이 A.B인 경우에 A는 패키지 이름이 되고 B는 A 패키지의 B모듈이 된다.
파이썬 패키지는 디렉터리와 파이썬 모듈로 이루어지며 구조는 다음과 같다.
가상의 game 패키지 예

game/
    __init__.py
    sound/
        __init__.py
        echo.py
        wav.py
    graphic/
        __init__.py
        screen.py
        render.py
    play/
        __init__.py
        run.py
        test.py
game, sound, graphic, play는 디렉터리 이름이고 확장자가 .py인 파일은 파이썬 모듈이다. game 디렉터리가 이 패키지의 루트 디렉터리이고 sound, graphic, play는 서브 디렉터리이다.


* 패키지 안의 함수 실행하기
1. echo 모듈을 import하여 실행하는 방법
import game.sound.echo
game.sound.echo.echo_test()

2. echo 모듈이 있는 디렉터리까지를 from ... import하여 실행하는 방법
from game.sound import echo
echo.echo_test()

3. echo 모듈의 echo_test 함수를 직접 import하여 실행하는 방법
from game.sound.echo import echo_test
echo_test()

4. 하지만 다음과 같이 echo_test 함수를 사용하는 것은 불가능하다
import game
game.sound.echo.echo_test()
import game을 수행하면 game 디렉터리의 모듈 또는 game 디렉터리의 __init__.py에 정의한 것만 참조할 수 있다.

5. 또 다음처럼 echo_test 함수를 사용하는 것도 불가능하다.
import game.sound.echo.echo_test
도트 연산자(.)를 사용해서 import a.b.c처럼 import할 때 가장 마지막 항목인 c는 반드시 모듈 또는 패키지여야만 한다.

6. 또 다음처럼 import하는 것도 불가능하다.
from game.sound import *
echo.echo_test()
분명 game.sound 패키지에서 모든 것(*)을 import하였으므로 echo 모듈을 사용할 수 있어야 할 것 같은데 echo라는 이름이 정의되지 않았다는 이름 오류(NameError)가 발생한다.
이렇게 특정 디렉터리의 모듈을 *를 사용하여 import할 때에는 다음과 같이 해당 디렉터리의 __init__.py 파일에 __all__ 변수를 설정하고 import할 수 있는 모듈을 정의해 주어야 한다.

# C:/game/sound/__init__.py
__all__ = ['echo']

여기에서 __all__이 의미하는 것은 sound 디렉터리에서 * 기호를 사용하여 import할 경우 이곳에 정의된 echo 모듈만 import된다는 의미이다.
착각하기 쉬운데 from game.sound.echo import * 는 __all__과 상관없이 무조건 import된다. 이렇게 __all__과 상관없이 무조건 import되는 경우는 from a.b.c import * 에서 from의 마지막 항목인 c가 모듈인 경우이다.


* __init__.py 의 용도
__init__.py 파일은 해당 디렉터리가 패키지의 일부임을 알려주는 역할을 한다. 만약 game, sound, graphic 등 패키지에 포함된 디렉터리에 __init__.py 파일이 없다면 패키지로 인식되지 않는다.
python3.3 버전부터는 __init__.py 파일이 없어도 패키지로 인식한다. 하지만 하위 버전 호환을 위해 __init__.py 파일을 생성하는 것이 안전한 방법이다.


* try, except문 오류 예외 처리 
try:
    ...
except [발생 오류[as 오류 메시지 변수]]:
    ...
try 블록 수행 중 오류가 발생하면 except 블록이 수행된다. 하지만 try 블록에서 오류가 발생하지 않는다면 except 블록은 수행되지 않는다.
위 구문을 보면 [ ] 기호를 사용하는데, 이 기호는 괄호 안의 내용을 생략할 수 있다는 관례 표기법이다. 즉 except 구문은 다음 3가지 방법으로 사용할 수 있다.

1) try:
    ...
except:
    ...
2) try:
    ...
except 발생 오류:
    ...
3) try:
    ...
except 발생 오류 as 오류 메시지 변수:
    ...


* try .. finally문 오류 예외 처리
finally절은 try문 수행 도중 예외 발생 여부에 상관없이 항상 수행된다. 보통 finally절은 사용한 리소스를 close해야 할 때에 많이 사용한다.


* raise NotImplementedError (오류 일부러 발생시키기)
NotImplementedError는 파이썬 내장 오류로, 꼭 작성해야 하는 부분이 구현되지 않았을 경우 일부러 오류를 일으키기 위해 사용한다.


* 예외 만들기
프로그램 수행 도중 특수한 경우에만 예외 처리를 하기 위해서 종종 예외를 만들어서 사용한다. 직접 예외를 만들어 보자. 예외는 다음과 같이 파이썬 내장 클래스인 Exception 클래스를 상속하여 만들 수 있다.

class MyError(Exception):
    def __str__(self):
        return "허용되지 않는 별명입니다."

def say_nick(nick):
    if nick == '바보':
        raise MyError()
    print(nick)

try:
    say_nick("천사")
    say_nick("바보")
except MyError:
    print("허용되지 않는 별명입니다.")

try:
    say_nick("천사")
    say_nick("바보")
except MyError as e:
    print(e)

프로그램을 실행하면 다음과 같이 출력된다.

천사
허용되지 않는 별명입니다.




<references>


파이썬의 기본과 자료형, 배열(Array)과 리스트(List) 등등 Python


* 파이썬은 0부터 숫자를 센다.

* 문자열, 리스트, 튜플, 딕셔너리 등의 값이 비어 있으면(" ", [ ], ( ), { }) 거짓이 된다. 당연히 비어있지 않으면 참이 된다. 숫자에서는 그 값이 0일 때 거짓이 된다. 또한, None도 거짓을 뜻한다.

* 배열 (Array) - 정적 할당
데이터가 많아지면 그룹 관리의 필요성 -> 배열
같은 종류의 여러 데이터를 하나의 이름으로 그룹핑해서 효율적으로 관리
배열을 이용하면 하나의 변수에 여러 정보를 담을 수 있고, 반복문과 결합 하면 많은 정보도 효율적으로 처리
배열 인덱스는 값에 대한 유일무이한 식별자 (참고로 리스트에서 인덱스는 몇 번째 데이터인가 정도의 의미를 가짐)
그러므로 인덱스 번호로 빠른접근이 가능, 즉 데이터의 위치에 대해 직접적인 접근(Access)가 가능

배열은 길이를 바꿀 수 없는 한계가 있으며, 인덱스에 따라서 값을 유지하기 때문에 엘리먼트가 삭제되어도 빈자리(null)가 남게 된다. (불필요한 메모리 차지)
중간에 데이터 삭제나 데이터의 추가 및 삭제가 불편
위와 같은 한계를 해결하기 위해서 linked list 자료형을 활용할 수 있다. (탐색, 할당, 복사, 삭제 등의 리소스 낭비가 없다.)


* 리스트 (List) - 동적 할당
리스트는 배열이 가지고 있는 인덱스라는 장점을 버리고 대신 빈틈없는 데이터의 적재 라는 장점을 취한 데이터 스트럭쳐
리스트 자료구조의 핵심은 엘리먼트들 간의 순서. 따라서 리스트를 다른 말로는 시퀀스(sequence)
즉 순서가 있는 데이터의 모임이 리스트
리스트에서 인덱스는 몇 번째 데이터인가 정도의 의미를 가짐 (배열에서의 인덱스는 값에 대한 유일무이한 식별자)
빈 엘리먼트는 허용하지 않음
포인터를 통하여 다음 데이터의 위치를 가르키고 있으므로 삽입 삭제가 쉬움. 
동적이므로 배열과 다르게 크기가 정해져있지 않음.
검색 성능이 좋지 못함. 이유는 배열은 데이터의 위치에 대해서 직접적인 접근이 가능하지만, 리스트는 직접 접근이 불가능하고 처음부터 몇 번째인지 일일이 세어가면서 위치를 찾기 때문


- 데이터 갯수가 확실하게 정해져 있고, 추가적인 삽입 삭제가 없고 검색이 필요할 때 배열이 더 효율적
데이터의 크기가 정해져 있지 않고, 추가적인 삼입 삭제가 많으며 검색이 필요하지 않을때 리스트가 더 효율적
인덱스가 중요한 경우는 배열을 사용, 인덱스가 중요하지 않은 경우에는 리스트를 사용
리스트에 대한 효용은 어떤 언어를 사용하느냐에 따라서 달라진다. 특히 많은 언어가 리스트를 기본적으로 지원하기 때문에 리스트를 직접 구현하는 경우는 줄고 있음


* C
리스트를 지원하지 않음. 대신 배열을 지원.
리스트를 사용하려면 직접 만들거나 라이브러리를 사용해야함. (따라서 리스트에 대한 깊은 이해와 안목이 필요)

* Python
기본적으로 리스트를 제공하며, 배열은 제공하지 않음.
파이썬에서는 리스트가 배열.
파이썬의 리스트는 크기가 가변적이고, 어떤 원소 타입이던 저장할 수 있다는 장점을 가진다. 
대신 C의 배열보다 메모리를 더 많이 필요로 한다는 단점이 있음.


* Numpy Array
Numpy를 사용하면 Array를 Python에서 사용할 수 있습니다.
동적으로 계속 크기가 변할 수 있는 Python List와 달리 NumPy Array는 고정된 크기를 갖습니다. Size를 변화하면 기존의 array를 삭제하고 새로운 array를 생성해야 합니다.

NumPy Array는 대량의 데이터에 대한 고급 수학적 및 기타 유형의 작업을 용이하게 합니다. 일반적으로 Python의 기본 제공 기능을 사용하여 가능한 것보다 적은 코드로 보다 효율적으로 작업 수행할 수 있습니다. NumPy를 쓰는 메인 이유라고 할 수 있습니다. 훨씬 효율적이고 쉽게 코딩할 수 있습니다.
과학적이고 수학적 Python 기반 패키지의 수가 증가하고 있지만 대부분이 NumPy 어레이를 사용하고 있다. 입력받은 파이썬 시퀀스 입력을 지원하며, 처리하기 전에 NumPy 어레이로 변환하고 종종 NumPy Array를 출력합니다. 즉, 많은 양을 효율적으로 사용하기 위해 Python의 내장 시퀀스로는 한계가 있으므로 오늘날의 과학/수학적인 NumPy 어레이를 사용하는 방법도 알아야만 데이터사이언스, 빅데이터분석, 머신러닝, 딥러닝 등을 진행하는데 필수적입니다.

Numpy array 접근 -> a[0,0]
Python list 접근 -> b[0][0]

1. numpy array는 numpy array끼리 연산이 가능하지만 Python list는 덧셈만 가능하다.
numpy array 에 numpy array를 더해주면 같은 인덱스에 있는 값들 끼리 더해진다.
예를들어 [10, 5, 3, 7, 1, 5] + [10, 5, 3, 7, 1, 5] = [20, 10, 6, 14, 2, 10] 이런식으로 덧셈 계산을 할 수 있다.

반면 Python list에서는 두 리스트의 값들이 한 리스트로 들어간다.
예를들어 [10, 5, 3, 7, 1, 5] + [10, 5, 3, 7, 1, 5] = [10, 5, 3, 7, 1, 5, 10, 5, 3, 7, 1, 5] 이런식으로 앞의 리스트 뒤에 뒤의 리스트 값이 붙어서 한 리스트로 만들어진다.

같은 맥락으로 numpy array는 numpy array 끼리 뺄셈, 곱셈, 나눗셈이 가능하다. 같은 인덱스에 있는 값들끼리 연산해준다. Pythom list는 리스트끼리 뺄셈, 곱셈, 나눗셈을 하면 오류가 난다.

2. numpy array는 array 전체에 연산이 가능하지만 Python list는 곱셈만 가능하다.
numpy array와 숫자의 연산을 하면 array에 들어가있는 각 값에 연산이 된다.
예를들어 [10, 5, 3, 7, 1, 5] + 5 = [15, 10, 8, 12, 6, 10] 와 같이 array 안에 들어가있는 각 값에 +5가 된다.
덧셈뿐 아니라 뺄셈, 곱셈, 나눗셈 모두 우리가 예상하는 결과대로 값이 나온다.

반면 Python list는 곱셈만 가능한데 이도 array처럼 각 값에 곱을 해주는 것이 아니라 list의 요소를 반복한다.
예를들어 [10, 5, 3, 7, 1, 5] * 2 = [10, 5, 3, 7, 1, 5, 10, 5, 3, 7, 1, 5] 이런식으로 나온다.

3. numpy array가 python list에 비해 문법이 간단하고 성능이 뛰어나다.
예를들어 1억개의 요소가 있는 기본 python list에 곱하기 2를 하려면 반복문을 1억번 돌려야 하는데 numpy array는 그냥 * 2 만 붙여주면 된다. 문법이 간단할 뿐만 아니라 실제 실행했을 때도 numpy array가 훨씬 짧은 시간에 연산을 마친다.

성능차이가 나는 이유를 간단히 말하면 값들이 저장되는 방식에 차이가 있기 때문이다. python list는 다양한 자료형이 저장가능 하지만 numpy array는 같은 자료형만 넣을 수 있다. 따라서 python list는 값을 추가하고 제거하는 일에 쓰고, numpy array는 수치 계산이 많고 복잡할 때나 행렬같은 다차원 배열을 쓸 때 사용하면 된다.


* 튜플(tuple)과 딕셔너리{dictionary}
튜플(tuple)은 몇 가지 점을 제외하곤 배열이나 리스트와 거의 비슷하며 리스트와 다른 점은 다음과 같다.
리스트는 [ ]으로 둘러싸지만 튜플은 ( )으로 둘러싼다.
리스트는 그 값의 생성, 삭제, 수정이 가능하지만 튜플은 생성하고 나면 그 값을 삭제, 변경을 할 수 없다.
단지 1개의 요소만을 가질 때는 요소 뒤에 콤마(,)를 반드시 붙여야 한다는 것과 괄호( )를 생략해도 무방하다는 점이다.

얼핏 보면 튜플과 리스트는 비슷한 역할을 하지만 프로그래밍을 할 때 튜플과 리스트는 구별해서 사용하는 것이 유리하다. 튜플과 리스트의 가장 큰 차이는 값을 변화시킬 수 있는가 여부이다. 즉 리스트의 항목 값은 변화가 가능하고 튜플의 항목 값은 변화가 불가능하다. 따라서 프로그램이 실행되는 동안 그 값이 항상 변하지 않기를 바란다거나 값이 바뀔까 걱정하고 싶지 않다면 주저하지 말고 튜플을 사용해야 한다. 이와는 반대로 수시로 그 값을 변화시켜야할 경우라면 리스트를 사용해야 한다. 실제 프로그램에서는 값이 변경되는 형태의 변수가 훨씬 많기 때문에 평균적으로 튜플보다는 리스트를 더 많이 사용한다.

튜플은 요소를 지우거나 값을 변경할려고 시도한다면 지원되지 않는다는 오류 메시지가 나온다.

사람은 누구든지 "이름" = "홍길동", "생일" = "몇 월 몇 일" 등으로 구별할 수 있다. 파이썬은 영리하게도 이러한 대응 관계를 나타낼 수 있는 자료형을 가지고 있다. 요즘 사용하는 대부분의 언어도 이러한 대응 관계를 나타내는 자료형을 갖고 있는데, 이를 연관 배열(Associative array) 또는 해시(Hash)라고 한다.

파이썬에서는 이러한 자료형을 딕셔너리(Dictionary)라고 하는데 딕셔너리 {dictionary}는 사전형태의 자료구조이며 순서가 없다 (unordered)
Key 와 Value으로 구분되며, Key를 사용하여 값에 접근 가능하다.
배열이나 튜플처럼 인덱스를 활용하여 Value 에 접근할 수 없다. 
딕셔너리는 리스트나 튜플처럼 순차적으로(sequential) 혹은 인덱스로 해당 요솟값을 구하지 않고 Key를 통해 Value를 얻는다.
Key 를 사용하여 값을 추가, 변경, 삭제가 가능하다. 
동일한 Key 자료는 존재할 수 없다. 

딕셔너리에서 Key는 고유한 값이므로 중복되는 Key 값을 설정해 놓으면 하나를 제외한 나머지 것들이 모두 무시된다는 점을 주의해야 한다. 동일한 Key가 2개 존재할 경우 나중에 입력된 것을 제외하고 나머지는 무시된다.

Key와 Value로 정수 값과 문자열을 넣을 수 있으며, Value에 리스트이나 듀플도 넣을 수 있다.
Key에 듀플은 넣을 수 있으나 리스트는 넣을 수 없다. 딕셔너리의 Key로 쓸 수 있느냐 없느냐는 Key가 변하는 값인지 변하지 않는 값인지에 달려 있다. 리스트는 그 값이 변할 수 있기 때문에 Key로 쓸 수 없다.

a.keys() -> 딕셔너리 a의 Key만을 모아서 dict_keys 객체를 돌려준다.
list(a.keys()) -> dict_keys 객체를 리스트로 변환
a.values() -> 딕셔너리 a의 Value만을 모아서 dict_values 객체를 돌려준다.
a.items() -> Key와 Value의 쌍을 튜플로 묶은 값을 dict_items 객체로 돌려준다. 
dict_values 객체와 dict_items 객체 역시 dict_keys 객체와 마찬가지로 리스트를 사용하는 것과 동일하게 사용할 수 있다.
a.clear() -> 딕셔너리 안의 모든 요소를 삭제. 빈 리스트를 [ ], 빈 튜플을 ( )로 표현하는 것과 마찬가지로 빈 딕셔너리도 { }로 표현됨
a.get('name') -> get(x) 함수는 x라는 Key에 대응되는 Value를 돌려준다. a.get('name')와 a['name']는 동일
다만, 존재하지 않는 키로 값을 가져오려고 할 경우 a['name']는 Key 오류를 발생시키고 a.get('name')는 None을 돌려준다는 차이가 있다. 
'name' in a -> 해당 Key 'name'이 딕셔너리 a 안에 있는지 조사하기(in), True or False로 반환

리스트: list = [1, 2, 3, 4], list[0]
튜플: tup = (1,2,3,4), tup[0]
딕셔너리: dic = {"january":1, "February": 2, "March":3 }, dic["March"]


* 집합 (set)
집합은 중복되는 요소가 없는 순서 없는 컬렉션입니다. 기본적인 용도는 멤버십 검사와 중복 엔트리 제거입니다. 집합 객체는 합집합, 교집합, 차집합, 대칭 차집합과 같은 수학적인 연산들도 지원합니다.

리스트나 튜플은 순서가 있기(ordered) 때문에 인덱싱을 통해 자료형의 값을 얻을 수 있지만 set 자료형은 순서가 없기(unordered) 때문에 인덱싱으로 값을 얻을 수 없다. 이는 마치 딕셔너리와 비슷하다. 딕셔너리 역시 순서가 없는 자료형이라 인덱싱을 지원하지 않는다.

만약 set 자료형에 저장된 값을 인덱싱으로 접근하려면 리스트나 튜플로 변환한후 해야 한다.
중복을 허용하지 않는 set의 특징은 자료형의 중복을 제거하기 위한 필터 역할로 종종 사용하기도 한다.

set 자료형을 정말 유용하게 사용하는 경우는 교집합, 합집합, 차집합을 구할 때이다.
1. 교집합
s1 & s2, s1.intersection(s2), s2.intersection(s1)

2. 합집합
s1 | s2, s1.union(s2), s2.union(s1)

3. 차집합
s1 - s2, s1.difference(s2)
s2 - s1, s2.difference(s1)

4. 집합에 값 추가
s1.add(4) # 값 1개 추가하기(add)
s1.update([4, 5, 6]) # 값 여러 개 추가하기(update)
s1.remove(2) # 특정 값 제거하기(remove)


* 연산자
제곱: **, ex) 3 ** 4 = 81
나눗셈 후 나머지를 반환: %, ex) 7 % 3 = 1
나눗셈 후 몫을 반환: //, ex) 7 // 3 = 2


* 문자열
1. 큰따옴표(")로 양쪽 둘러싸기
2. 작은따옴표(')로 양쪽 둘러싸기
3. 큰따옴표 3개를 연속(""")으로 써서 양쪽 둘러싸기
4. 작은따옴표 3개를 연속(''')으로 써서 양쪽 둘러싸기
5. 문자열은 더해서 (+) 연결할 수 있다.
6. 문자열은 곱해서 (*) 반복시킬 수 있다.
7. 문자열 자료형은 그 요소값을 변경할 수 없다. 그래서 immutable한 자료형이라고도 부른다

* 문자열 슬라이싱 (Slicing)
a[0:4]
슬라이싱 기법으로 a[시작 번호:끝 번호]를 지정할 때 끝 번호에 해당하는 것은 포함하지 않는다. 
a[0:4]을 수식으로 나타내면 다음과 같다.
0 <= a < 4

a[19:] - a[시작 번호:끝 번호]에서 끝 번호 부분을 생략하면 시작 번호부터 그 문자열의 끝까지 뽑아낸다.
a[:17] - a[시작 번호:끝 번호]에서 시작 번호를 생략하면 문자열의 처음부터 끝 번호까지 뽑아낸다.
a[:] - a[시작 번호:끝 번호]에서 시작 번호와 끝 번호를 생략하면 문자열의 처음부터 끝까지를 뽑아낸다.
a[19:-7] - 슬라이싱에서도 인덱싱과 마찬가지로 마이너스(-) 기호를 사용할 수 있다.

* 문자열 포매팅
"I ate %d apples. so I was sick for %s days." % (number, day)
"I ate {0} apples. so I was sick for {1} days.".format(number, day)
"I ate {number} apples. so I was sick for {day} days.".format(number=10, day=3)
"I ate {0} apples. so I was sick for {day} days.".format(10, day=3)

%s: 문자열 string 
%d: 문자 1개 char
%d: 정수 int
%f: 부동소수 float
%o: 8진수
%x: 16진수


* 문자열 관련 함수들
a.count('b') -> 문자열 중 문자 b의 개수를 돌려준다.
a.find('b') -> 문자열 중 문자 b가 처음으로 나온 위치를 반환한다. 만약 찾는 문자나 문자열이 존재하지 않는다면 -1을 반환한다.
a.index('k') -> 문자열 중 문자 k가 맨 처음으로 나온 위치를 반환한다. 만약 찾는 문자나 문자열이 존재하지 않는다면 오류를 발생시킨다. 앞의 find 함수와 다른 점은 문자열 안에 존재하지 않는 문자를 찾으면 오류가 발생한다는 점이다.
",".join('abcd') -> abcd 문자열의 각각의 문자 사이에 ','를 삽입한다.
join 함수는 문자열뿐만 아니라 리스트나 튜플도 입력으로 사용할 수 있다.
",".join(['a', 'b', 'c', 'd']) -> join 함수의 입력으로 리스트를 사용하는 예
a.upper() -> upper 함수는 소문자를 대문자로 바꾸어 준다. 만약 문자열이 이미 대문자라면 아무 변화도 일어나지 않을 것이다.
a.lower() -> lower 함수는 대문자를 소문자로 바꾸어 준다.
a.lstrip() -> 문자열 중 가장 왼쪽에 있는 한 칸 이상의 연속된 공백들을 모두 지운다. lstrip에서 l은 left를 의미한다.
a.rstrip() -> 문자열 중 가장 오른쪽에 있는 한 칸 이상의 연속된 공백을 모두 지운다. rstrip에서 r는 right를 의미한다.
a.strip() -> 문자열 양쪽에 있는 한 칸 이상의 연속된 공백을 모두 지운다.
a.replace("Life", "Your leg") -> replace(바뀌게 될 문자열, 바꿀 문자열)처럼 사용해서 문자열 안의 특정한 값을 다른 값으로 치환해 준다.
a.split() -> split 함수는 a.split()처럼 괄호 안에 아무 값도 넣어 주지 않으면 공백(스페이스, 탭, 엔터 등)을 기준으로 문자열을 나누어 준다. 만약 b.split(':')처럼 괄호 안에 특정 값이 있을 경우에는 괄호 안의 값을 구분자로 해서 문자열을 나누어 준다. 이렇게 나눈 값은 리스트에 하나씩 들어가게 된다.


* 리스트 연산 오류
a = [1, 2, 3]
a[2] + "hi"
-> Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'
형 오류(TypeError)가 발생. a[2]에 저장된 값은 3이라는 정수인데 "hi"는 문자열이다. 정수와 문자열은 당연히 서로 더할 수 없기 때문에 형 오류가 발생한 것이다.
만약 숫자와 문자열을 더해서 '3hi'처럼 만들고 싶다면 숫자 3을 문자 '3'으로 바꾸어 주어야 한다. 다음과 같이 할 수 있다.
str(a[2]) + "hi"
str 함수는 정수나 실수를 문자열의 형태로 바꾸어 주는 파이썬의 내장 함수이다.


* 리스트 관련 함수들
a.append(4) -> a 리스트의 맨 마지막에 4를 추가하는 함수이다. 리스트 안에는 어떤 자료형도 추가할 수 있다.
a.append([5,6]) -> a 리스트의 맨 마지막에 [5,6]을 추가하는 함수이다.
a.sort() -> 숫자를 오름차순으로, 문자를 알파벳 순서로 정렬할 수 있다.
a.reverse() -> reverse 함수는 리스트를 역순으로 뒤집어 준다. 이때 리스트 요소들을 순서대로 정렬한 다음 다시 역순으로 정렬하는 것이 아니라 그저 현재의 리스트를 그대로 거꾸로 뒤집는다.
a.index(1) -> 리스트 a에 숫자 1이 처음으로 오는 위치를 반환한다. a 리스트에 존재하지 않는다면 값오류(ValueError)가 발생한다.
a.insert(0, 4) -> 리스트의 0번째 위치에 4를 삽입하는 함수이다. 파이썬에서는 숫자를 0부터 센다는 것을 반드시 기억하자.
a.remove(3) -> 리스트에서 첫 번째로 나오는 3을 삭제하는 함수이다.
a.pop() -> 리스트의 맨 마지막 요소를 돌려주고 그 요소는 삭제한다.
a.pop(1) -> 리스트의 1번째 요소를 돌려주고 그 요소는 삭제한다.
a.count(1) -> 리스트 안에 1이 몇 개 있는지 조사하여 그 개수를 돌려주는 함수이다.
a.extend(b) -> extend(x)에서 x에는 리스트만 올 수 있으며 원래의 a 리스트에 b 리스트를 더하게 된다. a.extend(b)는 a += b와 동일하다.


* 리스트 복사
b = a -> 리스트 a를 "복제"히여 리스트 b를 생성, 리스트의 값 뿐만 아니라 저장되는 메모리 주소도 동일, 즉 a를 바꾸면 b까지 바뀜 
b = a[:] -> 리스트 a를 "복사"히여 리스트 b를 생성, 리스트의 값은 동일하지만 저장되는 메모리 주소는 다음, 즉 a를 바꾸더라도 b에 영향을 미치지 못함
b = copy(a) -> from copy import copy 필요, b = a[:]와 동일

(a, b) = 'python', 'life' -> 튜플로 a, b에 값을 대입할 수 있다. 튜플은 괄호를 생략해도 된다.
[a,b] = ['python', 'life'] -> 리스트로 변수를 만들 수도 있다.
a = b = 'python' -> 여러 개의 변수에 같은 값을 대입할 수도 있다.

>>> a = 3
>>> b = 5
>>> a, b = b, a
>>> a
5
>>> b
3
-> 위 방법을 사용하여 두 변수의 값을 아주 간단히 바꿀 수 있다.


* 조건문, 제어문
x in 리스트, 듀플, 문자열 -> 리스트, 듀플, 문자열 안에 x가 있는가 라는 조건문이다.
x not in 리스트, 듀플, 문자열 -> 리스트, 듀플, 문자열 안에 x가 없는가 라는 조건문이다.

if문을 한 줄로 작성하기
if문 다음에 수행할 문장이 한 줄이고, else문 다음에 수행할 문장도 한 줄이라면 다음과 같이 간략히 코드를 작성할 수 있다.
if 'money' in pocket:
    pass 
else:
    print("카드를 꺼내라")
-> if 'money' in pocket: pass
   else: print("카드를 꺼내라")


* 조건부 표현식 (conditional expression)
if score >= 60:
    message = "success"
else:
    message = "failure"
위 코드는 score가 60 이상일 경우 message에 문자열 "success"를, 아닐 경우에는 "failure"를 대입하는 코드이다.
파이썬의 조건부 표현식(conditional expression)을 사용하면 위 코드를 다음과 같이 간단히 표현할 수 있다.
-> message = "success" if score >= 60 else "failure"

조건부 표현식은 다음과 같이 정의한다.
(조건문이 참인 경우) if (조건문) else (조건문이 거짓인 경우)
조건부 표현식은 가독성에 유리하고 한 줄로 작성할 수 있어 활용성이 좋다.


* for나 while문 안의 문장을 수행할 때 입력 조건을 검사해서 조건에 맞지 않으면 break문으로 for나 while문을 빠져나간다. 그런데 프로그래밍을 하다 보면 for나 while문을 빠져나가지 않고 for나 while문의 맨 처음(조건문)으로 다시 돌아가게 만들고 싶은 경우가 생기게 된다. 이때 사용하는 것이 바로 continue문이다.


* for문의 기본 구조는 다음과 같다.
for 변수 in 리스트(또는 튜플, 문자열):
    수행할 문장1
    수행할 문장2

for문과 함께 자주 사용하는 range 함수
for문은 숫자 리스트를 자동으로 만들어 주는 range 함수와 함께 사용하는 경우가 많다. 
a = range(10) -> range(10)은 0부터 10 미만의 숫자를 포함하는 range 객체를 만들어 준다.
a = range(1, 11) -> 시작 숫자와 끝 숫자를 지정하려면 range(시작 숫자, 끝 숫자) 형태를 사용하는데, 이때 끝 숫자는 포함되지 않는다.


* 리스트 내포(List comprehension)
리스트 안에 for문을 포함하는 List comprehension를 사용하면 좀 더 편리하고 직관적인 프로그램을 만들 수 있다.

a = [1,2,3,4]
result = []
for num in a:
    result.append(num*3)
-> a = [1,2,3,4]
result = [num*3 for num in a]

만약 [1,2,3,4] 중에서 짝수에만 3을 곱하여 담고 싶다면 다음과 같이 리스트 내포 안에 "if 조건"을 사용할 수 있다.
a = [1,2,3,4]
result = [num*3 for num in a if num % 2 == 0]

리스트 내포의 일반 문법은 다음과 같다. "if 조건" 부분은 앞의 예제에서 볼 수 있듯이 생략할 수 있다.
(표현식) for (항목) in (리스트,배열,문자열) if (조건문)


* 추천 에디터
- 비주얼 스튜디오 코드
비주얼 스튜디오 코드(Visual Studio Code)는 파이참과 더불어 프로그래머들에게 가장 많은 사랑을 받는 파이썬의 대표적인 에디터이다. 비주얼 스튜디오 코드는 공식 다운로드 사이트 (https://code.visualstudio.com)에서 내려받을 수 있다.
비주얼 스튜디오 코드는 파이썬 전용 에디터가 아니다(파이썬 외에 여러 가지 언어를 지원하는 에디터이다). 따라서 비주얼 스튜디오 코드를 설치한 후 파이썬 편집을 위해 가장 먼저 해야 할 일 은 파이썬 Extension을 설치하는 것이다. 파이썬 Extension은 비주얼 스튜디오 코드를 실행 한 후 Extension 메뉴를 사용하여 설치할 수 있다.

- 파이참
파이썬에 어느 정도 익숙해졌다면 파이참(PyCharm)을 사용해 보기를 적극 추천한다. 파이참은 가장 유명한 파이썬 에디터 중 하나로서 코드를 작성할 때 자동 완성, 문법 체크 등 편리한 기능을 많이 제공한다.
이 에디터는 파이참 공식 다운로드 사이트(http://www.jetbrains.com/pycharm/download)에서 내려 받을 수 있다.
파이참은 파이썬 전용 에디터로서 별도의 Extension이나 플러그인을 따로 설치할 필요가 없다.




<References>


Intel RealSense T265 on Raspberry Pi 3 Linux / ROS

- System Requirements
A Raspberry Pi 3 Model B with 32GB micro SD card & Running Ubuntu MATE 16.04 LTS

- Installation Instruction
At first, it is required to increase swap size because RPi does not have enough RAM to compile the SDK.
Swap size of 2048 (2GB) seems to do the trick, but you can try other values. 

sudo apt-get install dphys-swapfile  # Install dependencies
sudo dphys-swapfile swapoff    # Toggle swap off
sudo nano /etc/dphys-swapfile  # Editing variable CONF_SWAPSIZE=2048 to increase the swap size to 2048 
sudo dphys-swapfile swapon    # Toggle swap back on 
sudo reboot          # Reboot your raspberry
free # Check that swap size changed, should show something like Swap: 2097148


Second, clone librealsense repository and compile SDK.

# Update system
sudo apt update
sudo apt upgrade -y

# Install dependencies
sudo apt-get install ros-kinetic-ddynamic_reconfigure
sudo apt install xorg-dev libglu1-mesa-dev
sudo apt install git libssl-dev libusb-1.0-0-dev pkg-config -y
sudo apt install cmake python3-dev
sudo apt install raspberrypi-kernel-headers -y (only for raspberry pi)

# Clone the repository under home
cd ~
git clone https://github.com/IntelRealSense/librealsense.git
cd librealsense

# Install udev rules
sudo cp config/99-realsense-libusb.rules /etc/udev/rules.d/
sudo udevadm control --reload-rules && udevadm trigger

# Create the destination directory
mkdir build
cd build

# Remove extra files if this is not your first run
xarg sudo rm < install_manifest.txt
rm CMakeCache.txt
export CC=/usr/bin/gcc-5
export CXX=/usr/bin/g++-5
cmake -D CMAKE_BUILD_TYPE="Release"\
-D FORCE_LIBUVC=ON \
-D BUILD_PYTHON_BINDINGS=ON \
-D BUILD_EXAMPLES=ON ..
make -j4
sudo make install
sudo ldconfig

# Finally, reboot the pi:
sudo reboot


Third, clone realsense-ros repository and compile it.

sudo apt-get install ros-kinetic-ddynamic-reconfigure
git clone https://github.com/IntelRealSense/realsense-ros.git
cd realsense-ros/
git checkout `git tag | sort -V | grep -P "^\d+\.\d+\.\d+" | tail -1`
cd ..

catkin_init_workspace
cd ..
catkin_make clean
catkin_make -DCATKIN_ENABLE_TESTING=False -DCMAKE_BUILD_TYPE=Release
catkin_make install
echo "source ~/catkin_ws/devel/setup.bash" >> ~/.bashrc
source ~/.bashrc


Finally, try to test camera node in ROS.

roslaunch realsense2_camera rs_camera.launch



< References >


윈도우에 파이썬, IPython 설치하기 완벽 가이드 Python

https://www.lucypark.kr/blog/2013/02/06/python-and-ipython-on-windows/

1 2 3