2020-02-04python學(xué)習(xí)記錄(4)-第三方庫&IO

八阁危、第三方庫

主要是

通過pip的方式安裝:

pip3 install PackageName

python3 -m pip install PackageName

sudo pip install PackageName

pip install --upgrade pip #升級pip

pip uninstall flask? #卸載庫

pip list? ? #查看已安裝庫

九朦拖、文件讀寫

讀文件:read

file = open('url.txt','r')

調(diào)用read()方法可以一次讀取文件的全部內(nèi)容狼牺,Python把內(nèi)容讀到內(nèi)存,用一個str對象表示。

#!/usr/bin/env python3 # -*- coding: utf-8 -*-? try:? ? f = open('/Users/XXX/Desktop/url.txt','r'encoding='utf-8', errors='ignore')? ? print(f.read()) finally:? ? if f:? ? ? ? f.close()

最后一步是調(diào)用close()方法關(guān)閉文件

但是每次都需要關(guān)閉文件流:(上面的文件可以改寫成)

#!/usr/bin/env python3 # -*- coding: utf-8 -*-? with open('/Users/fuwei/Desktop/url.txt','r', encoding='utf-8', errors='ignore') as file:? print(file.read())

encoding='utf-8', errors='ignore'

中文編碼和忽略非法編碼的字符

寫文件:write

file = open('url.txt','w')

調(diào)用read()方法可以一次讀取文件的全部內(nèi)容月趟,Python把內(nèi)容讀到內(nèi)存杨幼,用一個str對象表示撇簿。

#!/usr/bin/env python3 # -*- coding: utf-8 -*-? try:? ? f = open('/Users/XXX/Desktop/url.txt','w'encoding='utf-8', errors='ignore')? ? print(f.read()) finally:? ? if f:? ? ? ? f.close()

最后一步是調(diào)用close()方法關(guān)閉文件

但是每次都需要關(guān)閉文件流:(上面的文件可以改寫成)

#!/usr/bin/env python3 # -*- coding: utf-8 -*-? with open('/Users/fuwei/Desktop/url.txt','w', encoding='utf-8', errors='ignore') as file:? print(file.read())

encoding='utf-8', errors='ignore'

中文編碼和忽略非法編碼的字符

會發(fā)現(xiàn),以'w'模式寫入文件時差购,如果文件已存在四瘫,會直接覆蓋(相當(dāng)于刪掉后新寫入一個文件)。如果我們希望追加到文件末尾怎么辦欲逃?可以傳入'a'以追加(append)模式寫入找蜜。

StringIO和BytesIO[字符流和字節(jié)流]

StringIO和BytesIO是在內(nèi)存中操作str和bytes的方法,使得和讀寫文件具有一致的接口稳析。

操作文件和目錄:

要操作文件洗做、目錄弓叛,可以在命令行下面輸入操作系統(tǒng)提供的各種命令來完成。比如dir诚纸、cp等命令撰筷。

操作文件和目錄

# 查看當(dāng)前目錄的絕對路徑: >>> os.path.abspath('.') '/Users/michael' # 在某個目錄下創(chuàng)建一個新目錄,首先把新目錄的完整路徑表示出來: >>> os.path.join('/Users/michael', 'testdir') '/Users/michael/testdir' # 然后創(chuàng)建一個目錄: >>> os.mkdir('/Users/michael/testdir') # 刪掉一個目錄: >>> os.rmdir('/Users/michael/testdir')

Python的os模塊封裝了操作系統(tǒng)的目錄和文件操作畦徘,要注意這些函數(shù)有的在os模塊中毕籽,有的在os.path模塊中。

十井辆、進程和線程

提高效率:

一種是啟動多個進程影钉,每個進程雖然只有一個線程,但多個進程可以一塊執(zhí)行多個任務(wù)掘剪。

還有一種方法是啟動一個進程平委,在一個進程內(nèi)啟動多個線程,這樣夺谁,多個線程也可以一塊執(zhí)行多個任務(wù)廉赔。

當(dāng)然還有第三種方法,就是啟動多個進程匾鸥,每個進程再啟動多個線程蜡塌,這樣同時執(zhí)行的任務(wù)就更多了,當(dāng)然這種模型更復(fù)雜勿负,實際很少采用馏艾。

總結(jié)一下就是,多任務(wù)的實現(xiàn)有3種方式:

多進程模式奴愉;

多線程模式琅摩;

多進程+多線程模式。

多進程:process

fork(Unix/Linux/Mac)

Unix/Linux操作系統(tǒng)提供了一個fork()系統(tǒng)調(diào)用锭硼,它非常特殊房资。普通的函數(shù)調(diào)用,調(diào)用一次檀头,返回一次轰异,但是fork()調(diào)用一次,返回兩次暑始,因為操作系統(tǒng)自動把當(dāng)前進程(稱為父進程)復(fù)制了一份(稱為子進程)搭独,然后,分別在父進程和子進程內(nèi)返回廊镜。

#!/usr/bin/env python3 # -*- coding: utf-8 -*-? import os? def process():? print('Process (%s) start...' % os.getpid())? # Only works on Unix/Linux/Mac:? pid = os.fork() #fork復(fù)制一個子進程? if pid == 0:? ? ? print('I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid()))? else:? ? ? print('I (%s) just created a child process (%s).' % (os.getpid(), pid))? if __name__ == '__main__':? process()

由于Windows沒有fork調(diào)用牙肝,fork只能在Unix/Linux/Mac

multiprocessing(多平臺 Unix/Linux/Mac/win)

由于Windows沒有fork調(diào)用,難道在Windows上無法用Python編寫多進程的程序?

由于Python是跨平臺的惊奇,自然也應(yīng)該提供一個跨平臺的多進程支持互躬。multiprocessing模塊就是跨平臺版本的多進程模塊。

multiprocessing模塊提供了一個Process類來代表一個進程對象颂郎,下面的例子演示了啟動一個子進程并等待其結(jié)束:

#!/usr/bin/env python3 # -*- coding: utf-8 -*-? from multiprocessing import Process import os? # 子進程要執(zhí)行方法 def run_proc(name):? ? print('運行子進程 %s (%s)...' % (name, os.getpid()))? if __name__=='__main__':? ? print('父進程 %s.' % os.getpid()) #打印當(dāng)前的進程? ? p = Process(target=run_proc, args=('test',)) #調(diào)用指定方法run_proc 傳入?yún)?shù)? ? print('子進程將運行.')? ? p.start() #啟動子進程? ? p.join()? #將進程添加到調(diào)用的進程? ? print('子進程關(guān)閉')

Pool (進程池的方式批量創(chuàng)建子進程)

如果要啟動大量的子進程吼渡,可以用進程池的方式批量創(chuàng)建子進程:

#!/usr/bin/env python3 # -*- coding: utf-8 -*-? from multiprocessing import Pool import os, time, random? # 子進程要執(zhí)行方法 def run_proc(name):? ? print('運行子進程 %s (%s)...' % (name, os.getpid()))? ? start = time.time()? ? time.sleep(random.random() * 3)? ? end = time.time()? ? print('運行子進程 %s 運行的時間 %2f' % (name,(end - start))) #計算子進程運行的時間? if __name__=='__main__':? print('父進程 %s.' % os.getpid()) #打印當(dāng)前的進程? ? ? p = Pool(4) #創(chuàng)建進程連接池-最大的連接數(shù)是4? for i in range(5):? ? ? p.apply_async(run_proc, args = (i , )) #連接池調(diào)用運行進程的方法,同時傳入?yún)?shù)? ? print('等待全部的進程完成乓序。寺酪。。')? ? p.close() #關(guān)閉連接池? ? p.join()? #調(diào)用全部的子進程執(zhí)行? ? print('全部的進程完成')

添加詳細的每一步的注釋替劈。

代碼解讀:

對Pool對象調(diào)用join()方法會等待所有子進程執(zhí)行完畢寄雀,調(diào)用join()之前必須先調(diào)用close(),調(diào)用close()之后就不能繼續(xù)添加新的Process了陨献。

子進程:

很多時候盒犹,子進程并不是自身,而是一個外部進程眨业。我們創(chuàng)建了子進程后急膀,還需要控制子進程的輸入和輸出。

subprocess模塊可以讓我們非常方便地啟動一個子進程龄捡,然后控制其輸入和輸出卓嫂。

下面的例子演示了如何在Python代碼中運行命令nslookup www.python.org,這和命令行直接運行的效果是一樣的: #!/usr/bin/env python3 # -*- coding: utf-8 -*-? import subprocess? def lookup():? print('$ nslookup www.python.org')? r = subprocess.call(['nslookup', 'www.python.org'])? print('Exit code:', r)? if __name__=='__main__':? lookup()

運行的結(jié)果:

上面的代碼相當(dāng)于nslookup聘殖,利用DNS去解析

如何使用指定DNS服務(wù)器查詢?

語法為 nslookup -qt=類型 目標(biāo)域名 指定的DNS服務(wù)器IP或域名

例子:nslookup -qt=A tool.chinaz.com 8.8.8.8

如果子進程還需要輸入晨雳,則可以通過communicate()方法輸入:

import subprocess? print('$ nslookup') p = subprocess.Popen(['nslookup'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output, err = p.communicate(b'set q=mx\npython.org\nexit\n') print(output.decode('utf-8')) print('Exit code:', p.returncode)

進程間通信:

Process之間肯定是需要通信的,操作系統(tǒng)提供了很多機制來實現(xiàn)進程間的通信奸腺。Python的multiprocessing模塊包裝了底層的機制餐禁,提供了Queue、Pipes等多種方式來交換數(shù)據(jù)洋机。

#!/usr/bin/env python3 # -*- coding: utf-8 -*-? from multiprocessing import Process, Queue import os, time, random? # 寫數(shù)據(jù)進程執(zhí)行的代碼: def write(q):? print('寫入write進程 : %s ' % os.getpid()) #寫入到隊列的進程? for vlaue in ['A', 'B', 'C']:? print('傳入 %s to 隊列(queue)' % vlaue)? q.put(vlaue) #調(diào)用put方法寫入? time.sleep(random.random())? #去讀數(shù)據(jù)進程執(zhí)行的代碼 def read(q):? print('讀取read進程 : %s ' % os.getpid())? while True:? vlaue = q.get(True)? print('獲取get %s 來自隊列' % vlaue)? if __name__=='__main__':? # 父進程創(chuàng)建Queue坠宴,并且傳給給個子進程:? q = Queue()? pw = Process(target=write, args=(q,))? pr = Process(target=read, args=(q,))? #啟動子進程pw,寫入:? pw.start()? #啟動子進程pr绷旗,讀取:? pr.start()? #等待PW結(jié)束:? pw.join()? #pr讀取進程是死循環(huán)副砍,無法等待其結(jié)束衔肢,職能強行終止:? pr.terminate()

運行結(jié)果:

在Unix/Linux下,multiprocessing模塊封裝了fork()調(diào)用豁翎,使我們不需要關(guān)注fork()的細節(jié)角骤。由于Windows沒有fork調(diào)用,因此,multiprocessing需要“模擬”出fork的效果邦尊,父進程所有Python對象都必須通過pickle序列化再傳到子進程去背桐,所以,如果multiprocessing在Windows下調(diào)用失敗了蝉揍,要先考慮是不是pickle失敗了链峭。

小結(jié)

在Unix/Linux下,可以使用fork()調(diào)用實現(xiàn)多進程又沾。

要實現(xiàn)跨平臺的多進程弊仪,可以使用multiprocessing模塊。

進程間通信是通過Queue杖刷、Pipes等實現(xiàn)的励饵。

多線程:Thread

Python的標(biāo)準(zhǔn)庫提供了兩個模塊:_thread和threading,_thread是低級模塊滑燃,threading是高級模塊役听,對_thread進行了封裝。絕大多數(shù)情況下表窘,我們只需要使用threading這個高級模塊禾嫉。

#!/usr/bin/env python3 # -*- coding: utf-8 -*-? import time, threading? #新線程執(zhí)行代碼 def loop():? print('thread is %s runing' % threading.current_thread().name) #打印當(dāng)前主的線程名字? n = 0? while n < 5:? n = n + 1? print('thread %s >> %s' % (threading.current_thread().name,n))#獲取每次的線程? time.sleep(1)? print('thread %s is end ' % threading.current_thread().name)? print('thread %s is runing ..' % threading.current_thread().name) t = threading.Thread(target = loop, name = 'LoopThread') t.start() t.join() print('thread %s ended' % threading.current_thread().name)#打印結(jié)束當(dāng)前主的線程名字

由于任何進程默認(rèn)就會啟動一個線程,我們把該線程稱為主線程蚊丐,主線程又可以啟動新的線程熙参,Python的threading模塊有個current_thread()函數(shù),它永遠返回當(dāng)前線程的實例麦备。主線程實例的名字叫MainThread孽椰,子線程的名字在創(chuàng)建時指定,我們用LoopThread命名子線程凛篙。名字僅僅在打印時用來顯示黍匾,完全沒有其他意義,如果不起名字Python就自動給線程命名為Thread-1呛梆,Thread-2……

Lock

當(dāng)多個線程同時執(zhí)行l(wèi)ock.acquire()時锐涯,只有一個線程能成功地獲取鎖,然后繼續(xù)執(zhí)行代碼填物,其他線程就繼續(xù)等待直到獲得鎖為止纹腌。

balance = 0 lock = threading.Lock()? def run_thread(n):? ? for i in range(100000):? ? ? ? # 先要獲取鎖:? ? ? ? lock.acquire()? ? ? ? try:? ? ? ? ? ? # 放心地改吧:? ? ? ? ? ? change_it(n)? ? ? ? finally:? ? ? ? ? ? # 改完了一定要釋放鎖:? ? ? ? ? ? lock.release()

ThreadLocal:

在多線程環(huán)境下,每個線程都有自己的數(shù)據(jù)滞磺。一個線程使用自己的局部變量比使用全局變量好升薯,因為局部變量只有線程自己能看見,不會影響其他線程击困,而全局變量的修改必須加鎖涎劈。

#!/usr/bin/env python3 # -*- coding: utf-8 -*-? import threading? #創(chuàng)建全局的threadloacl對象: local_school = threading.local()? def process_student():? #獲取當(dāng)前現(xiàn)場的關(guān)聯(lián)的student? std = local_school.student? print('hello , %s (in %s )' % (std, threading.current_thread().name))? def process_thread(name):? #綁定threadlocal的student? local_school.student = name? process_student()? t1 = threading.Thread(target = process_thread, args = ('alice', ),name = 'Thread-A') t2 = threading.Thread(target = process_thread, args = ('BOb',),name = 'Thread-B') t1.start() t2.start() t1.join() t2.join()

不同的線程綁定自己線程

全局變量local_school就是一個ThreadLocal對象,每個Thread對它都可以讀寫student屬性,但互不影響蛛枚。你可以把local_school看成全局變量谅海,但每個屬性如local_school.student都是線程的局部變量,可以任意讀寫而互不干擾蹦浦,也不用管理鎖的問題扭吁,ThreadLocal內(nèi)部會處理。

可以理解為全局變量local_school是一個dict白筹,不但可以用local_school.student智末,還可以綁定其他變量,如local_school.teacher等等徒河。

ThreadLocal最常用的地方就是為每個線程綁定一個數(shù)據(jù)庫連接系馆,HTTP請求,用戶身份信息等顽照,這樣一個線程的所有調(diào)用到的處理函數(shù)都可以非常方便地訪問這些資源由蘑。

小結(jié):

一個ThreadLocal變量雖然是全局變量,但每個線程都只能讀寫自己線程的獨立副本代兵,互不干擾尼酿。ThreadLocal解決了參數(shù)在一個線程中各個函數(shù)之間互相傳遞的問題。

正則表達式:

表1.常用的元字符

代碼

說明

.

匹配除換行符以外的任意字符

\w

匹配字母或數(shù)字或下劃線或漢字

\s

匹配任意的空白符

\d

匹配數(shù)字

\b

匹配單詞的開始或結(jié)束

^

匹配字符串的開始

$

匹配字符串的結(jié)束

例子:

\d{3}表示匹配3個數(shù)字植影,例如'010'裳擎;

\s可以匹配一個空格(也包括Tab等空白符),所以\s+表示至少有一個空格思币,例如匹配' '鹿响,' '等;

\d{3,8}表示3-8個數(shù)字谷饿,例如'1234567'惶我。

進階

要做更精確地匹配,可以用[]表示范圍博投,比如:

[0-9a-zA-Z\_]可以匹配一個數(shù)字绸贡、字母或者下劃線;

[0-9a-zA-Z\_]+可以匹配至少由一個數(shù)字毅哗、字母或者下劃線組成的字符串听怕,比如'a100','0_Z'黎做,'Py3000'等等叉跛;

[a-zA-Z\_][0-9a-zA-Z\_]*可以匹配由字母或下劃線開頭,后接任意個由一個數(shù)字蒸殿、字母或者下劃線組成的字符串,也就是Python合法的變量;

[a-zA-Z\_][0-9a-zA-Z\_]{0, 19}更精確地限制了變量的長度是1-20個字符(前面1個字符+后面最多19個字符)宏所。

A|B可以匹配A或B酥艳,所以(P|p)ython可以匹配'Python'或者'python'。

^表示行的開頭爬骤,^\d表示必須以數(shù)字開頭充石。

$表示行的結(jié)束,\d$表示必須以數(shù)字結(jié)束霞玄。

你可能注意到了骤铃,py也可以匹配'python',但是加上^py$就變成了整行匹配坷剧,就只能匹配'py'了惰爬。

re模塊:

Python 里的 re.match() 方法

match()方法判斷是否匹配,如果匹配成功惫企,返回一個Match對象撕瞧,否則返回None。常見的判斷方法就是:

test = '用戶輸入的字符串' if re.match(r'正則表達式', test):? ? print('ok') else:? ? print('failed')

表2.常用的限定符

重復(fù)

代碼/語法

說明

*

重復(fù)零次或更多次

+

重復(fù)一次或更多次

狞尔?

重復(fù)零次或一次

{n}

重復(fù)n次

{n,}

重復(fù)n次或更多次

{n,m}

重復(fù)n到m次

分組:

除了簡單地判斷是否匹配之外丛版,正則表達式還有提取子串的強大功能。用()表示的就是要提取的分組(Group)偏序。比如:

^(\d{3})-(\d{3,8})$分別定義了兩個組页畦,可以直接從匹配的字符串中提取出區(qū)號和本地號碼:

>>> import re >>> m = re.match(r'^(\d{3})-(\d{3,8})$', '010-12345') >>> m.group(0) '010-12345' >>> m.group(1) '010' >>> m.group(2) '12345'

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市研儒,隨后出現(xiàn)的幾起案子豫缨,更是在濱河造成了極大的恐慌,老刑警劉巖殉摔,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件州胳,死亡現(xiàn)場離奇詭異,居然都是意外死亡逸月,警方通過查閱死者的電腦和手機栓撞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來碗硬,“玉大人瓤湘,你說我怎么就攤上這事《魑玻” “怎么了弛说?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長翰意。 經(jīng)常有香客問我木人,道長信柿,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任醒第,我火速辦了婚禮渔嚷,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘稠曼。我一直安慰自己形病,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布霞幅。 她就那樣靜靜地躺著漠吻,像睡著了一般。 火紅的嫁衣襯著肌膚如雪司恳。 梳的紋絲不亂的頭發(fā)上途乃,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天,我揣著相機與錄音抵赢,去河邊找鬼欺劳。 笑死,一個胖子當(dāng)著我的面吹牛铅鲤,可吹牛的內(nèi)容都是我干的划提。 我是一名探鬼主播,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼邢享,長吁一口氣:“原來是場噩夢啊……” “哼鹏往!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起骇塘,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤伊履,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后款违,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體唐瀑,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年插爹,在試婚紗的時候發(fā)現(xiàn)自己被綠了哄辣。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡赠尾,死狀恐怖力穗,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情气嫁,我是刑警寧澤当窗,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站寸宵,受9級特大地震影響崖面,放射性物質(zhì)發(fā)生泄漏元咙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一嘶朱、第九天 我趴在偏房一處隱蔽的房頂上張望蛾坯。 院中可真熱鬧光酣,春花似錦疏遏、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至唱遭,卻和暖如春戳寸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背拷泽。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工疫鹊, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人司致。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓拆吆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親脂矫。 傳聞我的和親對象是個殘疾皇子枣耀,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 寫在前面的話 代碼中的# > 表示的是輸出結(jié)果 輸入 使用input()函數(shù) 用法 注意input函數(shù)輸出的均是字...
    FlyingLittlePG閱讀 2,743評論 0 8
  • 線程 操作系統(tǒng)線程理論 線程概念的引入背景 進程 之前我們已經(jīng)了解了操作系統(tǒng)中進程的概念捞奕,程序并不能單獨運行,只有...
    go以恒閱讀 1,635評論 0 6
  • 多進程 要讓python程序?qū)崿F(xiàn)多進程拄轻,我們先了解操作系統(tǒng)的相關(guān)知識颅围。 Unix、Linux操作系統(tǒng)提供了一個fo...
    蓓蓓的萬能男友閱讀 593評論 0 1
  • 基礎(chǔ)1.r''表示''內(nèi)部的字符串默認(rèn)不轉(zhuǎn)義2.'''...'''表示多行內(nèi)容3. 布爾值:True恨搓、False(...
    neo已經(jīng)被使用閱讀 1,663評論 0 5
  • 高階函數(shù):將函數(shù)作為參數(shù) sortted()它還可以接收一個key函數(shù)來實現(xiàn)自定義的排序,reversec參數(shù)可反...
    royal_47a2閱讀 680評論 0 0