從零開始的異世界python全棧

吾生也有涯,而知也無涯彩扔。以有涯隨無涯妆档,殆已!已而為知者虫碉,殆而已矣贾惦!

1994年4月20日,中國第一根64K國際專線接入國際互聯(lián)網敦捧,說“想要世界的寶藏么须板?如果想要的話,那就去網上找吧兢卵,我把所有的一切都放在那里习瑰。”于是济蝉,水木清華杰刽、搜狐菠发、網易,等等贺嫂、等等滓鸠,掀起了中國互聯(lián)網的熱潮,大互聯(lián)網時代就此展開第喳。
我的上一篇文章How to build?寫于三月之前糜俗,介紹如何零基礎開始學習PYTHON,那時候我入職兩月曲饱,現(xiàn)在還差一月轉為正式員工悠抹,值此機會,從技術角度剖析一下助理PYTHON工程師的工作扩淀,也讓這篇文章作為入門者的技術指南楔敌,如果你能在每一項技術能力前面打勾,你一定是一名成熟的python web工程師驻谆!

工作范疇

  • 具備將產品經理的產品理念快速卵凑、有效的轉化為產品價值的全部技術能力
  • 對于產品的生命周期有一定認識,并能夠因此來控制自己代碼的復雜性
  • 有開放式工作環(huán)境的素質意識胜臊,具備持續(xù)“學習”的學習能力

工作1:技術能力


1.1 基本能力

軟件工程勺卢,是個很有意思的名字。十八世紀象对,歐洲創(chuàng)造了“工程”一次黑忱,本來含義是有關兵器制造、具有軍事目的的各項勞作勒魔,后擴展到許多領域甫煞,如建筑屋宇、制造機器沥邻、架橋修路等危虱。軟件·工程并無二致,甚至不需要車床吊車等物理硬件唐全,只要會想(敢于類比與聯(lián)想埃跷,讀史使人明智)、會寫(運用編輯器輸入代碼邮利,vim是不錯的選擇)弥雹、會問(靈活的使用Google,科學上網)延届、會生活(與同事搞好關系剪勿,辦公室至少9小時呢)。

當一個程序員方庭,不僅僅是實現(xiàn)功能代碼厕吉,還要有一點美感酱固,就像建房子。如果封裝不優(yōu)雅头朱,房子外表很難看运悲;如果接口不優(yōu)雅,房門都很難進项钮;如果抽象層不優(yōu)雅班眯,房子根本沒法裝修。有一點對“美感”的追求烁巫,對工程的敬畏之心署隘,就像電鋸驚魂中的工程工具(殺人的美學),會讓我們的工作事半功倍亚隙。


1.2 運維能力

說到運維磁餐,就是一種管理的能力,管理計算機系統(tǒng)恃鞋,管理數據庫崖媚,管理應用配置,讓一切都流程化恤浪、標準化并自動化。

  • 計算系統(tǒng)肴楷∷桑基于kubernetes寫dockerfile,基于成熟的docker系統(tǒng)創(chuàng)建赛蔫、銷毀容器砂客。DOCKER讓系統(tǒng)自動化
    任何系統(tǒng)問題都能用“重啟”的方式解決,如果不行呵恢,那就重啟兩次鞠值。云是大勢,所以只要我們能弄出最基本的系統(tǒng)image渗钉,比如macOS彤恶、阿里云,那么作為程序員的我們就能夠一展身手鳄橘。
    當然声离,理解操作系統(tǒng)是很有必要的,不要浪費或過度使用機器性能瘫怜,注重sql語句的優(yōu)化术徊,進程的使用
  • 數據庫。DBA讓數據庫自動化
  • 應用配置鲸湃。CMDB讓應用自動化
  • 生產環(huán)境赠涮。我們要學會利用以上子寓,必要時候開發(fā)以上,學會起docker笋除,學會和DBA溝通别瞭,學會起CMDB,以及學會管理自己的生產環(huán)境株憾!
    • 基本cmd命令蝙寨,比如yum,mkdir嗤瞎,touch墙歪,cd,rm贝奇,>虹菲,grep,ps掉瞳,top毕源,w,nohup陕习,set霎褐,crontab等等;
    • 基本編輯器vim该镣,會配置使用vim(用vundle來管理插件)冻璃,或者基本ide atom;
    • 基本解釋器损合,python環(huán)境管理pipenv省艳,pipenv installpipenv shell嫁审;
    • 基本代碼管理git跋炕,pull,push律适,checkout辐烂,rebase
    • 基本數據庫管理,mongo擦耀,mysql, els的啟用棉圈,migrate,export眷蜓,import
    • 基本業(yè)務管理分瘾,能夠預估開發(fā)feature的時間,能夠管理開發(fā)的輕重緩急,能夠對業(yè)務細節(jié)反復推敲
    • 基本個人管理德召,能夠健康白魂,能夠“有愛”

就個人或小組開發(fā)而言,掌握以上應該能讓你非常舒服地做一個開發(fā)工程師上岗,所謂工欲善其事福荸,必先利其器。


1.3 PYTHON能力

說到PYTHON肴掷,很多人都會寫敬锐,語言很簡單,但工程師之間工資又各有不同呆瞻,這是為什么呢台夺?為了回答這個問題,不妨上拉勾網搜索了一下“金主”們對工程師的要求痴脾。
搜索詞為'python'颤介,篩選為工資‘25k-50k’以及‘50k以上’,我隨機選取了第一頁的兩個公司

初級玩家

中級玩家

可是看出,對于‘初級玩家’公司主要看你“會不會”赞赖,也就是0和1的區(qū)別滚朵;而對于‘中級玩家’公司主要看中你“會不會分析,能不能優(yōu)化”前域,也就是1和10的區(qū)別辕近;至于‘高級玩家’,我想只會PYTHON是不行的话侄。那么我的這篇文章亏推,一方面總結一下我半年的學習成果,希望能夠把知識從0到1真正落到實處年堆,便于以后從1到10不斷進步;另一方面盏浇,借著分享交流的互聯(lián)網变丧,希望各位同行能夠指出我工作學習中的短板,幫助我不斷改進绢掰。

1.3.1 Clean Code

我在上篇文章中推薦在HackerRank做完全部python習題痒蓬,并且在LeetCode上繼續(xù)訓練。不斷刷題能極大的增強我們寫單個函數滴劲、算法的能力攻晒,訓練我們的思維能力,但對我們寫"工程項目"卻鮮有幫助班挖。因為每一題的context都不一樣鲁捏,容易養(yǎng)成重復造輪子、代碼不整潔的壞習慣萧芙,在我入職的第一個月给梅,因為壞習慣被反復批評假丧,之后我仔細讀了《Clean Code》一書,情況有所好轉动羽。所以包帚,請務必注意代碼的測試、抽象層运吓、命名規(guī)范渴邦、參數、Exception等拘哨。
訓練方法:《Clean Code》谋梭,要有好代碼的smell
訓練成果:厲害的程序員寫出機器能讀懂的代碼,好的程序員寫出人能讀懂的代碼宅静。

# 保齡球積分章蚣,從第0輪到第10輪,已知每一輪的擊倒情況姨夹,求總分
def score_frame(frame=10):
    score = 0
    ordinal_ball = 0
    for current_frame in range(frame):
        if is_strike(ordinal_ball):
            score += 10 + next_two_balls_for_strike()
            ordinal_ball += 1
        elif is_spare(ordinal_ball):
            score += 10 + next_ball_for_spare()
            ordinal_ball += 2
        else:
            score += two_balls_in_frame()
            ordinal_ball += 2
    return score
Clean code is simple and direct. Clean code reads like well-written prose. Clean code never obscures the designer’s intent but rather is full of crisp abstractions and straightforward lines of control.
1.3.2 Flask

整潔代碼是基礎中的基礎纤垂,接下來掌握的是web框架。要想熟練使用Flask磷账,知識上要求對網絡會話層峭沦、表示層和應用層有了解,從Client端輸入URI并發(fā)送請求的一瞬間逃糟,網絡通過自上而下的OSI結構吼鱼,傳輸層(TCP)--- 網絡層(IP) --- 數據鏈路層 --- 物理層, 路由(識別IP)绰咽,然后菇肃,Server端與之建立TCP連接,拿到request對象取募,梳理業(yè)務邏輯琐谤,返回response對象,經過同樣的一系列過程到Client端接受數據(如果是瀏覽器則會渲染頁面)玩敏。這背后所有的事情斗忌,就是一個web工程師的工作所在。
訓練方法:《Flask Web開發(fā)旺聚,基于python的web開發(fā)實戰(zhàn)》织阳,上篇文章已經推薦過了
訓練成果:能夠獨立編寫并部署一個滿足業(yè)務需求的web應用


FLASK框架可以簡單至此,但面對更大的需求砰粹,還望多思量唧躲。
from flask import Flask, request, jsonify
from models import get_question_analysis

app = Flask(__name__)

@app.route('/', methods=['GET'])
def index():
    return 'hello world'

@app.route('/api', methods=['POST'])
def api():
    data = request.get_json()
    question = data['question']
    question_analysis = get_question_analysis(question)
    return jsonify(question_analysis)

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=False)
1.3.3 AioHttp

一步通,則步步通,能夠學會一個框架惊窖,其他的框架就不難了刽宪。Flask的底層是werkzeuk,基于CGI(通用網關接口界酒,Common Gateway Interface)的WSGI在業(yè)務受到了異步的挑戰(zhàn)圣拄,ASGI應運而生。AioHttp的框架毁欣,支持python asycio庇谆,能極大的提高API的性能(與flask框架下API性能的差異,請移步我的測試文章)凭疮。
訓練方法:AioHttp Git饭耳,Asyncio Doc,永遠不要忘記源碼和doc
訓練成果:能夠獨立編寫并部署一個滿足業(yè)務需求的web應用执解,理解并掌握python的異步語法

from aiohttp import web
from models import get_question_analysis

async def index(request):
    return web.Response(text='Hello World')

async def api(request):
    data = await request.json()
    question = data['question']
    question_analysis = await get_question_analysis(question)
    return web.json_response(question_analysis)

app = web.Application()
app.add_routes([web.get('/', index),
                web.post('/api', api)])

if __name__ == '__main__':
    web.run_app(app, host='0.0.0.0', port=5000)

Parallelism introduces new challenges in writing correct code, particularly in the presence of shared, mutable state.

1.3.4 MONGO

對于一個助理工程師寞肖,不懂框架,你也能形成生產力衰腌,可以做一個寫數據庫增刪改查的cool boy新蟆。如果一個工程師不會操作數據庫,那就連“刪庫跑路”的“黑暗森林威懾”都建立不起來...所以無論怎樣右蕊,這個得會琼稻。我們有兩種操作mongodb的方式,一種是ODM(Object-Document Mapper)饶囚,如mongoengine帕翻;另一種則是超有名的pymongo。
訓練方法:MongoEngine文檔萝风,PyMongo文檔
訓練成果:熟練對mongo表進行增刪改查嘀掸,能夠對mongo表查詢進行一定程度的優(yōu)化

# 更改user_info這張表中的user_id為‘test’的年齡為22
# mongoengine
from mongoengine import Document, connect
from config import MONGO_URI

connect(host=MONGO_URI, alias='default')

class UserInfo(Document):
    user_id = StringField(required=True)
    age = IntField()

UserInfo.objects.get(user_id='test').update(age=22)


# pymongo
from config import MONGO_URI, DB
from pymongo import MongoClient

client = MongoClient(MONGO_URI)
collection = client[DB]['user_info']

collection.update({'user_id': 'test'}, {'age': 22})

簡單分析一下二者的優(yōu)缺點:

  • mongoengine允許我們定義一套模式,然后把所有的值都匹配到我們定義的schema上规惰,這種schema更加清楚和明確横殴,個人感覺比字典更容易操作,用dot notation更像OOP卿拴,而pymong返回的是一個dict,操作時困難的多梨与,很多時候有點丑
  • mongoengine相當于在你和pymongo之間加了map層堕花,所以會對性能有微乎其微的影響,在進行很簡單的查詢時顯得有些沒有必要
1.3.5 MYSQL

noSQL和SQL的取舍總是要不斷斟酌粥鞋。操作mysql我們也有兩種方式缘挽,ORM的sqlalchemy,以及pymysql
訓練方法:SqlAlchemy文檔,PyMySql文檔
訓練成果:熟練對mysql表進行增刪改查壕曼,能夠對mysql表查詢進行一定程度的優(yōu)化

# 向user_info這張表中存入一條姓名為‘test’苏研,年齡為22的數據
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from config import MYSQL_URI

Base = declarative_base()
engine = create_engine(MYSQL_URI, echo=False)
Session = sessionmaker(bind=engine)
session = Session()

class UserInfo(Base):
    __tablename__ = 'user_info'
    user_id = Column(String(80), nullable=False)
    age = Column(Integer(), nullable=True)

session.add(UserInfo('test', 22))
session.commit()

ORM的用途非常非常廣,使用起來很優(yōu)雅腮郊,但如同flask框架一般摹蘑,深入探究它的使用方法和場景需要大量的篇幅,會在以后的文章中繼續(xù)分享轧飞,希望感興趣的同學自行探索衅鹿,也可以在評論區(qū)有更多交流。

1.3.6 Abstraction

Computer programs consist of instructions to either: Compute some value Or Carry out some action

有了框架和數據庫过咬,剩下的就是“操作”了大渤,也就是業(yè)務邏輯的編寫。如果使用命令式編程掸绞,實現(xiàn)業(yè)務不是一件困難的事情泵三,那么代碼的區(qū)別就彰顯了工程師們的抽象水平。百多行的函數衔掸;沒有層次感的代碼烫幕;命名不規(guī)范的代碼;概率編程具篇;google編程纬霞,等等,不一而足驱显。優(yōu)秀的工程師诗芜,對抽象一定有自己的理解!
訓練方法:多想埃疫,多看
訓練成果:至少能夠從“只看到了”函數伏恐,到“看到了”項目,從細節(jié)到系統(tǒng)

# 表示有理數栓霜,并計算其平方
# 表示方法
def rational(n, d):
    return [n, d]

def numerator(x):
    return x[0]

def denominator(x):
    return x[1]

# 操作方法
def square_rational(x):
    return mul_rational(x, x)

def square_rational_violation_once(x):
    return rational(numerator(x) * numerator(x), denominator(x) * denominator(x))

def square_rational_violation_twice(x):
    return [x[0] * x[0], x[1] * x[1]]

# 表示方法 2
def rational(n, d):
    def get(index):
        if index == 0:
            return n
        elif index == 1:
            return d
    return get

def numerator(x):
    return x(0)

def denominator(x):
    return x(1)
Isolate the parts of a program that deal with how data are represendted from the parts that deal with how data are manipulated

用了一個簡單的例子來解釋表示層和操作層(完全不一樣的表示層翠桦,但是操作層卻完全一樣),龐大的系統(tǒng)必然存在著細小的抽象胳蛮。我們只要能夠掌握抽象的方法销凑,再配合leetcode中的算法知識,那么所有的業(yè)務邏輯必然迎刃而解仅炊。

1.3.7 lib/site-packages

框架 -> 數據庫 -> 抽象斗幼,我把技術內容分成了這三塊,那其實還有一些邊角料抚垄。python為人稱道的就是大量好用的包蜕窿,所以python工程師經常被說成調包的谋逻。在工作中當然也會直接調包,比如smtp和beautifulsoup桐经,這兩個太常見了毁兆。

import requests
from bs4 import BeautifulSoup

url_head = 'http://www.reibang.com/u/1f167239855b'
HTML = requests.get(url_head).text
soup = BeautifulSoup(HTML, 'lxml')
soup.find_all()
1.3.8 widgets

最后的最后,在項目開發(fā)的過程中阴挣,一定會和公司業(yè)務有聯(lián)系气堕,也一定會發(fā)生很多bug,更會有一些奇奇怪怪的需求屯吊。為了應對各種各樣的事情送巡,python工程師集成了大量好用的工具,比如elastic-search盒卸,sentry骗爆,kafka, memcache等等蔽介,這種Client/Server的構架很好用摘投,也是微服務的雛形。


The client/server model is appropriate for service-oriented situations.
1.3.9 behave && selenium

OK虹蓄,做完所有工作犀呼,臨近上線,我的PM一定會在旁邊大喊三聲:測試薇组!測試外臂!測試!自動化測試是所有穩(wěn)定系統(tǒng)的標配律胀,unittests和doc tests不必多提宋光,這里介紹一種BDD工具,behave和selenium炭菌。

功能: 自動測試
    場景: 頁面點擊
        假如 我在登陸頁面
        當 輸入賬號罪佳、密碼并點擊登陸
        那么 我在個人主頁

from behave import given, when, then
from selenium import webdiver

driver = webdrivear.Chrome(driver_path, chrome_options=chrome_options)

@given('我在登陸頁面')
def login_in(context):
    driver.get(login_url)
    assert is_at_page(LOGIN_PAGE)

@when('輸入賬號、密碼并點擊登陸')
def send_key(context):
    driver.find_element_by_id(ACCOUNT).send_keys(KEYS)
    dirver.find_element_by_id(CONFIRM).click()

@then('我在個人主頁')
    assert is_at_page(HOME_PAGE)

如果你覺得測試沒有必要黑低,那你一定沒有寫過測試赘艳!

1.3.10 CI && CD

OK,順利通過測試克握,合并到master蕾管,此時應該有一套能夠自動集成、自動部署的機制菩暗,用python起一個監(jiān)控master分支的服務娇掏,一出現(xiàn)合并操作,就使用ssh協(xié)議重啟原服務勋眯。

至此婴梧,整套python web開發(fā)后端流程的技術要點都清晰了,希望以后能夠繼續(xù)成長客蹋、分享塞蹭,也希望閱讀到這里的伙伴多多交流、給予指導讶坯。


1.4 前端能力

互聯(lián)網行業(yè)注重T型人才的培養(yǎng)番电,所謂的T型人才就是橫向了解,縱向發(fā)展辆琅,所以web開發(fā)往往看重全棧的能力漱办。

  • HTML。標記性語言婉烟,就用jinja模版吧娩井。
{% import "bootstrap/wtf.html" as wtf %}
{{ wtf.quick_form(form) }}
  • CSS。樣式語言似袁,就用bootstrap吧洞辣。
    {% extends 'bootstrap/base.html %}

  • JS。動態(tài)交互昙衅,就用ajax吧扬霜。

$("#botton").on("click",function(){
    $.ajax({
            url: 'http://www.baidu.com',
            type: 'GET',
            success: function(data){
            };
        })
    })

如果你不滿足于如此簡單的前端知識,也可以主動將vue框架融合到我們的頁面中而涉。前端語言還是有很多奇技淫巧著瓶,好看的頁面比后端開發(fā)更容易獲得成就感。


1.5 數據能力
All models are wrong, some are useful.

但凡python工程師啼县,大都會一點數據分析材原。那我感覺呢,有數據比沒數據強谭羔,用數據驅動的PM比只有PM驅動靠譜华糖。

  • 數據提取。
    1. 從雜亂的打點數據中瘟裸,用技術取出結構化的數據
  • 數據分析和挖掘客叉。
    1. 可以用random forest分析feature
    2. 可以用OLS直接預測模型
    3. 還有一些教育上的模型如BKT,IRT
  • 數據驅動话告。
    1. 可視化模型結果兼搏,并寫分析報告
  • 數據理解
    • 以上所有技術都可以很快學會,無外乎調包調參沙郭,但理解和分析才是重點
    • 在不能獨立佛呻、全方面分析問題時,建議先養(yǎng)成科學的思維習慣(不要連貝葉斯都沒搞明白就妄圖進軍數據分析...)

工作2:架構能力

我經驗較少病线,這部分的理解還需要不斷加強吓著,所言也不過拾人牙慧鲤嫡,暫且一放(代碼的經驗、不一樣的設計模式绑莺、業(yè)務生命周期的理解能力)


工作3:學習能力

  • Junior Programmer暖眼,想從碼農成長為工程師,要進步纺裁!
  • 工作中有很多可以學習的點诫肠,優(yōu)化一段代碼、發(fā)布一個發(fā)送郵件的package欺缘、上coursera課程栋豫,要學習!
  • 學習和工作是很辛苦的谚殊,寫了一天代碼頭昏腦脹丧鸯,還要再看兩個小時英文文檔,要勇敢络凿!

終于在周一發(fā)版了骡送,本來告訴自己每周日要發(fā)布一篇文章的,最近熬夜看TI絮记,時間和精力完全跟不上摔踱。算是全面總結了工作中的一些事情吧,比較基礎怨愤,深入鉆研也有些東西派敷,嗯,共勉撰洗,加油篮愉!

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市差导,隨后出現(xiàn)的幾起案子试躏,更是在濱河造成了極大的恐慌,老刑警劉巖设褐,帶你破解...
    沈念sama閱讀 211,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件颠蕴,死亡現(xiàn)場離奇詭異咐熙,居然都是意外死亡摊腋,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評論 3 385
  • 文/潘曉璐 我一進店門贱除,熙熙樓的掌柜王于貴愁眉苦臉地迎上來外冀,“玉大人寡键,你說我怎么就攤上這事⊙┧恚” “怎么了西轩?”我有些...
    開封第一講書人閱讀 157,435評論 0 348
  • 文/不壞的土叔 我叫張陵员舵,是天一觀的道長。 經常有香客問我遭商,道長固灵,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,509評論 1 284
  • 正文 為了忘掉前任劫流,我火速辦了婚禮,結果婚禮上丛忆,老公的妹妹穿的比我還像新娘祠汇。我一直安慰自己,他們只是感情好熄诡,可當我...
    茶點故事閱讀 65,611評論 6 386
  • 文/花漫 我一把揭開白布可很。 她就那樣靜靜地躺著,像睡著了一般凰浮。 火紅的嫁衣襯著肌膚如雪我抠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,837評論 1 290
  • 那天袜茧,我揣著相機與錄音菜拓,去河邊找鬼。 笑死笛厦,一個胖子當著我的面吹牛纳鼎,可吹牛的內容都是我干的。 我是一名探鬼主播裳凸,決...
    沈念sama閱讀 38,987評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼贱鄙,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了姨谷?” 一聲冷哼從身側響起逗宁,我...
    開封第一講書人閱讀 37,730評論 0 267
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎梦湘,沒想到半個月后瞎颗,有當地人在樹林里發(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 44,194評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡践叠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,525評論 2 327
  • 正文 我和宋清朗相戀三年言缤,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片禁灼。...
    茶點故事閱讀 38,664評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡管挟,死狀恐怖,靈堂內的尸體忽然破棺而出弄捕,到底是詐尸還是另有隱情僻孝,我是刑警寧澤导帝,帶...
    沈念sama閱讀 34,334評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站穿铆,受9級特大地震影響您单,放射性物質發(fā)生泄漏。R本人自食惡果不足惜荞雏,卻給世界環(huán)境...
    茶點故事閱讀 39,944評論 3 313
  • 文/蒙蒙 一虐秦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧凤优,春花似錦悦陋、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,764評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至棍辕,卻和暖如春暮现,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背楚昭。 一陣腳步聲響...
    開封第一講書人閱讀 31,997評論 1 266
  • 我被黑心中介騙來泰國打工栖袋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人哪替。 一個月前我還...
    沈念sama閱讀 46,389評論 2 360
  • 正文 我出身青樓栋荸,卻偏偏與公主長得像,于是被迫代替她去往敵國和親凭舶。 傳聞我的和親對象是個殘疾皇子晌块,可洞房花燭夜當晚...
    茶點故事閱讀 43,554評論 2 349

推薦閱讀更多精彩內容