'MINERVA/Python'에 해당되는 글 47건
- 2022.09.03 :: [Python] 동적 변수 선언, 값 할당 그리고 사용
- 2022.08.19 :: [Python] for 문 비교( C/C++ vs Python)
- 2022.08.16 :: [Python] 휴일 & 공휴일 확인
- 2022.08.16 :: [Python] 리스트 안에 값(value, element)가 있는지 확인
- 2022.08.15 :: [Datetime] 기준날짜를 offset day 계산
- 2022.08.13 :: [데이타 변환] list str 원소를 int 로 변환
- 2022.08.10 :: [Pandas] 데이타프레임(DataFrame)을 엑셀(excel) 파일로 저장
- 2022.07.01 :: [Anaconda] 가상환경(virtual environment) 관리
- 2022.06.05 :: [Python] 집합(set) 객체 정리
- 2022.05.31 :: [Python] 튜플(tuple) 객체 정리
C/C++을 오랫동안(음...20년이 넘나?)사용하다가, Data type assignment 언어인 Python은 처음부터 접근과 사용이 매우 수월(?)했습니다. 그렇지만, 문법(?)적으로 동적으로 변수를 선언 및 사용하는 방법은 다른 개발 언어와 비교했을때 확실히 다름(?)이 있어, 아래와 같이 간단히 정리하고자 합니다.
# 지역별 APT 평균 가격
# 강남구,서초구,........
regionPrice = ['14억', '13억', '9억', '7억', '6억']
#regionMajor = [....]
# 동적 변수 선언 및 값 할당
for i in range(0, len(regionPrice)):
locals()['df{}'.format(i)] = regionPrice[i]
# 동적 변수 접근
for i in range(0, len(regionPrice)):
df = locals()['df{}'.format(i)]
print(df)
프로젝트에 사용된 일부 코드를 발취하여 편집하였습니다.
글로벌 변수로 사용하기 위해서는 locals() --> Globals()로 변경하면 됩니다.
기술적인 이론을 이해하기 위해서는, Python의 메모리 관리와 인터프린터 언어의 특성에 대해서 감(?)을 잡아함. 이부분은시간이 날때 따로 정리 하도록하겠습니다.
개발 언어를 여러개 사용하다보니 순간 순간 헷갈리는 경우가 있어 나를 위해 기록으로 남김
[C/C++]
for (int i = 0; i < 10; i++) {
printf("%d\n", i);
}
[PYTHON]
for i in range(0, 10, 1): #range(시작,끝,증가값)
print i
해당 일이 휴일 또는 공휴일인지 확인
# 공휴일 체크 모듈:
pytimekr
# 샘플 코드
import datetime
from pytimekr import pytimekr
# 주말(weekend) & 연휴(holiday)
def CheckOffDay(d):
holidayList = pytimekr.holidays()
bHoliday = holidayList.__contains__(d)
bWeekday = d.weekday() > 4
return(bWeekday or bHoliday)
if __name__ == '__main__':
# 리턴: 리스트 형태로 관련값 반환: %Y-%m-%d
#holidayList = pytimekr.holidays()
#for index in holidayList:
# print(index)
# 시분초 없이
dtTest = datetime.date(2022, 9, 8)
print(type(dtTest))
print(dtTest)
# for manual test
strToday = '20220815'
dtToday = datetime.datetime.strptime(strToday, '%Y%m%d')
print(type(dtToday))
print(dtToday.date())
print(CheckOffDay(dtToday.date()))
# CheckOffDay()를 통해서, 해당일이 공휴일 또는 주말이면 True가 리턴됨
리스트내에 값(value, element)가 존재하는지 확인 하는 3가지 방법
아래 코드는 광복절(8월 15일)이 리스트 내에 존재하는지 확인
# 리스트 안에 값(value, element)가 있는지 확인
dtDay = datetime.date(2022, 8, 15)
holidayList = pytimekr.holidays()
# 방법1:
bOffDay = holidayList.__contains__(dtDay)
print(f'[방법 1:] {bOffDay}')
# 방법2:
bOffDay = False
if dtDay in holidayList:
bOffDay = True
print(f'[방법 2:] {bOffDay}')
# 방법3:
bOffDay = False
if holidayList.count(dtDay) > 0:
bOffDay = True
print(f'[방법 3:] {bOffDay}')
[결과]
[방법 1:] True
[방법 2:] True
[방법 3:] True
아래 코드는 특정 날짜를 기준으로 offset day를 구하는 코드 입니다.
이때, working day를 기준으로 해당 날짜를 예제입니다.
사용 용례: 오늘을 기준으로 working day 5일전의 날짜는 언제인가?(주말제외)
# working days 계산: 오늘 기준 5일전(당일제외) 날짜 구함(단, 주말을 제외)
nBefore = 5
PivotDatetime = datetime.datetime.now()
BeforeDatatime = PivotDatetime - datetime.timedelta(days=nBefore)
# BeforeDatatime 부터 PivotDatetime 으로 주말이 몇번 있는지 확인
nLoop = 0
nOffday = 0
while nLoop < nBefore:
if CheckWeekend(BeforeDatatime):
nOffday = nOffday +1
BeforeDatatime = BeforeDatatime + datetime.timedelta(days=1)
nLoop = nLoop + 1
#
BeforeDatatime = PivotDatetime - datetime.timedelta(days=(nBefore+nOffday))
strBeforeDay = BeforeDatatime.strftime('%Y%m%d%H%M%S')
#
print(f'{BeforeDatatime} {PivotDatetime}')
주말을 체크하는 함수
# return: Bool
def CheckWeekend(d):
return d.weekday() > 4
파이썬의 데이타 변환은 이전 블로그 글에서 소개드린 대로 매우 직관적으로 됩니다. 하지만, 다른 객체의 원소로 포함된 데이타 타입의 변환은 익숙하지 않으면 실수할 수 있어 정리하고자 합니다.
# List 원소 str원소를 int로 변환
stringList = ['1','2','3','4','5']
print(type(stringList))
print(stringList)
# 방법1: map 사용
intList1 = list(map(int,stringList))
print(type(intList1))
print(intList1)
# 방법2: list 사용
intList2 = [int(n) for n in stringList]
print(type(intList2))
print(intList2)
[결과]
['1', '2', '3', '4', '5']
<class 'list'>
[1, 2, 3, 4, 5]
<class 'list'>
[1, 2, 3, 4, 5]
cf) 추가 적으로 위의 방법은 python 3인 경우에 적용되며, python 2를 사용한다면 아래를 사용
intList1 = map(int, stringList)
print(type(intList1))
print(intList1)
DataFrame 데이터를 엑셀(excel)로 저장하는 방법중 개인적으로 선호하는 두가지 방법을 정리하고자 합니다.
1. to_excel() 사용
to_excel()함수를 보면, 다양한 인자를 지원하고 있는 것을 확인 할수 있습니다. 하나하나 세세하게 살표보면 좋겠지만, 제 경험상으로는 파일 이름(excel_writer)과 엑셀형식에서 맞게 시트 이름(sheet_name) 정도만 알면 일차적으로 접근하는데는 무리가 없습니다.
(샘플코드)
# 투자자별 순매수 상위종목
# 20220808 부터 20220809 까지 개인의 순매수 금액이 높은 순서대로 종목을 정렬해서 반환
# KOSPI, KOSDAQ, KONEX
# 금융투자 / 보험 / 투신 / 사모 / 은행 / 기타금융 / 연기금 / 기관합계 / 기타법인 / 개인 / 외국인 / 기타외국인 / 전체
market = "ALL"
strfrom = "20220809"
strTo = "20220809"
foreignDf = stock.get_market_net_purchases_of_equities(strfrom, strTo, market, "외국인")
print(foreignDf)
# 파일 이름
prefix = 'cww'
suffix = datetime.datetime.now().strftime("_%y%m%d_%H%M%S.xlsx") #연월일_시분초
print('{}{}'.format(prefix,suffix))
filename = prefix + suffix
print(filename)
# 저장
foreignDf.to_excel(
excel_writer=filename,
sheet_name='외국인',
index=False)
print('Done')
위의 코드는 프로젝트 코드의 일부를 발취한 부분으로, 주기적으로 외국인이 순매수한 거래량과 거래대금등을 취합하고, 그 내용을 엑셀 파일로 기록하는 부분입니다.
해당 경로에 파일이 파일이 없으면 새로 만들지만, 이미 존재하면 덮어쓰기를 함
(실행결과)
to_excel()의 경우 하나의 시트만 저장 가능함. (이 부분은 단점으로 생각됨)
그래서, 하나의 엑셀파일에 여러 시트를 저장하는 경우는 아래의 방법을 사용
2. ExcelWriter()사용
여러개 데이타프레임을 하나의 엑셀 파일에 저장
# 투자자별 순매수 상위종목
# 20220808 부터 20220809 까지 개인의 순매수 금액이 높은 순서대로 종목을 정렬해서 반환
# KOSPI, KOSDAQ, KONEX
# 금융투자 / 보험 / 투신 / 사모 / 은행 / 기타금융 / 연기금 / 기관합계 / 기타법인 / 개인 / 외국인 / 기타외국인 / 전체
market = "ALL"
strfrom = "20220809"
strTo = "20220809"
foreignDf = stock.get_market_net_purchases_of_equities(strfrom, strTo, market, "외국인")
print(foreignDf)
#market = "KOSPI"
gigwanDf = stock.get_market_net_purchases_of_equities(strfrom, strTo, market, "기관합계")
print(gigwanDf)
#
tusinDf = stock.get_market_net_purchases_of_equities(strfrom, strTo, market, "투신")
print(tusinDf)
#
samoDf = stock.get_market_net_purchases_of_equities(strfrom, strTo, market, "투신")
print(samoDf)
# 파일 이름
prefix = 'cww'
suffix = datetime.datetime.now().strftime("_%y%m%d_%H%M%S.xlsx") #연월일_시분초
print('{}{}'.format(prefix,suffix))
filename = prefix + suffix
print(filename)
# 저장
writer = pd.ExcelWriter(filename)
foreignDf.to_excel(writer, sheet_name='외국인')
gigwanDf.to_excel(writer, sheet_name='기관')
tusinDf.to_excel(writer, sheet_name='투신')
samoDf.to_excel(writer, sheet_name='사모')
writer.save()
(출력결과)
가상환경을 제공하는 아나콘다(Anaconda)에서 필수적인 명령어를 정리하고자 합니다.
1) 버전 확인
[Anaconda Prompt(anaconda3)]
(base) D:\NextTime\cwwDev>conda -V
conda 4.13.0
2) 라이브러리(패키지) 설치, 업데이트 그리고 삭제하기
2-1) 설치된 라이브러리(패키지) 전체 업데이트
(base) D:\NextTime\cwwDev>conda update --all
Collecting package metadata (current_repodata.json): done
Solving environment: done
# All requested packages already installed.
2-2) 라이브러리(패키지) 설치
(base) D:\NextTime\cwwDev>conda install 라이브러리(패키지)명
2-3) 부분 업데이트
(base) D:\NextTime\cwwDev>conda update 라이브러리(패키지)명
2-4) 라이브러리(패키지) 삭제
(base) D:\NextTime\cwwDev>conda remove 라이브러리(패키지)명
3) 설치된 가상환경(virtual environment) 확인
(base) D:\NextTime\cwwDev>conda info --env
# conda environments:
#
base * d:\Dev\anaconda3 <-- 기본 아나콘다 가상환경
(base) D:\NextTime\cwwDev>conda env list
# conda environments:
#
base * d:\Dev\anaconda3 <-- 기본 아나콘다 가상환경
4) 사용중인 가상환경에 구성된 시스템 정보보기
4-1) 64 bit 확인
(base) D:\NextTime\cwwDev>conda info
active environment : base
active env location : d:\Dev\anaconda3
shell level : 1
user config file : C:\Users\CHOI\.condarc
populated config files : C:\Users\CHOI\.condarc
conda version : 4.13.0
conda-build version : 3.21.9
python version : 3.8.5.final.0
virtual packages : __cuda=11.1=0
__win=0=0
__archspec=1=x86_64
base environment : d:\Dev\anaconda3 (writable)
conda av data dir : d:\Dev\anaconda3\etc\conda
conda av metadata url : None
channel URLs : https://repo.anaconda.com/pkgs/main/win-64
https://repo.anaconda.com/pkgs/main/noarch
https://repo.anaconda.com/pkgs/r/win-64
https://repo.anaconda.com/pkgs/r/noarch
https://repo.anaconda.com/pkgs/msys2/win-64
https://repo.anaconda.com/pkgs/msys2/noarch
package cache : d:\Dev\anaconda3\pkgs
C:\Users\CHOI\.conda\pkgs
C:\Users\CHOI\AppData\Local\conda\conda\pkgs
envs directories : d:\Dev\anaconda3\envs
C:\Users\CHOI\.conda\envs
C:\Users\CHOI\AppData\Local\conda\conda\envs
platform : win-64
user-agent : conda/4.13.0 requests/2.24.0 CPython/3.8.5 Windows/10 Windows/10.0.19041
administrator : False
netrc file : None
offline mode : False
4-2) 32 bit 확인
(base) D:\NextTime\cwwDev>set CONDA_FORCE_32BIT=1
(base) D:\NextTime\cwwDev>conda info
active environment : base
active env location : d:\Dev\anaconda3
shell level : 1
user config file : C:\Users\CHOI\.condarc
populated config files : C:\Users\CHOI\.condarc
conda version : 4.13.0
conda-build version : 3.21.9
python version : 3.8.5.final.0
virtual packages : __cuda=11.1=0
__win=0=0
__archspec=1=x86
base environment : d:\Dev\anaconda3 (writable)
conda av data dir : d:\Dev\anaconda3\etc\conda
conda av metadata url : None
channel URLs : https://repo.anaconda.com/pkgs/main/win-32
https://repo.anaconda.com/pkgs/main/noarch
https://repo.anaconda.com/pkgs/r/win-32
https://repo.anaconda.com/pkgs/r/noarch
https://repo.anaconda.com/pkgs/msys2/win-32
https://repo.anaconda.com/pkgs/msys2/noarch
package cache : d:\Dev\anaconda3\pkgs32
C:\Users\CHOI\.conda\pkgs32
C:\Users\CHOI\AppData\Local\conda\conda\pkgs32
envs directories : d:\Dev\anaconda3\envs
C:\Users\CHOI\.conda\envs
C:\Users\CHOI\AppData\Local\conda\conda\envs
platform : win-32
user-agent : conda/4.13.0 requests/2.24.0 CPython/3.8.5 Windows/10 Windows/10.0.19041
administrator : False
netrc file : None
offline mode : False
5) 가상환경(virtual environment) 만들기
(base) D:\NextTime\cwwDev>conda create -n py39_32 python=3.9
Collecting package metadata (current_repodata.json): done
Solving environment: done
## Package Plan ##
environment location: d:\Dev\anaconda3\envs\py39_32
added / updated specs:
- python=3.9
The following packages will be downloaded:
package | build
---------------------------|-----------------
ca-certificates-2022.4.26 | haa95532_0 124 KB
certifi-2022.6.15 | py39haa95532_0 153 KB
openssl-1.1.1p | h2bbff1b_0 4.8 MB
pip-21.2.4 | py39haa95532_0 1.8 MB
python-3.9.12 | h6244533_0 17.1 MB
setuptools-61.2.0 | py39haa95532_0 1.0 MB
sqlite-3.38.5 | h2bbff1b_0 798 KB
tzdata-2022a | hda174b7_0 109 KB
vc-14.2 | h21ff451_1 8 KB
vs2015_runtime-14.27.29016 | h5e58377_2 1007 KB
wheel-0.37.1 | pyhd3eb1b0_0 33 KB
wincertstore-0.2 | py39haa95532_2 15 KB
------------------------------------------------------------
Total: 26.9 MB
The following NEW packages will be INSTALLED:
ca-certificates pkgs/main/win-64::ca-certificates-2022.4.26-haa95532_0
certifi pkgs/main/win-64::certifi-2022.6.15-py39haa95532_0
openssl pkgs/main/win-64::openssl-1.1.1p-h2bbff1b_0
pip pkgs/main/win-64::pip-21.2.4-py39haa95532_0
python pkgs/main/win-64::python-3.9.12-h6244533_0
setuptools pkgs/main/win-64::setuptools-61.2.0-py39haa95532_0
sqlite pkgs/main/win-64::sqlite-3.38.5-h2bbff1b_0
tzdata pkgs/main/noarch::tzdata-2022a-hda174b7_0
vc pkgs/main/win-64::vc-14.2-h21ff451_1
vs2015_runtime pkgs/main/win-64::vs2015_runtime-14.27.29016-h5e58377_2
wheel pkgs/main/noarch::wheel-0.37.1-pyhd3eb1b0_0
wincertstore pkgs/main/win-64::wincertstore-0.2-py39haa95532_2
Proceed ([y]/n)?y
....
done
#
# To activate this environment, use
#
# $ conda activate py39_32
#
# To deactivate an active environment, use
#
# $ conda deactivate
(base) D:\NextTime\cwwDev>
(base) D:\NextTime\cwwDev>conda env list
# conda environments:
#
base * d:\Dev\anaconda3
py39_32 d:\Dev\anaconda3\envs\py39_32
5) 가상환경(virtual environment) 지우기
(base) D:\NextTime\cwwDev>conda env remove -n py39_32
Remove all packages in environment d:\Dev\anaconda3\envs\py39_32:
(base) D:\NextTime\cwwDev>conda env list
# conda environments:
#
base * d:\Dev\anaconda3
6) 생성된 가상환경(virtual environment) 활성화 및 비활성화
6-1) 활성화
(base) D:\NextTime\cwwDev>conda activate py39_32
(py39_32) D:\NextTime\cwwDev>
6-2) 비활성화
(py39_32) D:\NextTime\cwwDev>conda deactivate
(base) D:\NextTime\cwwDev>
7) 생성된 가상환경(virtual environment)에 패키지 설치
7-1) 가상환경(virtual environment) 생성, 진입(활성화), 그리고 설치하기
(base) D:\NextTime\cwwDev>conda activate py39_32
(py39_32) D:\NextTime\cwwDev>pip install pyqt5
(py39_32) D:\NextTime\cwwDev>pip install pykiwoom
7-2) 가상환경(virtual environment) 생성하면서 동시에 패키지 설치하기
(base) D:\NextTime\cwwDev>conda create -n py39_32 python=3.9 pyqt5 pykiwoom
Python 언어가 다른 개발언어와 비교할때, 가장 개성(?)있는 장점이 집합(set)객체의 제공이라고 생각합니다.
데이타의 집합을 직관적으로 합집합, 차집합, 교집합으로 처리할때 마치 SQL 언어에서 사용할때 보다 더욱 편리하게 느껴집니다. 개인적으로, 이 특성으로 인해 Python이 데이타 처리에 큰 강점을 가지게 된것 같습니다.
(또한, 이전에는 Database에 데이타를 넣고, 프로시져를 통해서 처리하던 부분을 지금은 다르게 처리하게 되었습니다.)
집합(set) 객체를 한마리도 정리하면 '중복이 허용되지 않는 mutable type의 객체라고 정의 합니다.
백문이 불여 일타록 하였으니 정리된 코드로 확인해보도록 하겠습니다.
#########################################
# [집한(set) 실습]
# 1) 정의: 중복이 허용되지 않는 mutable data object이다.
# 2) 접근: NOT Sequence type
# 3) 집합 기능: 합집합, 교집한, 차집합
# 4) 추가적인 함수: 넣고, 빼기, 업데이트하기
#####
# 1) 정의
aSet1 = set()
print(aSet1)
print(type(aSet1))
aSet2 = set((1,2,3,4,5)) # 튜플(tuple) -> 집합(set)
print(aSet2)
aSet3 = set(['a', 'b', 'c', 'd', 'e']) # 리스트(list) -> 집합(set)
print(aSet3)
aSet4 = set('Hello world') # 문자열(string) -> 집합(set)
print(aSet4) # 데이타 중복 제거
[결과]
set()
<class 'set'>
{1, 2, 3, 4, 5}
{'b', 'a', 'd', 'c', 'e'}
{'l', 'w', 'd', ' ', 'r', 'H', 'o', 'e'}
# 2) 접근: Sequence type 아니기 때문애 indexing 접근불가
# indexing을 하기 위해서는 Sequence type으로 전환(convert) 필요
aList2 = list(aSet2) # tuple -> set -> list
print(aList2)
print(aList2[2])
aTuple3 = tuple(aSet3) # list -> set -> tuple
print(aTuple3)
print(aTuple3[0])
aStr3 = str(aSet4) # string -> set -> string
print(aStr3)
print(aStr3[1])
[결과]
[1, 2, 3, 4, 5]
3
('b', 'a', 'd', 'c', 'e')
b
{'l', 'w', 'd', ' ', 'r', 'H', 'o', 'e'}
'
# 3) 집합 기능: 합집합, 교집한, 차집합
bSet = set([1,2,3,4,5,6,7]) # list -> set
cSet = set((4,5,6,7,8,9)) # tuple -> set
print(bSet)
print(cSet)
# 차집합 : '-', difference()
dSetDiff1 = bSet - cSet
print(dSetDiff1)
dSetDiff2 = bSet.difference(cSet)
print(dSetDiff2)
# 교집합 : '&', intersection()
dSetInter1 = bSet & cSet
print(dSetInter1)
dSetInter2 = bSet.intersection(cSet)
print(dSetInter2)
# 합집합: '|', union()
dSetUnion1 = bSet | cSet
print(dSetUnion1)
dSetUnion2 = bSet.union(cSet)
print(dSetUnion2)
[결과]
{1, 2, 3, 4, 5, 6, 7}
{4, 5, 6, 7, 8, 9}
{1, 2, 3}
{1, 2, 3}
{4, 5, 6, 7}
{4, 5, 6, 7}
{1, 2, 3, 4, 5, 6, 7, 8, 9}
{1, 2, 3, 4, 5, 6, 7, 8, 9}
# 추가적인 함수
fSet = set(['a','b','c','d'])
print(fSet)
# 추가: add()
fSet.add(1)
print(fSet)
# 업데이트: update()
fSet.add((3,4,5))
print(fSet)
# 삭제: remove()
fSet.remove(1)
print(fSet)
[결과]
{'c', 'b', 'a', 'd'}
{1, 'b', 'a', 'd', 'c'}
{1, 'b', 'a', 'd', (3, 4, 5), 'c'}
{'b', 'a', 'd', (3, 4, 5), 'c'}
튜플(tuple)을 간단히 말하면 변경할수 없는(immutable) 시퀀스 자료형(sequence type)입니다.
그런데, 앞에서 학습한 리스트(list)가 있는데 왜? 튜플(tuple)이 있을까?
그 이유는, 튜플은 리스트에 비해서, 가볍고(즉, 빠르다)고 메모리를 작게 사용합니다.(이 부분은 별도로 정리하겠습니다.)
튜플(tuple) 사용 용례를 정리하면 다음과 같습니다.
#########################################
# [튜플(Tuple) 실습]
# 1) sequence types 실습: indexing, slicing, concatenating, iterating, size
# 2) 왜? Tuple을 사용할까? 리스트로 다하면 되는데?
# -> 메모리를 절약하고, 성능이 더 좋다.
#####
# 1) 인덱싱(indexing)
print(aTuple)
print(aTuple[0]) # 0 인덱스: Tuple 객체의 맨 처음
print(aTuple[-1]) # -1 인덱스: Tuple 객체의 맨 마지막
# tuple안의 tuple: 기준값을 저장할때 많이 사용
dTuple = ( (1,2,3), ('a','b','c'))
print(dTuple)
print(dTuple[0])
print(dTuple[1])
print(dTuple[0][1])
print(dTuple[1][0])
[결과]
(1, 2, 3, 4, 5, 6, 7, 8, 9)
1
9
((1, 2, 3), ('a', 'b', 'c'))
(1, 2, 3)
('a', 'b', 'c')
2
a
# 2) 슬라이싱(slicing)
print(aTuple[1:]) # 인덱스 1부터 마지막까지
print(aTuple[:4]) # 인덱스 처음(0)부터 인덱스 4까지
print(aTuple[1:3]) # 인덱스 1부터 인덱스 5까지
print(aTuple[:]) # 인덱스 처음 마지막까지
print(aTuple[1:9:2]) # 인덱스 1부터, 9까지, 2간격으로 추출
[결과]
(2, 3, 4, 5, 6, 7, 8, 9)
(1, 2, 3, 4)
(2, 3)
(1, 2, 3, 4, 5, 6, 7, 8, 9)
(2, 4, 6, 8)
# 3) 연결(concatenating)
bTuple = ('a','b','c','d')
cTuple = aTuple + bTuple
print(cTuple)
[결과]
(1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd')
# 4) 반복(iterating)
print(bTuple*3)
[결과]
('a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd')
# 5) 크기(sizing)
print(len(bTuple))
[결과]
4