클래스 변수

  • C++/Java에서 static 멤버 변수와 같은 역할
  • 정의 방법
    class ClassName1:
      var1 = None
      ...
    
  • 사용 방법 : [클래스명].[변수명], [인스턴스명].[변수명] 모두 가능


인스턴스 변수

  • C++/Java에서 비 static 멤버 변수와 같은 역할
  • 정의 방법
    class ClassName2:
      def __init__(self):
        self.var2 = None
        ...
    
  • 사용 방법 : [인스턴스명].[변수명] 만 가능
  • 같은 이름일 경우, 인스턴스 변수에서 먼저 찾고 클래스 변수에서 찾는다


<테스트 환경> 
- OS : Windows 10 
- Python 버전 : 3.7.5
,
현재의 티스토리 에디터는 직접 markdown 편집도 지원을 하고 있지만, 구 버전의 편집기 사용시에 다음과 같은 markdown 소스를 작성하여 HTML 변환을 한 후 티스토리 소스에 붙여넣을 경우,


## 제목1
본문

## 제목2
- 리스트1
- 리스트2

본문

## 제목2
본문

- 리스트1
- 리스트2


아래와 같이 깔끔하지 않게 나오지 않는 경우가 있는데, (특히, 단락 앞뒤에 공백 옵션을 사용하지 않았을 경우. 적용되는 스킨의 CSS에 따라 차이는 있을 수 있음.)


제목1

본문

제목2

  • 리스트1
  • 리스트2

본문

제목2

본문

  • 리스트1
  • 리스트2


이 변환기를 사용할 경우, 다음과 같이 추가적인 줄바꿈을 넣어줘서,


## 제목1
<p><br></p>
본문
 
<p><br></p>
<p><br></p>
## 제목2
- 리스트1
- 리스트2
 
본문
 
<p><br></p>
<p><br></p>
## 제목2
<p><br></p>
본문
 
- 리스트1
- 리스트2


HTML 변환후에, 아래 결과와 같이 보기좋게(?) 표시될 수 있게합니다.


제목1


본문



제목2

  • 리스트1
  • 리스트2

본문



제목2


본문

  • 리스트1
  • 리스트2


변환기 소스


md_convert.py:

# -*- coding: utf-8 -*-
#!/usr/bin/python

import sys

DOUBLE_BR_BEFORE_HEADER = True

STATUS_START = 0
STATUS_NONE = 1
STATUS_LIST = 2
STATUS_PRE = 3
STATUS_HEADER = 4

LINE_BR = "<p><br></p>\n"

def print_usage():
    print("usage: python md_convert.py [option]")
    print("Options:")
    print("-i input-file : 지정된 입력 파일을 사용하여 변환을 하고 입력 파일을 덮어씁니다.")
    print("-i input-file output-file : 지정된 입력 파일과 출력 파일을 사용하여 변환을 합니다.")

def is_ol_item(str):
    pos = str.find(". ")
    if pos == -1:
        return False
    return str[:pos].isdigit()

def go_convert(config):
    filename_in = config["filename_in"]
    filename_out = config["filename_in"]
    if "filename_out" in config:
        filename_out = config["filename_out"]

    print("\nconverting %s.." % filename_in)

    file_in = open(filename_in, 'r', encoding = "utf-8")

    all_line = []
    for line in file_in:
        all_line.append(line)
    file_in.close()

    all_line_new = []
    insidePre = False
    status = STATUS_START
    status_old = status

    for line in all_line:
        status_old = status

        line_strip = line.lstrip()
        if len(line_strip) > 0:
            if insidePre:
                if line_strip[:5] == "</pre":
                    insidePre = False
            else:
                if line_strip[:4] == "<pre":
                    insidePre = True
                    status = STATUS_PRE
                elif line_strip[:1] == "-" or is_ol_item(line_strip):
                    status = STATUS_LIST
                elif line_strip[:1] == "#":
                    status = STATUS_HEADER
                else:
                    status = STATUS_NONE
                    
            if DOUBLE_BR_BEFORE_HEADER and status == STATUS_HEADER and status_old != STATUS_START:
                all_line_new.append(LINE_BR)
                
            if status_old == STATUS_NONE:
                if status == STATUS_HEADER:
                    all_line_new.append(LINE_BR)
            elif status_old == STATUS_HEADER:
                if status == STATUS_NONE:
                    all_line_new.append(LINE_BR)
                if status == STATUS_HEADER:
                    all_line_new.append(LINE_BR)
        all_line_new.append(line)

    file_out = open(filename_out, 'w', encoding = "utf-8")
    for line in all_line_new:
        file_out.write(line)
    file_out.close()

    print("end")

config = {}

if len(sys.argv) >= 2:
    if sys.argv[1] == "-i":
        if len(sys.argv) == 3:
            config['filename_in'] = sys.argv[2]
            go_convert(config)
        else:
            config['filename_in'] = sys.argv[2]
            config['filename_out'] = sys.argv[3]
            go_convert(config)
    else:
        print_usage()
else:
    print_usage()






사용 방법


사용 방법: python md_convert.py [옵션]
옵션:
-i input-file             : 지정된 입력 파일을 사용하여 변환을 하고 입력 파일을 덮어씁니다.
-i input-file output-file : 지정된 입력 파일과 출력 파일을 사용하여 변환을 합니다.


PS1. pre 태그 내에서 소스 코드에 html 관련 코드를 사용할 경우, 충돌이 나서 (특히 pre 태그 관련, 당연한가?) 소스내 모든 <와 >를 &lt;와 &gt;로 바꿔줄 수 밖에 없었습니다.
PS2. 추가 작업 후보 : 소스 md에 줄바꿈이 있을 때만 추가적인 줄바꿈 삽입
,

PyMunk에 pyGame을 결합한 예제 코드입니다.

우선 pyGame 기본 예제는 아래 글을 참고하시기 바랍니다.

>> pyGame 기본 예제

 

사전 설치 요구사항

pygame 모듈 사용시, 추가적인 pygame 모듈 설치를 필요로 합니다.

pip install pygame

 

예제 코드

import pygame
from pygame.locals import *
import pymunk
import pymunk.pygame_util

SCREEN_WD = 400
SCREEN_HT = 400
TARGET_FPS = 60

screen = pygame.display.set_mode((SCREEN_WD, SCREEN_HT), 0, 32)
pygame.display.set_caption("PyMunk_Example")
clock = pygame.time.Clock()

space = pymunk.Space()
space.gravity = 0, -1000
draw_options = pymunk.pygame_util.DrawOptions(screen)

ground = pymunk.Body(body_type=pymunk.Body.STATIC)
ground.position = 50, 50
 
ground_shape = pymunk.Segment(ground, (-50, 0), (50, 0), 1)
space.add(ground_shape)

body = pymunk.Body(1, 1666)
body.position = 50, 100
 
poly = pymunk.Poly.create_box(body, (10, 10))
space.add(body, poly)

timeStep = 1.0 / 60

running = True
while running:
    for event in pygame.event.get():
        if event.type == QUIT:
            running = False
            continue
        if event.type == KEYDOWN and event.key == K_ESCAPE:
            running = False
            continue

    screen.fill((0, 0, 0, 0))

    space.debug_draw(draw_options)

    space.step(timeStep)

    pygame.display.flip()
    clock.tick(TARGET_FPS)

pygame.quit()
print("done")

PyMunk에서는 다음 두 호출을 통해 기본적인 내용을 자동적으로 pyGame 영역에 그려주게 됩니다. 다만 (0, 0)에서부터 그려주므로 앞의 예제에서 전체적으로 (+50, +50) 만큼 좌표를 이동시켰습니다.

draw_options = pymunk.pygame_util.DrawOptions(screen)
...

space.debug_draw(draw_options)

 

정찰 위성 이미지

 

<테스트 환경>
  - OS : Windows 7
 - Python 버전 : 3.6
 - Pymunk 버전 : 5.3.2
 - PyGame 버전 : 1.9.3

 

,

파이썬용 2D 물리엔진중 하나인 Pymunk에 관한 기본 예제 코드를 소개하고자 합니다.



사전 설치 요구사항


pymunk 모듈 사용시, 추가적인 pymunk 모듈 설치를 필요로 합니다.

pip install pymunk


기본 예제


(0, 50) 좌표에 위치한 박스가 중력에 의해 지면을 향해 떨어져 지면에 부딧혀 멈출 때까지의 박스의 좌표가 출력되는(무려 텍스트로!) 예제 코드입니다. Pymunk 자체에는 그래픽 표현 기능이 없으므로 좌표 계산만 해줍니다. 이것을 화면 상으로 표현하는 것은 이후의 예제를 통하여 알아보겠습니다.

# -*- coding: utf-8 -*-

import pymunk

# 시뮬레이션 공간을 생성하고, 중력의 방향 및 크기를 설정한다.
space = pymunk.Space()
space.gravity = 0, -1000

# 두 점을 있는 직선을 나타내는 Segment 요소를 사용하여 지면을 생성한다.
# 길이 100, 두께 1인 직선을 생성하여 (0, 0)에 위치시킨다.
ground = pymunk.Body(body_type=pymunk.Body.STATIC)
ground.position = 0, 0
 
ground_shape = pymunk.Segment(ground, (-50, 0), (50, 0), 1)
space.add(ground_shape)

# (0, 50) 위치에 (10, 10) 크기의 박스를 생성한다.
body = pymunk.Body(1, 1666)  # 질량, 모멘트를 지정한다.
body.position = 0, 50
 
poly = pymunk.Poly.create_box(body, (10, 10))
space.add(body, poly)

# 1초 동안 1.0 / 60 초씩 진행시키며 박스의 좌표를 출력한다.
for i in range(60):
    space.step(1.0 / 60)
    print(body.position)


결과 캡처

Vec2d(0.0, 50.0)
Vec2d(0.0, 49.72222222222222)
Vec2d(0.0, 49.166666666666664)
Vec2d(0.0, 48.33333333333333)
Vec2d(0.0, 47.222222222222214)
Vec2d(0.0, 45.83333333333333)
Vec2d(0.0, 44.166666666666664)
Vec2d(0.0, 42.22222222222222)
Vec2d(0.0, 40.0)
Vec2d(0.0, 37.5)
Vec2d(0.0, 34.72222222222222)
Vec2d(0.0, 31.666666666666664)
Vec2d(0.0, 28.333333333333332)
Vec2d(0.0, 24.72222222222222)
Vec2d(0.0, 20.833333333333332)
Vec2d(0.0, 16.666666666666664)
Vec2d(0.0, 12.222222222222221)
Vec2d(0.0, 7.5)
Vec2d(0.0, 2.5)
Vec2d(0.0, 2.886956552845999)
Vec2d(0.0, 3.2330661044876274)
Vec2d(0.0, 3.542236920798546)
Vec2d(0.0, 3.8179830207826186)
Vec2d(0.0, 4.065083408185165)
Vec2d(0.0, 4.286249625299963)
Vec2d(0.0, 4.483745226989828)
Vec2d(0.0, 4.659603964972919)
Vec2d(0.0, 4.81565131414432)
Vec2d(0.0, 4.95352387113101)
Vec2d(0.0, 5.074686834357406)
Vec2d(0.0, 5.180449754301324)
Vec2d(0.0, 5.273414633437768)
Vec2d(0.0, 5.356441970464741)
Vec2d(0.0, 5.431683496733098)
Vec2d(0.0, 5.500322361070223)
Vec2d(0.0, 5.562826033647434)
Vec2d(0.0, 5.619373494273605)
Vec2d(0.0, 5.670188929782226)
Vec2d(0.0, 5.7156761612570905)
Vec2d(0.0, 5.756385891638544)
Vec2d(0.0, 5.792908604984999)
Vec2d(0.0, 5.822032616838716)
Vec2d(0.0, 5.844112775433398)
Vec2d(0.0, 5.859454641289297)
Vec2d(0.0, 5.868318121528639)
Vec2d(0.0, 5.870920746762018)
Vec2d(0.0, 5.86744062807873)
Vec2d(0.0, 5.858019128912104)
Vec2d(0.0, 5.897059737778078)
Vec2d(0.0, 5.925671363059304)
Vec2d(0.0, 5.909019468605577)
Vec2d(0.0, 5.9310174562872575)
Vec2d(0.0, 5.94492949182134)
Vec2d(0.0, 5.953966287149509)
Vec2d(0.0, 5.958854474347584)
Vec2d(0.0, 5.959613136913926)
Vec2d(0.0, 5.961507841637967)
Vec2d(0.0, 5.964013945366503)
Vec2d(0.0, 5.9657250791899505)
Vec2d(0.0, 5.966229061776563)


참고 자료

<테스트 환경> 
- OS : Windows 7 
- Python 버전 : 3.6
- Pymunk 버전 : 5.3.2
,

텔레그램 봇과 명령과 응답을 양방향으로 주고 받는 방법을 구현해보겠습니다. (Python 3 사용)

  • 텔레그램 봇을 구현하는 방법에는 두가지가 있는데, 그 중 한가지는 웹훅을 사용하는 방식으로 고정된 주소를 가진 사용자 서버를 등록시켜놓고 이를 통해 서비스하는 방법인데 아무래도 개인 사용자가 하기에는 부담이 따르겠죠.
  • 다른 한가지는 Long-Polling을 사용하는 방식인데, 서버를 열어놓지 않고 새로운 메시지가 있는지 여부를 약간 긴 주기로 계속적으로 확인하는 방법으로, 고정된 주소가 없는 개인 PC로도 서비스할 수 있는 장점이 있습니다. 여기서는 Long-Polling을 사용한 방식을 정리해보겠습니다.

다음은 Long-Polling에 의한 요청 처리가 구현되어, 기본적인 명령과 응답을 주고받는 기능이 동작하는 예제입니다.

  • 입력된 요청 문자열을 텔레그램 봇 창에 메세지로 보내는 내용이 구현되어있습니다.
  • 앱 상에서 요청 입력은 채널 포스팅에서 사용되었던 채널창이 아닌 텔레그램 봇 자체창에서 입력되어야 합니다

소스 중 <텔레그램 봇 토큰>은 아래 글을 참고하여 적당한 값으로 바꿔줍니다.

 

>> 텔레그램 봇 생성 및 봇 토큰 얻기

 

telegramagent.py :

# -*- coding: utf-8 -*-
  
import http.client, urllib
import json
import datetime
  
class ChatInfo:
  
  def __init__(self):
    self.chatId = None
    self.firstName = None
    self.lastName= None
    self.userName = None
    self.text = None
    self.date = None
  
class TelegramAgent:
  
  API_URL = "api.telegram.org"
  CONTENT_TYPE = "Content-type"
  APPLICATION_JSON = "application/json"
  
  BOT_PATH = "/bot%s"
  SEND_MESSAGE_PATH = "/sendMessage"
  SEND_MESSAGE_DATA = '{"chat_id": %s, "text": "%s"}'
  GET_ME_PATH = "/getMe"
  GET_UPDATES_PATH = "/getUpdates"
  GET_UPDATES_DATA = '{"offset": "%d"}'
  SEND_PHOTO_PATH = "/sendPhoto"
  SEND_PHOTO_DATA = '{"chat_id": %s, "photo": "%s"}'
  
  def __init__(self):
    self.bContinue = True
    self.response = None
    self.callback = None
    self.bDumpData = False
  
  def setToken(self, token):
    self.token = token
  
  def setCallback(self, callback):
    self.callback = callback
  
  def setContinue(self, bContinue):
    self.bContinue = bContinue
  
  def setDumpData(self, bDumpData):
    self.bDumpData = bDumpData
  
  def convertDate(self, date, format):
    return datetime.datetime.fromtimestamp(date).strftime(format)
  
  def packChatId(self, chatId):
    if len(chatId) > 0 and chatId[:1] == "@":
      return "\"%s\"" % chatId
    return chatId
  
  def postRequest(self, url, path, headers, paramsRaw):
    try:
      params = paramsRaw
      conn = http.client.HTTPSConnection(url)
      conn.request("POST", path, params.encode("UTF-8"), headers)
      self.response = conn.getresponse()
      self.data = self.response.read().decode("UTF-8")
      if self.bDumpData:
        print(self.data)
      conn.close()
    except (ConnectionError, TimeoutError) as e:
      print(f'Catched : {e}')
  
  def sendCommon(self, actionPath, data):
    path = self.BOT_PATH % self.token + actionPath
    self.postRequest(self.API_URL, path,
        {self.CONTENT_TYPE : self.APPLICATION_JSON}, data);
  
  def sendNoData(self, actionPath):
    self.sendCommon(actionPath, "")
  
  def sendMessage(self, chatId, message):
    chatId = self.packChatId(chatId)
    data = self.SEND_MESSAGE_DATA % (chatId, message)
    self.sendCommon(self.SEND_MESSAGE_PATH, data)
  
  def sendPhoto(self, chatId, photoUrl):
    data = self.SEND_PHOTO_DATA % (chatId, photoUrl)
    self.sendCommon(self.SEND_PHOTO_PATH, data)
  
  def getMe(self):
    self.sendNoData(self.GET_ME_PATH)
  
  def getUpdates(self, offset):
    data = self.GET_UPDATES_DATA % offset
    self.sendCommon(self.GET_UPDATES_PATH, data)
  
  def processResult(self, result):
    chatInfo = ChatInfo()
  
    try:
      message = result['message']
      if message == None:
        print("message is null")
      else:
        chat = message['chat']
        if chat == None:
          print("chat is null")
        else:
          chatInfo.chatId = "%d" % chat['id']
          chatInfo.firstName = chat['first_name']
          chatInfo.lastName = chat['last_name']
          chatInfo.userName = None
          if 'username' in chat:  # username 키 값 존재 체크하도록. 설정 안하면 없을 수 있음
            chatInfo.userName = chat['username']
        chatInfo.text = message['text']
        chatInfo.date = message['date']
          
      if self.callback != None:
        self.callback(chatInfo)
    except KeyError as e:
      return
  
  def loop(self):
    self.bContinue = True
    updateId = 0
      
    while (self.bContinue):
      self.getUpdates(updateId)
      if self.response.status == 200:
        respDict = json.loads(self.data)
        results = respDict['result']
        resultsNum = len(results)
        if resultsNum > 0:
          lastResult = results[resultsNum - 1]
          updateId = lastResult['update_id'] + 1
          self.processResult(lastResult)

main.py :

# -*- coding: utf-8 -*-
  
from telegramagent import *
 
def myCallback(chatInfo):
  print("chat id = %s" % chatInfo.chatId)
  print("username = %s" % chatInfo.userName)
  print("date = %s" % agent.convertDate(chatInfo.date, '%Y-%m-%d %H:%M:%S'))
  print("text = %s" % chatInfo.text)
  if chatInfo.text == "quit":
    agent.setContinue(False)
  else:
    agent.sendMessage(chatInfo.chatId, "입력된 요청 : %s" % chatInfo.text)
 
agent = TelegramAgent()
agent.setDumpData(True)
agent.setToken("<텔레그램 봇 토큰>")
agent.setCallback(myCallback)
  
agent.loop()

telegramagent.py 주요 행 설명

  • 7 : 요청을 보낸 사용자 정보가 담기는 클래스입니다.
  • 77 : chatId가 채널 ID일 경우 따옴표로 감싸줍니다.
  • 133 : Long-Polling 시, update id를 0으로 설정할 경우, 기존에 가지고 있는 상태 데이터를 모두 가져오고, 두번째 호출부터는 마지막 update id + 1로 설정하면 기존의 데이터는 무시하고 새로운 데이터만 가져오게 됩니다.

main.py 주요 행 설명

  • 11 : quit 명령을 받으면 서버를 종료합니다.
  • 13 : Callback 함수에서 입력된 요청 문자열을 텔레그램 봇 창에 메세지로 보내줍니다.
  • 16 : 텔레그램 서버에서 받은 응답 정보를 출력합니다. 실사용시는 False로 합니다.
  • 18 : 요청을 처리할 Callback 함수를 등록하여 사용합니다.

 

 

정찰 위성 이미지

 

 

 

참고 사이트

  • 더 많은 텔레그램 봇 라이브러리들 : https://core.telegram.org/bots/samples

 

 

<테스트 환경> 
- OS : Windows 10 
- Python 버전 : 3.6 

 

,

다음은 몇가지 부가적인 기능이 추가된 예제입니다.

  • getMe : 텔레그램 봇 자신에 대한 정보를 가져온다.
  • getUpdates : 텔레그램 봇의 상태 정보를 가져온다.
  • sendPhoto : 텔레그램 봇 채널에 이미지를 전송한다.
# -*- coding: utf-8 -*-

import http.client, urllib
import json
import datetime

class TelegramAgent:

  API_URL = "api.telegram.org"
  CONTENT_TYPE = "Content-type"
  APPLICATION_JSON = "application/json"

  BOT_PATH = "/bot%s"
  SEND_MESSAGE_PATH = "/sendMessage"
  SEND_MESSAGE_DATA = '{"chat_id": %s, "text": "%s"}'
  GET_ME_PATH = "/getMe"
  GET_UPDATES_PATH = "/getUpdates"
  GET_UPDATES_DATA = '{"offset": "%d"}'
  SEND_PHOTO_PATH = "/sendPhoto"
  SEND_PHOTO_DATA = '{"chat_id": %s, "photo": "%s"}'

  def __init__(self):
    self.bContinue = True
    self.response = None
    self.callback = None
    self.bDumpData = False

  def setToken(self, token):
    self.token = token

  def setCallback(self, callback):
    self.callback = callback

  def setContinue(self, bContinue):
    self.bContinue = bContinue

  def setDumpData(self, bDumpData):
    self.bDumpData = bDumpData

  def convertDate(self, date, format):
    return datetime.datetime.fromtimestamp(date).strftime(format)

  def packChatId(self, chatId):
    if len(chatId) > 0 and chatId[:1] == "@":
      return "\"%s\"" % chatId
    return chatId

  def postRequest(self, url, path, headers, paramsRaw):
    params = paramsRaw
    conn = http.client.HTTPSConnection(url)
    conn.request("POST", path, params.encode("UTF-8"), headers)
    self.response = conn.getresponse()
    self.data = self.response.read().decode("UTF-8")
    if self.bDumpData:
      print(self.data)
    conn.close()

  def sendCommon(self, actionPath, data):
    path = self.BOT_PATH % self.token + actionPath
    self.postRequest(self.API_URL, path, 
        {self.CONTENT_TYPE : self.APPLICATION_JSON}, data);

  def sendNoData(self, actionPath):
    self.sendCommon(actionPath, "")

  def sendMessage(self, chatId, message):
    chatId = self.packChatId(chatId)
    data = self.SEND_MESSAGE_DATA % (chatId, message)
    self.sendCommon(self.SEND_MESSAGE_PATH, data)

  def sendPhoto(self, chatId, photoUrl):
    chatId = self.packChatId(chatId)
    data = self.SEND_PHOTO_DATA % (chatId, photoUrl)
    self.sendCommon(self.SEND_PHOTO_PATH, data)

  def getMe(self):
    self.sendNoData(self.GET_ME_PATH)

  def getUpdates(self, offset):
    data = self.GET_UPDATES_DATA % offset
    self.sendCommon(self.GET_UPDATES_PATH, data)

agent = TelegramAgent()
agent.setDumpData(True)
agent.setToken("<텔레그램 봇 토큰>")
agent.getMe()
agent.getUpdates(0)
agent.sendPhoto("@<채널 ID>", "http://t1.daumcdn.net/thumb/R0x640/?fname=http%3A%2F%2Fcfile168.uf.daum.net%2Fimage%2F235D1A445731A2332F780E")

<테스트 환경>
- OS : Windows 7
- Python 버전 : 3.6


,

앞서 작성한 코드를 클래스로 정리해 보겠습니다.


# -*- coding: utf-8 -*-

import http.client, urllib
import json
import datetime

class TelegramAgent:

  API_URL = "api.telegram.org"
  CONTENT_TYPE = "Content-type"
  APPLICATION_JSON = "application/json"

  BOT_PATH = "/bot%s"
  SEND_MESSAGE_PATH = "/sendMessage"
  SEND_MESSAGE_DATA = '{"chat_id": %s, "text": "%s"}'

  def __init__(self):
    self.bContinue = True
    self.response = None
    self.callback = None
    self.bDumpData = False

  def setToken(self, token):
    self.token = token

  def setCallback(self, callback):
    self.callback = callback

  def setContinue(self, bContinue):
    self.bContinue = bContinue

  def setDumpData(self, bDumpData):
    self.bDumpData = bDumpData

  def packChatId(self, chatId):
    if len(chatId) > 0 and chatId[:1] == "@":
      return "\"%s\"" % chatId
    return chatId

  def postRequest(self, url, path, headers, paramsRaw):
    params = paramsRaw
    conn = http.client.HTTPSConnection(url)
    conn.request("POST", path, params.encode("UTF-8"), headers)
    self.response = conn.getresponse()
    self.data = self.response.read().decode("UTF-8")
    if self.bDumpData:
      print(self.data)
    conn.close()

  def sendCommon(self, actionPath, data):
    path = self.BOT_PATH % self.token + actionPath
    self.postRequest(self.API_URL, path, 
        {self.CONTENT_TYPE : self.APPLICATION_JSON}, data);

  def sendNoData(self, actionPath):
    self.sendCommon(actionPath, "")

  def sendMessage(self, chatId, message):
    chatId = self.packChatId(chatId)
    data = self.SEND_MESSAGE_DATA % (chatId, message)
    self.sendCommon(self.SEND_MESSAGE_PATH, data)

agent = TelegramAgent()
agent.setDumpData(True)
agent.setToken("<텔레그램 봇 토큰>")
agent.sendMessage("@<채널 ID>", "test string [한글]")


<테스트 환경>
- OS : Windows 7
- Python 버전 : 3.6


,

파이썬에서 문자열은 바이트 코드와 유니코드로 나뉜다.


파이썬 3에서,

바이트 코드의 타입 -> <class 'bytes'>

유니 코드의 타입 -> <type 'str'>



변환


바이트 코드는 euc-kr, UTF–8 등과 같이 특정 인코딩이 적용된 문자열을 말한다. 파이썬에서 유니코드는 어떤 특정 인코딩에 속하지 않는 유니버셜한 어떤 것을 나타낸다. (다른 언어에서 흔히 UTF–8을 유니코드로 일컫는 것과는 다름에 유의)

  • 유니코드 >>> 바이트 코드로 변환하기 위해서는 encode() 함수가 사용된다.

  • 바이트 코드 >>> 유니코드로 변환하기 위해서는 decode() 함수가 사용된다.

    bstr = str.encode("UTF–8") # 유니코드에서 UTF–8 바이트 코드로 변환 
    str = bstr.decode("UTF–8") # UTF–8 바이트 코드에서 유니코드로 변환


타입 확인

  • type() 함수를 사용하여 어떤 문자열이 유니코드인지 바이트 코드인지 알아낼 수 있다.
    print(type(bstr)) # 바이트 코드일 경우 
    -> <type 'bytes'> 
    
    print(type(str)) # 유니코드일 경우
    -> <type 'str'>


소스 코드 상에서 대입시,


파이썬 2에서는 기본적으로 바이트 코드이고 <type 'str'>로 표기되며, 이에 대비되는 유니코드가 있는 것과 달리,

파이썬 3에서는 기본적으로 유니코드이고 <type 'str'>로 표기된다.


참고


print 함수를 사용하여 바이트 코드를 출력할 경우, 앞에 b'가 붙는 것을 볼 수 있다.


테스트 환경 
- OS : Windows 7 
- Python 버전 : 3.6


,