Python 程式設計入門 - 02

Pyladies Taiwan

Speaker : Mars

2017/10/01

Roadmap

  • 前情提要:物件與字串
  • 再談字串
  • 字串好用的方法
  • 序列型別
  • 可變與不可變
  • 序列共同介面
  • 序列的應用
  • 總練習
  • 補充知識
  • 學習資源對應

前情提要:物件與字串

物件型別

  • 在Python程式中「=」可以想像成是「貼標籤」的意思
  • 在右邊的「物件」(資料內容)存放位置貼上左邊「名稱」的標籤,亦即名稱指向物件。
  • type(物件):印出此物件的型別
In [1]:
my_score = 96
pi = 3.14159
url = "http://blog.marsw.tw"

print(type(my_score))
print(type(pi))
print(type(url))
print(type(print))
<class 'int'>
<class 'float'>
<class 'str'>
<class 'builtin_function_or_method'>

在Python3中,所有東西都是物件!!!

字串(string)

  • 可以直接給定詞句
  • 也可以給空白句
  • 可以相+、相*
In [2]:
my_string = "Hi"
my_string2 = ""
my_string2 = my_string2 + "Py" + 'Ladies'
my_string3 = "Hello"*4

print (my_string)
print (my_string2)
print (my_string3)
Hi
PyLadies
HelloHelloHelloHello

!注意

  • 用「成對的」雙引號"或是單引號',將字串包住

!注意

  • 字串與數值不可一同運算
In [3]:
my_string = "123"
my_int_number = 456
print (my_string+my_int_number)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-151fbba3d316> in <module>()
      1 my_string = "123"
      2 my_int_number = 456
----> 3 print (my_string+my_int_number)

TypeError: Can't convert 'int' object to str implicitly

型別轉換

  • int(物件):將物件轉成整數(integer)型別
  • float(物件):將物件轉成浮點數(float)型別
  • str(物件):將物件轉成字串(string)型別

!注意

  • 字串轉數字,需要符合整數、浮點數的格式
In [4]:
input1 = 123
input2 = "456"
input3 = "5566.123"
print (str(input1)+input2)
print (input1+int(input2))
print (float(input3)+input1)
print (int(input3))
123456
579
5689.123
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-4-347d8eaf9d2b> in <module>()
      5 print (input1+int(input2))
      6 print (float(input3)+input1)
----> 7 print (int(input3))

ValueError: invalid literal for int() with base 10: '5566.123'

再談字串

跳脫字元

當字串內有特殊字元的時候,要把「反斜線\」當作跳脫字元,後面跟著特定的符號編碼。

  • \':單引號'
  • \":雙引號"
  • \\:反斜線\
  • \n:ASCII的LF ,換行
  • \b:ASCII的BS ,退後一格
  • \r:ASCII的CR ,游標返回
  • \f:ASCII的FF ,插入一頁
  • \t:ASCII的HT ,水平定位,TAB
  • \v:ASCII的HT ,垂直定位
  • \a:ASCII的BEL,鈴響
  • \數字:換算成以八進位的ASCII碼
  • \x數字:換算成以十六進位的ASCII碼
In [5]:
print('PyLadies\'s Event', "Hello \"PyLadies\"")
print("Hello PyLadies\n")
print("\tHello PyLadies")
PyLadies's Event Hello "PyLadies"
Hello PyLadies

	Hello PyLadies

ASCII

In [6]:
print('\x61')
print('\141')
a
a

遇到了路徑表示

Desktop\pyladies\event02.py
可以在字串加上「r」,代表取消跳脫格式,保留原始的字元

In [7]:
print('\\')  # 原來的跳脫串代表印出一個反斜線
print(r'\\') # 用r取消跳脫,就是原來的兩個反斜線
\
\\
In [8]:
print("Desktop\\pyladies\\event02.py")
print(r"Desktop\pyladies\event02.py") 
Desktop\pyladies\event02.py
Desktop\pyladies\event02.py

但要注意不能以 \ 結尾,會被跳脫

In [9]:
print(r"C:\")  
  File "<ipython-input-9-e14c0efb0752>", line 1
    print(r"C:\")
                   ^
SyntaxError: EOL while scanning string literal

字串好用的方法

方法 method

  • 每個不同的型別都有各自不同的方法
  • Python的許多運算元、內建函式,這些操作方便的背後都是用方法來運作
    • 有些方法可以利用這些運算元、內建函式,
      用更簡單的寫法,去達到同樣的結果
In [10]:
print("Hello".__add__("PyLadies")) # 使用字串型別的__add__方法
print("Hello"+"PyLadies")          # 用+運算元,就簡單多了
HelloPyLadies
HelloPyLadies
In [11]:
x = 2
y = 3
print(x.__add__(y).__sub__(y.__pow__(2))) # 使用整數型別的方法
print(x+y-pow(y,2))                       # 使用運算元+內建函式
print(x+y-y**2)                           # 使用運算元
-4
-4
-4

取代 replace

原字串.replace(舊字串,新字串,取代次數)

  • 將「原字串」中「舊字串」都取代為「新字串」,
    產生一個新的「處理後字串」,並不會改變原來字串
  • 取代次數預設是無限次
In [12]:
my_string = "PyLadies Taiwan"
print(my_string.replace("a","A"))
print(my_string.replace("a","A",2))
print(my_string)
PyLAdies TAiwAn
PyLAdies TAiwan
PyLadies Taiwan
In [13]:
my_string = "PyLadies Taiwan"
my_string = my_string.replace("a","A") # 讓原來命名的標籤,貼到新的字串
print (my_string)
my_string = my_string.replace("T","L")
print (my_string)
my_string = my_string.replace("LA","")
print (my_string)
PyLAdies TAiwAn
PyLAdies LAiwAn
Pydies iwAn

replace 應用情境

景點改名

In [14]:
article="""
中正紀念堂,位於臺北市中正區,全區250,000平方公尺,主樓高76公尺。
中正紀念堂全區面積達250,000平方公尺,除了高76公尺的主建築外,還有國家戲劇院、國家音樂廳(合稱「兩廳院」),以及....等。
"""
# 字串太長,或有換行,可以用三個 雙引號" 或是 單引號' 包起來
article=article.replace("中正紀念堂","臺灣民主紀念園區")
print (article)
臺灣民主紀念園區,位於臺北市中正區,全區250,000平方公尺,主樓高76公尺。
臺灣民主紀念園區全區面積達250,000平方公尺,除了高76公尺的主建築外,還有國家戲劇院、國家音樂廳(合稱「兩廳院」),以及....等。

資料正規化

In [15]:
brand = "APPLE"
brand = brand.replace("A","A").replace("P","P").replace("L","L").replace("E","E")
print (brand)
APPLE

去除

常用在檔案、網頁內容的清理

  • 字串.strip(字元):從字串首尾兩端去除掉指定字元(預設為空格,可設定多個)
  • 字串.lstrip(字元):同strip(),但只去除首端
  • 字串.rstrip(字元):同strip(),但只去除尾端
In [16]:
s = """ Pyladies is a group of women developers 
who love Python. """
print(s.strip()+"END===")
print(s.lstrip()+"END===")
print(s.rstrip()+"END===")
Pyladies is a group of women developers 
who love Python.END===
Pyladies is a group of women developers 
who love Python. END===
 Pyladies is a group of women developers 
who love Python.END===
In [17]:
s = """ Pyladies is a group of women developers who love Python. 
"""
print(s+"END===")
print(s.strip(' \n\r.e')+"END===") # 去除掉空格、換行、句點、字母e
 Pyladies is a group of women developers who love Python. 
END===
Pyladies is a group of women developers who love PythonEND===

[練習]

試著把以下這篇演講逐字稿

  • 去除開頭的空白
  • 把前面出現的三個「女孩」取代成「女生」
  • 然後印出
article = """
 2012年我創立了一間公司 來教女孩寫程式 我發現到,透過教程式編寫 其實我是在培養她們變得勇敢 
程式編寫是一個「不斷檢測 與發現錯誤」的無止境過程 
要設法在對的地方,輸入正確的指令 有時候只是差一個分號 就足以決定成敗 
程式碼錯了,就全盤皆錯 時常要嘗試很多很多次 奇蹟才會出現 
你試著建構的東西總算活了起來 這項工作需要毅力 需要不完美

我們馬上就發現 參與學程的女孩都害怕犯錯 害怕不完美 「寫程式的女孩」計畫的每個老師 都告訴我一樣的故事 
第一週,女孩們還在學 怎麼編寫程式碼時 學生會請她過去跟她說 「我不知道要寫什麼程式碼」 
老師看了看她的螢幕 只會看到一片空白 
假如她不夠瞭解,她會覺得她的學生 花了20分鐘,只是盯著螢幕發呆 
但如果她多按幾下復原鍵 她會看見學生其實 寫下程式碼又刪除了 
她試過,她逼近了 可是還沒做到完全正確 
她不呈現編寫的進展 卻寧願給人看一片空白 寧缺勿濫"""

進階挑戰

  • 如果我希望把前面三個出現「女孩」的地方保留,而其他地方的「女孩」都取代成「女生」呢?

格式化-format

包含{}的字串.format(將{}取代的值)

format裡可以放數值、字串,不用特別再將數值轉換成字串型別

產生各股票網址(股票代號是在網址中,不是在尾端)

In [18]:
# 使用字串相加
url = "http://www.wantgoo.com/stock/"+str(2330)+"?searchType=stocks"
print (url)
url = "http://www.wantgoo.com/stock/"+str(2371)+"?searchType=stocks"
print (url)
http://www.wantgoo.com/stock/2330?searchType=stocks
http://www.wantgoo.com/stock/2371?searchType=stocks
In [19]:
# 使用格式化方法
url = "http://www.wantgoo.com/stock/{}?searchType=stocks".format(2330)
print (url)
url = "http://www.wantgoo.com/stock/{}?searchType=stocks".format(2371)
print (url)
http://www.wantgoo.com/stock/2330?searchType=stocks
http://www.wantgoo.com/stock/2371?searchType=stocks

可以傳遞很多參數

  • 按照順序取用參數
In [20]:
word1 = "颱風"
word2 = "泛舟"
my_sentence = "{}就是要{}呀,不然要幹嘛?".format(word1,word2)
my_sentence = word1+"就是要"+word2+"呀,不然要幹嘛?"           # 用字串相加,程式碼會比較凌亂
print (my_sentence)

word1 = "夏天"
word2 = "吃冰"
my_sentence = "{}就是要{}呀,不然要幹嘛?".format(word1,word2)
print (my_sentence)
颱風就是要泛舟呀,不然要幹嘛?
夏天就是要吃冰呀,不然要幹嘛?

[練習]

第一次會輸入{姓名},
第二次會輸入{喜好},
利用字串的format方法,
讓程式印出「我是PyLadies的{姓名},我喜歡{喜好},很高興認識大家!」

Hint:

  • input():輸入,要記得要用個命名物件去接,儲存的型別為字串
name = input()
hobby = _____
print("我是PyLadies的___,我喜歡___,很高興認識大家!"_______)

格式化-對齊

  • 字串.center(指定長度,單一字元):原字串置於中央,兩端補入指定字元
  • 字串.ljust(指定長度,單一字元):原字串置於左端,右端補入指定字元
  • 字串.rjust(指定長度,單一字元):原字串置於右端,左端補入指定字元

!注意

  • 指定字元預設為空格
  • 若指定長度比原字串長度小,結果等同原字串
In [21]:
s = "PyLadies"
print(s.center(5))
print(s.center(10))
print(s.ljust(10,'='))
print(s.rjust(10,'='))
PyLadies
 PyLadies 
PyLadies==
==PyLadies

格式化-數字補零

字串.zfill(指定長度)

  • 補零會在正負號之後
  • 正負號、小數點也會佔位子
  • 若指定長度比原字串長度小,結果等同原字串
In [22]:
print('12345'.zfill(4))
print('12345'.zfill(8))
print('-12345'.zfill(8))
print('+12345'.zfill(8))
print('123.45'.zfill(8))
12345
00012345
-0012345
+0012345
00123.45

[練習]

圓周率 pi=3.1415926...
想要印出小數點後兩位,有效位數為4(不包含小數點、正負號)
怎麼利用字串的方法、以及內建函式做到呢?

Hint:

  • round(數值型別,n):取小數點後n位
  • 字串.zfill()是「字串」的方法
  • str(物件):可以將物件轉換成字串型別
pi = 3.1415926
pi = round(pi,__)
pi = __.zfill(__)
print(pi)

大小寫

  • 字串.capitalize():首字元大寫,其餘皆小寫
  • 字串.title():「標題式大小寫」,句子中,
    每個單字的第一個字母大寫,其餘皆小寫
  • 字串.upper():全部大寫
  • 字串.lower():全部小寫
  • 字串.casefold():全部小寫
  • 字串.swapcase():大寫變小寫,小寫變大寫
  • replace一樣,並不會改變原本的字串
  • 遇到特殊字元,每個方法的處理方式不太一樣,多數頗為暴力。
In [24]:
s = "hello pyLadie's 123ABC你好ß"
print("capitalize => ",s.capitalize())
print("title      => ",s.title())
print("upper      => ",s.upper())
print("lower      => ",s.lower())
print("casefold   => ",s.casefold())
print("swapcase   => ",s.swapcase())
print(s)
capitalize =>  Hello pyladie's 123abc你好ß
title      =>  Hello Pyladie'S 123Abc你好Ss
upper      =>  HELLO PYLADIE'S 123ABC你好SS
lower      =>  hello pyladie's 123abc你好ß
casefold   =>  hello pyladie's 123abc你好ss
swapcase   =>  HELLO PYlADIE'S 123abc你好SS
hello pyLadie's 123ABC你好ß

[練習]

利用字串轉大小寫的方法,
把「hello pyLadies 123ABC」印成「hELLO pYLADIES 123aBC

判斷內容-大小寫

  • 字串.islower():是否包含字母,且全部小寫
  • 字串.isupper():是否包含字母,且全部大寫
  • 字串.istitle():是否符合標題式大小寫
In [25]:
print("abc12!3".islower(),"12!3".islower(),"Hello".islower())
print("hello hi".islower(),"hello Hi".islower())
print("HELLO PYTHON".isupper(),"HELLO Python".isupper())
print("Hello Pyladies".istitle(),"Hello PyLadies".istitle(),"Hello PyLadies".istitle())
True False False
True False
True False
True False False

判斷內容-是否只含有數字

  • 字串.isdecimal():僅支援0~9
  • 字串.isdigit() :除了支援0~9,還支援部分unicode字元
  • 字串.isnumeric():全支援

!注意

  • 包含小數點的數字,都會被判定成False
In [26]:
print("123".isnumeric(),"123.45".isnumeric()," H!123".isnumeric())
True False False
In [27]:
s = '123'
print(s,s.isdigit(),s.isdecimal(),s.isnumeric())
123 True True True
In [28]:
s = '\u00B2'
print(s,s.isdigit(),s.isdecimal(),s.isnumeric())
² True False True
In [29]:
s = '\u00BD'
print(s,s.isdigit(),s.isdecimal(),s.isnumeric())
½ False False True

判斷內容

  • 字串.isspace():是否只含有空白字元,
    包含空格字元、\n\r\f\t\v
  • 字串.isalpha():是否只含有字母
  • 字串.isalnum():是否只含有字母與數字(isalpha() or isnumeric())
  • 字串.isidentifier():是否符合命名規則
  • 字串.isprintable():是否只包含可視字元
    (除了單雙引號反斜線的跳脫字元非可視字元)
In [30]:
print(" \n\r\f\t\v".isspace()," H123".isspace())
print("abcDEF".isalpha()," H!123".isalpha())
print("abcDEF123".isalnum()," H!123".isalnum())
print("_name".isidentifier(),"Word1".isidentifier(),"1word".isidentifier(),"Word-1".isidentifier())
print("Hi PyLaides".isprintable(),'\t'.isprintable())
True False
True False
True False
True True False False
True False

[練習]

還記得字串轉數值的型別轉換int(物件)float(物件)嗎?
需要符合特定格式,不然程式會直接錯誤,無法在執行下去
這個時候就可以用字串的判別內容方法來幫我們處理:

  • 會輸入一個字串
    • 可能是整數、浮點數、無法轉換成數值的字串
  • 請將字串轉換成數字,並印出此數字+120的結果
    • 沒有小數點的請轉成int,有小數點的請轉成float
    • 如果字串是無法轉換成數值,請直接印出「無法運算」

Hint:

  • 會用到判斷式
  • 前面提到的字串判定數字的方法,無法判定小數點,
    想想看有什麼字串方法可以把小數點取代?然後再來判斷是否為數字
    • 更進階:11.22可以轉換成float,那11.22.33應該是不行的吧!
s = input()
if ____:
    print(int(s)+120)
____ ____:
    print(float(s)+120)
____:
    print('無法運算')

序列型別

常見序列型別的有字串(string)、串列(list)、元組(tuple)

串列(list)

  • 可以直接給定有值的串列
  • 也可以給空串列
  • 可以相+、相*

!注意

  • 串列的組成可以不必都是同樣類型的元素
In [32]:
my_list1 = ["a",2016,5566,"PyLadies"]
my_list2 = []
my_list3 = my_list1+[2016,2016.0]
my_list4 = [1,2,3]*3
print (my_list1,bool(my_list1))
print (my_list2,bool(my_list2))
print (my_list3)
print (my_list4)
['a', 2016, 5566, 'PyLadies'] True
[] False
['a', 2016, 5566, 'PyLadies', 2016, 2016.0]
[1, 2, 3, 1, 2, 3, 1, 2, 3]

存取串列元素

  • my_list[i]:取得索引(index)在i的元素
  • 索引可以是負數,如果是索引為-i,會被當作拿取索引為「串列長度-i」的元素

!注意

  • Python 是從0開始數
In [33]:
# 索引值     0 , 1  ,  2 ,    3     ,  4 ,  5   
my_list = ["a",2016,5566,"PyLadies",2016,2016.0] # 這是一個長度為6的串列
print ("The 4th  element",my_list[3])
print ("The last element",my_list[-1])           # 等同於拿取索引=6-1=5的元素
print ("The second-last element",my_list[-2])    # 等同於拿取索引=6-2=4的元素
The 4th  element PyLadies
The last element 2016.0
The second-last element 2016
In [34]:
my_list = ["a",2016,5566,"PyLadies",2016,2016.0]
b = my_list[1]
my_list[2] = 2017
print(b)
print(my_list)
2016
['a', 2016, 2017, 'PyLadies', 2016, 2016.0]

「字串」跟「串列」很像

  • 字串的每個元素都是一個字元(字母或符號)
  • 用同樣的方式存取元素
In [35]:
my_string = "PyLadies Taiwan"
print ("The 1st  element of my_string = ",my_string[0])
print ("The 8th  element of my_string = ",my_string[7])
print ("The last element of my_string = ",my_string[-1]) 
The 1st  element of my_string =  P
The 8th  element of my_string =  s
The last element of my_string =  n

!注意

  • 索引不能超過界線
In [36]:
print(my_string[20])
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-36-071b8d4e8c76> in <module>()
----> 1 print(my_string[20])

IndexError: string index out of range

「元組(tuple)」跟「串列」更像

  • 元組是不能修改的串列

!注意

  • 因為()會被當成調整運算元的優先順序,所以只有一個元素的元組,要多加,
In [37]:
my_tuple1 = ("a",2016,5566,"PyLadies")
my_tuple2 = ()
my_tuple3 = my_tuple1+(2016,2016.0)
my_tuple4 = (1,2,3)*3
my_tuple5 = (1,)
print (my_tuple1,bool(my_tuple1))
print (my_tuple2,bool(my_tuple2))
print (my_tuple3)
print (my_tuple4)
print (my_tuple5)
print (my_tuple1[1])
('a', 2016, 5566, 'PyLadies') True
() False
('a', 2016, 5566, 'PyLadies', 2016, 2016.0)
(1, 2, 3, 1, 2, 3, 1, 2, 3)
(1,)
2016

型別轉換

In [38]:
s = "PyLadies"
l = ["a",2016,5566,"PyLadies"]
t = ("a",2016,5566,"PyLadies")
print(type(list(t)))
print(type(tuple(l)))
print(list(s))
print(tuple(s))
<class 'list'>
<class 'tuple'>
['P', 'y', 'L', 'a', 'd', 'i', 'e', 's']
('P', 'y', 'L', 'a', 'd', 'i', 'e', 's')

比較運算

  • 從第1個元素開始比,如果一樣就再比第2個元素...,直到不一樣就停止比對。
  • 如果元素型別不同,會出現錯誤!
In [39]:
s1 = "Hi"
s2 = "Hello" 
print(s1<s2) # i 的 ASCII 比 e 大
False
In [40]:
l1 = ["a",2016,5566,"PyLadies"]
l2 = ["a",2016,5566,"PyLadies"]
print(l1==l2)
l2+= [2017]
print(l2>l1,l2)
True
True ['a', 2016, 5566, 'PyLadies', 2017]
In [41]:
l3 = ["a",2016,"PyLadies"]
print(l1<l3)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-41-5b31c0361295> in <module>()
      1 l3 = ["a",2016,"PyLadies"]
----> 2 print(l1<l3)

TypeError: unorderable types: int() < str()

可變與不可變

intfloatstrtuple是不可變(immutable)物件,在建立之後就不能更改他的值,
list是可變(mutable)物件。

!注意

以下這段程式碼,是讓a這個名稱,指向別的物件,
也就是把標籤撕下來貼到別人身上,並不是更改a的值喔!

a = 3  
a = 4

原先的3這個物件,如果沒有其他名稱指到他,就會成為垃圾,被系統回收。

In [ ]:
l = ["a",2016,5566,"PyLadies"]
t = ("a",2016,5566,"PyLadies")
l[1] = 2017
t[1] = 2017

判斷是否指向同一個物件

  • s is ts is not t
In [ ]:
a = 3
b = 3
c = a
print(a is b,a is c)
print(id(a),id(b),id(c))
a += 2  # a = 5
b = 4   
print(a is b,a is c)
print(id(a),id(b),id(c))

不可變物件,進行運算、或是重新指向,都是直接指向新的物件。

In [42]:
l1 = ["a",2016,5566,"PyLadies"]
l2 = l1
print(l1 is l2,id(l1),id(l2))
True 140328731022024 140328731022024
In [43]:
l1 += ["Hi"]
print(l1 is l2,id(l1),id(l2))
print(l1)
print(l2)
True 140328731022024 140328731022024
['a', 2016, 5566, 'PyLadies', 'Hi']
['a', 2016, 5566, 'PyLadies', 'Hi']
In [44]:
l2[2] = 2017
print(l1 is l2,id(l1),id(l2))
print(l1)
print(l2)
True 140328731022024 140328731022024
['a', 2016, 2017, 'PyLadies', 'Hi']
['a', 2016, 2017, 'PyLadies', 'Hi']

!注意

  • 可變物件不管怎麼修改,位置還是不會變的
  • 如果有兩個名稱指向同一個可變物件,物件一修改,
    兩個名稱取到的都會是同樣一個修改之後的物件

序列共同介面

前面提到的利用 序列[索引] 存取元素,也是共同介面之一!

序列長度

len(s)

In [45]:
my_string = "PyLadies Taiwan"
my_list = ["a",2016,5566,"PyLadies",2016,2016.0]
print ("Length of my_string = ",len(my_string))
print ("Length of my_list = ",len(my_list))
Length of my_string =  15
Length of my_list =  6

數值計算

  • max(串列):序列中最大值
  • min(串列):序列中最小值
  • sum(串列):序列總和,針對全數字序列才有用
In [46]:
l = [3, 4, 2.1, 1]
t = (3, 4, 2.1, 1)
s = "PyLadies"
print(max(l),min(l),sum(l))
print(max(t),min(t),sum(t))
print(max(s),min(s))
print(sum(s))
4 1 10.1
4 1 10.1
y L
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-46-b1315ad1dd8c> in <module>()
      5 print(max(t),min(t),sum(t))
      6 print(max(s),min(s))
----> 7 print(sum(s))

TypeError: unsupported operand type(s) for +: 'int' and 'str'

[練習]

統計全班的成績狀況:

  • 全班最高分與最低分的落差為?
  • 全班分數的平均為?
In [47]:
score_of_each_student = [85,70,54,87,98,66,40]
In [48]:
avg_score = sum(score_of_each_student) / len(score_of_each_student)
print ("全班分數落差為",max(score_of_each_student)-min(score_of_each_student))
print ("全班平均為",avg_score)
全班分數落差為 58
全班平均為 71.42857142857143

判斷序列中是否存在某元素

x in sx not in s

In [49]:
my_string = "PyLadies Taiwan"

if "PyLadies" in my_string:
    print ("\"PyLadies\" found")
if "Python" in my_string:
    print ("\"Python\" found")
if "Taiwan" in my_string:
    print ("\"Taiwan\" found")
"PyLadies" found
"Taiwan" found
In [50]:
my_list = ["a",2016,5566,"PyLadies",2016,2016.0]
print(2016 in my_list)
print("2016" in my_list)
True
False

序列出現某元素的次數

s.count(x)

In [51]:
my_string = "PyLadies Taiwan"
my_list = ["a",2016,5566,"PyLadies",2016,2016.0]
print ("The time 'a' appears in my_string = ",my_string.count('a'))
print ("The time '2016' appears in my_string = ",my_list.count(2016))
The time 'a' appears in my_string =  3
The time '2016' appears in my_string =  3

[練習]

想想看要用什麼序列方法,找出以下這篇文章,出現幾次「in」

In [52]:
article = """
Bubble tea represents the "QQ" food texture that Taiwanese love. 
The phrase refers to something that is especially chewy, like the tapioca balls that form the 'bubbles' in bubble tea. 
It's said this unusual drink was invented out of boredom. 
"""
In [53]:
print (article.count("in"))
4

「in」的確在文章出現4次:someth"in"g、"in"、dr"in"k、"in"vented
但如果我們想要的是代表單字的「in」,就需要把文章分割,再來計算!

序列的應用

分割

串列 = 原字串.split(子字串,最多分割次數)

  • 將「原字串」以「子字串」切割,產生一個新的「串列」(不改變原本字串)
  • 最多分割次數預設為無限
In [54]:
s = "Hi PyLadies Taiwan"
l = s.split(" ")
print (l)
print (s.split(" ",1))
print (s)
print (l[0])
print (l[-1])
['Hi', 'PyLadies', 'Taiwan']
['Hi', 'PyLadies Taiwan']
Hi PyLadies Taiwan
Hi
Taiwan

[練習]

所以再想想看要用哪些序列方法,找出以下這篇文章,出現幾次單字「in」

  • 把文章切割成單字
  • 算出單字中,「in」出現幾次
In [55]:
article = """
Bubble tea represents the "QQ" food texture that Taiwanese love. 
The phrase refers to something that is especially chewy, like the tapioca balls that form the 'bubbles' in bubble tea. 
It's said this unusual drink was invented out of boredom. 
"""
In [56]:
word_of_article = article.split(" ")
print (word_of_article.count("in"))
1

那這篇文章出現幾次「tea」呢?

In [57]:
article = """
Bubble tea represents the "QQ" food texture that Taiwanese love. 
The phrase refers to something that is especially chewy, like the tapioca balls that form the 'bubbles' in bubble tea. 
It's said this unusual drink was invented out of boredom. 
"""
word_of_article = article.split(" ")
In [58]:
print (word_of_article.count("tea"))
1

可是文章中我們有看到兩次的tea,怎麼只算一次?
原因是因為split之後,是分成「tea」、「tea.」
這兩個是不同的字串,以count("tea")來說,就只會算到剛好等於「tea」的字

所以可以先將常用標點符號取代之後再來計算!

[練習]

所以再想想看要用哪些序列方法,找出以下這篇文章,出現幾次單字「tea」

  • 把標點符號取代
  • 把文章切割成單字
  • 算出單字中,「tea」出現幾次
In [59]:
clean_article = article.replace(".","").replace(",","").replace(":","")
clean_article = clean_article.replace("?","").replace("\"","").replace("\'","")
word_of_article = clean_article.split(" ")
print (word_of_article.count("tea"))
2

如果遇到大小寫不同,記得前面有講過字串有方法可以轉換大小寫!

應用情境 - 日期正規化 (年-月-日 時:分:秒)

In [60]:
ebc_datetime = "2016-10-17 17:00"
back_datetime = "2016-10-11, 19:55"
ptt_datatime = "Tue Oct 18 23:22:05 2016"

format_ebc_datetime = ebc_datetime+":00"
format_back_datetime = back_datetime.replace(",","")+":00"

# ptt
ptt_split_list = ptt_datatime.split(" ")
ptt_year = ptt_split_list[-1]
ptt_month = ptt_split_list[1].replace("Oct","10")
ptt_date = ptt_split_list[2]
ptt_time = ptt_split_list[3]
format_ptt_datetime = "{}-{}-{} {}".format(ptt_year,ptt_month,ptt_date,ptt_time)

print (format_ebc_datetime)
print (format_back_datetime)
print (format_ptt_datetime)
2016-10-17 17:00:00
2016-10-11 19:55:00
2016-10-18 23:22:05

同樣道理,
如果是用要用in判斷,找「單字」是否存在字串中,
記得先分割成單字的字串才使用

In [61]:
my_string = "PyLadies Taiwan"
if "Py" in my_string:
    print ("\"Py\" found in my_string")

my_string_list = my_string.split(" ")
if "Py" in my_string_list:
    print ("\"Py\" found in my_string_list")
"Py" found in my_string

應用情境 - 日期正規化 (年-月-日 時:分:秒) 24小時制

In [62]:
yahoo_datetime = "2016年10月18日 下午10:33"
temp_yahoo_date = yahoo_datetime.split(" ")[0].replace("年","-").replace("月","-")
temp_yahoo_date = temp_yahoo_date.replace("日","")
temp_yahoo_time = yahoo_datetime.split(" ")[-1]
temp_yahoo_hour = temp_yahoo_time.split(":")[0]
temp_yahoo_mins = temp_yahoo_time.split(":")[-1]

if "下午" in temp_yahoo_hour:
    temp_yahoo_hour_int = int(temp_yahoo_hour.replace("下午",""))+12
    temp_yahoo_hour = str(temp_yahoo_hour_int)
else:
    temp_yahoo_hour_int = int(temp_yahoo_hour.replace("上午",""))
    temp_yahoo_hour = str(temp_yahoo_hour_int)

format_yahoo_datetime = "{} {}:{}:00".format(temp_yahoo_date,temp_yahoo_hour,temp_yahoo_mins)
print (format_yahoo_datetime)
    
2016-10-18 22:33:00

組合

字串 = 間隔字串.join(序列)

  • 與split分割相反,是將字串串列以某個字串組合起來
  • 針對全字串串列才有用
In [63]:
l = ["Hello","PyLadies","Taiwan"]
t = ("Hello","PyLadies","Taiwan")
s = "Hi PyLadies"
print (" ".join(l))
print (",.".join(t))
print (".".join(s))
Hello PyLadies Taiwan
Hello,.PyLadies,.Taiwan
H.i. .P.y.L.a.d.i.e.s

應用情境 - 正規化 ('人名1','人名2','人名3')

  • 常用在SQL語法
In [64]:
l = ["Kelly","Mars","Maomao"]
s = "','".join(l)
print(s)
print("('{}')".format(s))
Kelly','Mars','Maomao
('Kelly','Mars','Maomao')

總練習

[練習]

簡易型計算機(加減乘除、次方、餘數),
輸入一行文字,印出計算結果

  • 只會有兩個數字,與一個運算元

ex:

  • 11+2 -> 13
  • 2**3 -> 8
  • 10%3 -> 1

[think]

如果我要算這篇文章,每個單字出現幾次:

In [65]:
article = """Bubble tea represents the "QQ" food texture that Taiwanese love. 
The phrase refers to something that is especially chewy, like the tapioca balls that form the 'bubbles' in bubble tea. 
It's said this unusual drink was invented out of boredom. 
"""
word_of_article = article.split(" ")
print(word_of_article[0],word_of_article.count(word_of_article[0]))
print(word_of_article[1],word_of_article.count(word_of_article[1]))
print(word_of_article[2],word_of_article.count(word_of_article[2]))
Bubble 1
tea 1
represents 1

總不能一個個慢慢寫吧...
下一次活動就會教到程式語言中很厲害的技巧:「迴圈」

補充知識-再談format

format 是一個非常強大的格式化方法,{}裡面其實有很多的方法可以運用
{指名成分!轉換:格式指定子}

https://docs.python.org/3.4/library/string.html

指名與成分 field_name

  • 指名:用數字或關鍵字決定取用哪個關鍵字
  • 成分:更進一步取用物件裡面的元素,可用索引或是屬性
In [66]:
print("{}-{}-{}".format(2017,10,1))    # 預設是按照順序
print("{0}-{2}-{1}".format(2017,10,1)) # 指名:數字
print("{year}-{month}-{date}".format(month=10,year=2017,date=1)) # 指名:關鍵字
2017-10-1
2017-1-10
2017-10-1
In [67]:
l = ['a','b','c']
t = (1,2,3)
c = 3-5j
print("複數的實數部分{}".format(c.real))    # 成分:屬性
print("{0[0]}-{0[1]}-{1[2]}".format(l,t)) # 成分:索引(只能用零或正整數)
print("{}-{}-{}".format(l[0],l[1],t[2]))  
print("{}-{}-{}".format(l[-1],l[1],t[2])) # 要用負數索引,只能用在參數
複數的實數部分3.0
a-b-3
a-b-3
c-b-3

轉換 conversion

使用方式是以驚嘆號!開頭,後面只能跟著

  • s:呼叫內建函式str()
  • r:呼叫內建函式repr()
  • a:呼叫內建函式ascii()
In [68]:
s = "桌面\pyladies\nb.py"
print("{!s}".format(s)) # 等同於 print(s)
桌面\pyladies
b.py
In [69]:
print("{!r}".format(s)) # 不處理跳脫
print("{!a}".format(s)) # 遇到非半形英數符號,會用Unicode跳脫表達
'桌面\\pyladies\nb.py'
'\u684c\u9762\\pyladies\nb.py'

格式指令子 format_spec

使用方式是以冒號:開頭
[[fill]align][sign][#][0][width][,][.precision][typecode]

[[fill]align][sign][#][0][width][,][.precision][typecode]

  • align:「<」靠左對齊、「>」靠右對齊、「^」置中對齊、「=」填補
  • width:欄寬

可以實現前面提到字串的對齊方法:

In [70]:
i = 1253.14159
print('{:15}'.format(i))       # width~15 數值預設靠右對齊
print('{:15}'.format(str(i)))  # width~15 字串預設靠左對齊
print('{:>15}'.format(str(i))) # align~「>」 width~15
print(str(i).rjust(15,' '))
print('{:<15}'.format(str(i))) # align~「<」 width~15
print(str(i).ljust(15,' '))
print('{:^15}'.format(str(i))) # align~「^」 width~15
print(str(i).center(15,' '))   # 字串長度10,(15-10)%2=1 優先放在左邊
     1253.14159
1253.14159     
     1253.14159
     1253.14159
1253.14159     
1253.14159     
  1253.14159   
   1253.14159  

[[fill]align][sign][#][0][width][,][.precision][typecode]

  • align:「<」靠左對齊、「>」靠右對齊、「^」置中對齊、「=」填補
    • fill:可使用除了大括號以外的任何字元填補(預設為空格)
  • sign:可使用空格、「+」、「-」
  • width:欄寬

可以實現前面提到字串的補零方法:

In [71]:
i = 1253.14159
print('{: 15}'.format(i))   # sign~空格 width~15
print('{:=15}'.format(i))   # fill~空格 align~「=」 width~15
print('{:+15}'.format(i))   # sign~正號 width~15
print('{:=+15}'.format(i))  # fill~空格 align~「=」 sign~「+」 width~15
print('{:0=+15}'.format(i)) # fill~'0' align~「=」 sign~「+」 width~15
s = '+1253.14159'
print(s.zfill(15))
     1253.14159
     1253.14159
    +1253.14159
+    1253.14159
+00001253.14159
+00001253.14159

[[fill]align][sign][#][0][width][,][.precision][typecode]

  • align:「<」靠左對齊、「>」靠右對齊、「^」置中對齊、「=」填補
    • fill:可使用除了大括號以外的任何字元填補(預設為空格)
  • 0:數值前補零
  • width:欄寬

!注意

  • 如果同時有fill、0,以fill優先
In [72]:
i = 1253.14159
print('{:15}'.format(i))    #   width~15
print('{:015}'.format(i))   # 0 width~15
print('{:?=015}'.format(i)) # fill~空格 align~「=」 0 width~15 
     1253.14159
000001253.14159
?????1253.14159

[[fill]align][sign][#][0][width][,][.precision][typecode]

  • ,:每一千(三個位數)就加上逗號
  • .precision:表示精確度,小數點後precision-1位數,以指數表示
    • 若後面接著typecode,則是小數點後precision位數
  • typecode
    • f、F:以浮點數表示,預設是小數點後六位
    • e、E:以指數表示,預設是小數點後六位(小寫、大寫字母)
In [73]:
i = 1253.14159
print('{:,}'.format(i))    # ,
print('{:.2}'.format(i))   #   .precsion~2
print('{:,.2F}'.format(i)) # , .precsion~2 typecode~f
print('{:F}'.format(i))    #               typecode~f
print('{:.2e}'.format(i))  #   .precsion~2 typecode~e
print('{:E}'.format(i))    #               typecode~e
1,253.14159
1.3e+03
1,253.14
1253.141590
1.25e+03
1.253142E+03

[[fill]align][sign][#][0][width][,][.precision][typecode]

  • #:以另外一種方式表示
    • 8進位前面會加上0o
    • 16進位前面會加上0x
  • typecode
    • o:有號8進位整數
    • x、X:有號16進位整數(小寫、大寫字母)
In [74]:
i = 200
print('{:o}'.format(i))  #  8進位的310=(3*8^2)+(1*8^1)+(0*8^0)=200
print('{:#o}'.format(i)) #  8進位的310=(3*8^2)+(1*8^1)+(0*8^0)=200
print('{:x}'.format(i))  # 16進位的c8 =(12*16^1)+(8*16^0)=200
print('{:X}'.format(i))  # 16進位的C8 =(12*16^1)+(8*16^0)=200
print('{:#x}'.format(i))  # 16進位的c8 =(12*16^1)+(8*16^0)=200
310
0o310
c8
C8
0xc8

字串的其他格式化作法

  • 運算子%
  • 內建函式 format()

這兩種是比較舊,但比較簡單的寫法,
不過參數要對應指定型別d~interger、f~float、s~string
紅色部分是跟前面提到的字串format方法-格式指令子,有相同功能的
[[fill]align][sign][#][0][width][,][.precision][typecode]

In [75]:
i = 1253.14159
print('{:015}'.format(i))
print('%015f'%(i)) #小數點預設6位
print('%015.5f'%(i)) 
print(format(i,'015.5f'))
000001253.14159
00001253.141590
000001253.14159
000001253.14159
In [76]:
i = 200
print('{}'.format(i),'%d'%(i))  
print('{:o}'.format(i),'%o'%(i))  
print('{:#x}'.format(i),'%#x'%(i)) 
200 200
310 310
0xc8 0xc8

補充知識-將TAB取代成空格

原字串.expandtabs(取代成TAB寬度的空白)

  • TAB在Python的預設寬度為8
    (在不同環境TAB的寬度會不一樣,像是編輯器很常預設為4)
  • 不等同於 字串.replace("\t", " " * n).
    • 是以TAB出現前面m個字元來決定,取代公式是:n - m%n

參考來源:Python expandtabs string operation | StackOverflow

In [77]:
s = "Hello\tPyLadies"
#    12345 
print(s.expandtabs(1)) #  1 - 5%1 = 1-0 = 1
print(s.expandtabs(2)) #  2 - 5%2 = 2-1 = 1
print(s.expandtabs(3)) #  3 - 5%3 = 3-2 = 1
print(s.expandtabs(4)) #  4 - 5%4 = 4-1 = 3
print(s.expandtabs(5)) #  5 - 5%5 = 5-0 = 5
print(s.expandtabs(6)) #  6 - 5%6 = 6-5 = 1
print(s.expandtabs(7)) #  7 - 5%7 = 7-5 = 2
print(s.expandtabs())  #  8 - 5%8 = 8-5 = 3
Hello PyLadies
Hello PyLadies
Hello PyLadies
Hello   PyLadies
Hello     PyLadies
Hello PyLadies
Hello  PyLadies
Hello   PyLadies
In [78]:
s = "Hi\tPyLadies\t"
#    12 
print(s.expandtabs(1)) #  1 - 2%1 = 1-0 = 1
print(s.expandtabs(2)) #  2 - 2%2 = 2-0 = 2
print(s.expandtabs(3)) #  3 - 2%3 = 3-2 = 1
print(s.expandtabs(4)) #  4 - 2%4 = 4-2 = 2
print(s.expandtabs(5)) #  5 - 2%5 = 5-2 = 3
print(s.expandtabs(6)) #  6 - 2%6 = 6-2 = 4
print(s.expandtabs(7)) #  7 - 2%7 = 7-2 = 5
print(s.expandtabs())  #  8 - 2%8 = 8-2 = 6
Hi PyLadies 
Hi  PyLadies  
Hi PyLadies 
Hi  PyLadies    
Hi   PyLadies  
Hi    PyLadies    
Hi     PyLadies      
Hi      PyLadies        
In [79]:
s = "Hello\tNice\tto see you"
#    12345  1234
print(s.expandtabs(1)) #  1 - 5%1 = 1-0 = 1  ,  1 - 4%1 = 1-0 = 1 
print(s.expandtabs(2)) #  2 - 5%2 = 2-1 = 1  ,  2 - 4%2 = 2-0 = 2
print(s.expandtabs(3)) #  3 - 5%3 = 3-2 = 1  ,  3 - 4%3 = 3-1 = 2 
print(s.expandtabs(4)) #  4 - 5%4 = 4-1 = 3  ,  4 - 4%4 = 4-0 = 4 
print(s.expandtabs(5)) #  5 - 5%5 = 5-0 = 5  ,  5 - 4%5 = 5-4 = 1 
print(s.expandtabs(6)) #  6 - 5%6 = 6-5 = 1  ,  6 - 4%6 = 6-4 = 2 
print(s.expandtabs(7)) #  7 - 5%7 = 7-5 = 2  ,  7 - 4%7 = 7-4 = 3 
print(s.expandtabs())  #  8 - 5%8 = 8-5 = 3  ,  8 - 4%8 = 8-4 = 4 
Hello Nice to see you
Hello Nice  to see you
Hello Nice  to see you
Hello   Nice    to see you
Hello     Nice to see you
Hello Nice  to see you
Hello  Nice   to see you
Hello   Nice    to see you

補充知識-更多字串切割方法

  • 將「原字串」以「子字串」切割,產生一個新的「序列」(不改變原本字串)

不保留切割字串

  • 原字串.split(子字串,最多分割次數) :從左邊開始切,預設無限次
  • 原字串.rsplit(子字串,最多分割次數):從右邊開始切,預設無限次
In [80]:
s="Hello PyLadies Taiwan"
print(s.split(" "))
print(s.rsplit(" "))
print(s.split(" ",1))
print(s.rsplit(" ",1))
['Hello', 'PyLadies', 'Taiwan']
['Hello', 'PyLadies', 'Taiwan']
['Hello', 'PyLadies Taiwan']
['Hello PyLadies', 'Taiwan']

只切割一次,並保留切割字串

切割後的型別為元祖tuple

  • 原字串.partition(子字串) :從左邊開始切
  • 原字串.rpartition(子字串):從右邊開始切
In [81]:
s="Hello PyLadies Taiwan"
print(s.split(" ",1))
print(s.partition(" "))
print(s.rsplit(" ",1))
print(s.rpartition(" "))
['Hello', 'PyLadies Taiwan']
('Hello', ' ', 'PyLadies Taiwan')
['Hello PyLadies', 'Taiwan']
('Hello PyLadies', ' ', 'Taiwan')

以換行切割,並可決定保留與否

  • 原字串.splitlines()
  • 原字串.splitlines(True):保留換行字元
In [82]:
s="Hello\n\nPyLadies\r\nTaiwan\nWelcome"
print(s.replace("\r","").split("\n"))
print(s.splitlines())
print(s.splitlines(True))
['Hello', '', 'PyLadies', 'Taiwan', 'Welcome']
['Hello', '', 'PyLadies', 'Taiwan', 'Welcome']
['Hello\n', '\n', 'PyLadies\r\n', 'Taiwan\n', 'Welcome']

學習資源對應

  • Python 程式設計入門 (適用於 2.x 與 3.x 版) 葉難
    • 02 開始撰寫Python 程式
      • 2.1 名稱、物件、型別、指派:串列、可變與不可變、tuple
      • 2.2 運算式:串列運算、is、in
    • 04 序列型別與迭代
      • 4.2 抽象型別:共同介面(部分)
      • 4.3 元素存取:索引、比較、運算子「+」與「*
      • 4.6 字串
        • 不包含:子字串方法
  • The Python Standard Library(Python 3.6.2)
    • 4.6.1. Common Sequence Operations
    • 4.6.5. Tuples
    • 4.7. Text Sequence Type
    • 6.1.3. Format String Syntax