python之回調(diào)函數(shù)和裝飾函數(shù)

一.回調(diào)函數(shù)

1.回調(diào)函數(shù)的概念: 是在某一函數(shù)中調(diào)用另一個(gè)函數(shù)變量方式,來執(zhí)行函數(shù).回調(diào)函數(shù)不是有實(shí)現(xiàn)方調(diào)用,應(yīng)該在特定的的時(shí)間或事件下,由另一個(gè)函數(shù)調(diào)用的,用于對(duì)某一事件或條件的響應(yīng).
2.什么事回調(diào)
軟件模塊之間總是存在著一定的接口,從調(diào)用方式上,可以把他們分為三類: 同步調(diào)用春贸、回調(diào)和異步調(diào)用迈嘹。

  • 同步調(diào)用是一種阻塞式調(diào)用钧舌,調(diào)用方要等待對(duì)方執(zhí)行完畢才返回,它是一種單向調(diào)用歉糜;
  • 回調(diào)是一種雙向調(diào)用模式,也就是說苫纤,被調(diào)用方在接口被調(diào)用時(shí)也會(huì)調(diào)用對(duì)方的接口叠赦;
  • 異步調(diào)用是一種類似消息或事件的機(jī)制,不過它的調(diào)用方向剛好相反牲蜀,接口的服務(wù)在收到某種訊息或發(fā)生某種事件時(shí)笆制,會(huì)主動(dòng)通知客戶方(即調(diào)用客戶方的接口.

回調(diào)和異步調(diào)用的關(guān)系非常緊密,通常我們使用回調(diào)來實(shí)現(xiàn)異步消息的注冊(cè)涣达,通過異步調(diào)用來實(shí)現(xiàn)消息的通知在辆。同步調(diào)用是三者當(dāng)中最簡(jiǎn)單的,而回調(diào)又常常是異步調(diào)用的基礎(chǔ)度苔,因此开缎,下面我們著重討論回調(diào)機(jī)制在不同軟件架構(gòu)中的實(shí)現(xiàn)回調(diào)和異步調(diào)用的關(guān)系非常緊密,通常我們使用回調(diào)來實(shí)現(xiàn)異步消息的注冊(cè)林螃,通過異步調(diào)用來實(shí)現(xiàn)消息的通知。同步調(diào)用是三者當(dāng)中最簡(jiǎn)單的俺泣,而回調(diào)又常常是異步調(diào)用的基礎(chǔ)疗认,因此,下面我們著重討論回調(diào)機(jī)制在不同軟件架構(gòu)中的實(shí)現(xiàn).
3.簡(jiǎn)單的案例
案例一

import random as rd

    # -----------被調(diào)用方----------------------------
    def newRN(fn):  # 生成10個(gè)[0,1)之間小數(shù)
        ns = []
        for i in range(10):
            n = round(rd.random(), 2)
        ns.append(n)

        # 不用直接 return, 因?yàn)檎{(diào)用方 通知不接返回結(jié)果
        # 改成回調(diào)函數(shù)方式
        fn(ns)  # 調(diào)用是調(diào)用方函數(shù)伏钠,這一操作稱之為回調(diào)

    # ----------------調(diào)用方------------------------

    # 定義回調(diào)函數(shù)
    def abc(*args):
        # 進(jìn)入到本函數(shù)內(nèi)横漏,意味著被調(diào)用方函數(shù)已執(zhí)行完
        print('生成數(shù)據(jù)成功')
        print(args)

    newRN(abc)   

案例二

import  random as rd
import time

def test(fn, n):
        """
        測(cè)試生成 n 個(gè)隨機(jī)數(shù)需要的時(shí)間(秒)
        :param fn:  回調(diào)函數(shù)
        :param n:  生成的數(shù)量
        :return:
        """
        start_time = time.time()  # 開始時(shí)間

        for i in range(n):
            rd.random()
            time.sleep(0.1)  # 讓CPU休眠0.1秒

            end_time = time.time()  # 循環(huán)結(jié)束的時(shí)間
            seconds = round(end_time - start_time)  # 執(zhí)行的時(shí)間
            fn(seconds,n)  # 回傳用時(shí)(秒),n 生成的數(shù)量


    def test_callback(tm_s,n):
        print('生成 {0}個(gè)數(shù)熟掂,用時(shí) {1} 秒'.format(n, tm_s))


    test(test_callback, 20)

案例三

def findNumbers(path,num,fn):
        l =[]
        rowNo = 1
        with open(path,'r+') as f:
        for line in f.readlines():
            index = line.find(str(num))
            if index !=-1:
                l.append((rowNo,index+1))
            rowNo +=1
        fn(l)
def callback_(sl):
    print(sl)

findNumbers('222.txt',5,callback_)

二.裝飾函數(shù)

一).裝飾函數(shù)的用途

裝飾器用來實(shí)現(xiàn)一種AOP切面功能缎浇,即一些函數(shù)在調(diào)用前都必須實(shí)現(xiàn)的功能,比如用戶是否登錄赴肚,用戶是否有權(quán)限素跺, 數(shù)據(jù)讀寫操作前打開事務(wù)等之類需求,由裝飾器來實(shí)現(xiàn)比較容易誉券。

二).裝飾器的前世今生

1.史前故事

先看一個(gè)簡(jiǎn)單例子指厌,實(shí)際可能會(huì)復(fù)雜很多:

def today():
    print('2018-05-25')

現(xiàn)在有一個(gè)新的需求,希望可以記錄下函數(shù)的執(zhí)行日志踊跟,于是在代碼中添加日志代碼:

def today():
    print('2018-05-25')
    logging.info('today is running...')

如果函數(shù) yesterday()踩验、tomorrow() 也有類似的需求,怎么做?再寫一個(gè) logging 在yesterday函數(shù)里箕憾?這樣就造成大量雷同的代碼牡借,為了減少重復(fù)寫代碼,我們可以這樣做袭异,重新定義一個(gè)新的函數(shù):專門處理日志 钠龙,日志處理完之后再執(zhí)行真正的業(yè)務(wù)代碼

def logging_tool(func):
    logging.info('%s is running...' % func.__name__)
    func()

def today():
    print('2018-05-25')
logging_tool(today)

這樣做邏輯上是沒問題的,功能是實(shí)現(xiàn)了扁远,但是我們調(diào)用的時(shí)候不再是調(diào)用真正的業(yè)務(wù)邏輯today函數(shù)俊鱼,而是換成了logging_tool函數(shù),這就破壞了原有的代碼結(jié)構(gòu)畅买,為了支持日志功能并闲,原有代碼需要大幅修改,那么有沒有更好的方式的呢谷羞?當(dāng)然有帝火,答案就是裝飾器。

2.開天辟地

一個(gè)簡(jiǎn)單的裝飾器

def logging_tool(func): 
      def wrapper(*arg, **kwargs): 
           logging.info('%s is running...' % func.__name__) 
           func() # 把today當(dāng)作參數(shù)傳遞進(jìn)來湃缎,執(zhí)行func()就相當(dāng)于執(zhí)行today() 
      return wrapper
def today(): 
    print('2018-05-25') 

today = logging_tool(today) # 因?yàn)檠b飾器logging_tool(today)返回函數(shù)對(duì)象wrapper犀填,故這條語句相當(dāng)于today=wrapper 
today() # 執(zhí)行today() 就相當(dāng)于執(zhí)行wrapper()

以上也是裝飾器的原理!Iのァ九巡!

3.Pythonic世界的初探

@語法糖
接觸 Python 有一段時(shí)間的話,對(duì) @ 符號(hào)一定不陌生了蹂季,沒錯(cuò) @ 符號(hào)就是裝飾器的語法糖冕广,它放在函數(shù)開始定義的地方,這樣就可以省略最后一步再次賦值的操作

def logging_tool(func): 
    def wrapper(*arg, **kwargs): 
        logging.info('%s is running...' % func.__name__) 
        func() # 把today當(dāng)作參數(shù)傳遞進(jìn)來偿洁,執(zhí)行func()就相當(dāng)于執(zhí)行today() 
    return wrapper

@logging_tool 
def today(): 
    print('2018-05-25') 
today()

有了 @ 撒汉,我們就可以省去today = logging_tool(today)這一句了,直接調(diào)用 today() 即可得到想要的結(jié)果涕滋。
不需要對(duì)today() 函數(shù)做任何修改睬辐,只需在定義的地方加上裝飾器,調(diào)用的時(shí)候還是和以前一樣宾肺。
如果我們有其他的類似函數(shù)溯饵,可以繼續(xù)調(diào)用裝飾器來修飾函數(shù),而不用重復(fù)修改函數(shù)或者增加新的封裝锨用。這樣瓣喊,提高程序可重復(fù)利用性,并增加程序的可讀性黔酥。

裝飾器在 Python 使用之所以如此方便藻三,歸因于Python函數(shù)能像普通的對(duì)象一樣能作為參數(shù)傳遞給其他函數(shù)洪橘,可以被賦值給其他變量,可以作為返回值棵帽,可以被定義在另外一個(gè)函數(shù)內(nèi)熄求。

裝飾器本質(zhì)上是一個(gè)Python函數(shù)或類,它可以讓其他函數(shù)或類在不需要做任何代碼修改的前提下增加額外的功能逗概,裝飾器的返回值也是一個(gè)函數(shù)/類對(duì)象弟晚。
它經(jīng)常用于有切面需求的場(chǎng)景,比如:插入日志逾苫、性能測(cè)試卿城、事務(wù)處理、緩存铅搓、權(quán)限校驗(yàn)等場(chǎng)景就轧,裝飾器是解決這類問題的絕佳設(shè)計(jì)今穿。
有了裝飾器窿冯,我們就可以抽離出大量與函數(shù)功能本身無關(guān)的代碼到裝飾器中并繼續(xù)重用凤跑。
簡(jiǎn)單來說:裝飾器的作用就是讓已經(jīng)存在的對(duì)象添加額外的功能。

4.多元化百家爭(zhēng)鳴

1).帶參數(shù)的裝飾器

裝飾器的語法允許我們?cè)谡{(diào)用時(shí)氢烘,提供其它參數(shù)怀偷,比如@decorator(condition)。為裝飾器的編寫和使用提供了更大的靈活性播玖。比如椎工,我們可以在裝飾器中指定日志的等級(jí),因?yàn)椴煌瑯I(yè)務(wù)函數(shù)可能需要不同的日志級(jí)別蜀踏。

def logging_tool(level):
     def decorator(func): 
         def wrapper(*arg, **kwargs): 
             if level == 'error':    
                 logging.error('%s is running...' % func.__name__) 
             elif level == 'warn': 
                 logging.warn('%s is running...' % func.__name__) 
             else: 
                  logging.info('%s is running...' % func.__name__) 
             func() 
          return wrapper 
      return decorator 
@logging_tool(level='warn')
def today(name='devin'): 
     print('Hello, %s! Today is 208-05-25' % name)

today()
2).讓裝飾器同時(shí)支持帶參數(shù)或不帶參數(shù)
def new_logging_tool(obj): 
    if isinstanc(obj, str): # 帶參數(shù)的情況晋渺,參數(shù)類型為str 
        def decorator(func): 
            @functools.wraps(func)
            def wrapper(*arg, **kwargs): 
                if obj == 'error': 
                    logging.error('%s is running...' % func.__name__)
                elif obj == 'warn':
                    logging.warn('%s is running...' % func.__name__) 
                else:
                    logging.info('%s is running...' % func.__name__) 
                func()
             return wrapper 
          return decorator 
   else: # 不帶參數(shù)的情況,參數(shù)類型為函數(shù)類型脓斩,即被裝飾的函數(shù) 
       @functools.wraps(obj) 
       def wrapper(*args, **kwargs): 
           logging.info('%s is running...' % obj.__name__) 
           obj() 
       return wrapper

@new_logging_tool 
def yesterday():
    print('2018-05-24') 
yesterday()

@new_logging_tool('warn') 
def today(name='devin'): 
    print('Hello, %s! Today is 208-05-25' % name) 
today()

如上所示,參數(shù)有兩種類型畴栖,一種是字符串随静,另一種是可調(diào)用的函數(shù)類型。因此吗讶,通過對(duì)參數(shù)類型的判斷即可實(shí)現(xiàn)支持帶參數(shù)和不帶參數(shù)的兩種情況燎猛。

3).類裝飾器

裝飾器不僅可以是函數(shù),還可以是類照皆,相比函數(shù)裝飾器重绷,類裝飾器具有靈活度大、高內(nèi)聚膜毁、封裝性等優(yōu)點(diǎn)昭卓。使用類裝飾器主要依靠類的call方法愤钾,當(dāng)使用 @ 形式將裝飾器附加到函數(shù)上時(shí),就會(huì)調(diào)用此方法候醒。

  • 示例一能颁、被裝飾函數(shù)不帶參數(shù)
class Foo(object): 
     def __init__(self, func): 
          self._func = func # 初始化裝飾的函數(shù) 

     def __call__(self): 
          print ('class decorator runing') 
          self._func() # 調(diào)用裝飾的函數(shù) 
          print ('class decorator ending') 
@Foo 
def bar(): # 被裝飾函數(shù)不帶參數(shù)的情況 
    print ('bar') 
bar()

  • 示例二、被裝飾函數(shù)帶參數(shù)
class Counter: 
     def __init__(self, func):
         self.func = func 
         self.count = 0 # 記錄函數(shù)被調(diào)用的次數(shù) 

def __call__(self, *args, **kwargs): 
    self.count += 1 
    return self.func(*args, **kwargs) 

@Counter 
def today(name='devin'):
    print('Hello, %s! Today is 208-05-25' % name) # 被裝飾的函數(shù)帶參數(shù)的情況 

for i in range(10): 
    today() 
print(today.count) # 10

  • 示例三倒淫、不依賴初始化函數(shù)伙菊,單獨(dú)使用call函數(shù)實(shí)現(xiàn)(體現(xiàn)類裝飾器靈活性大、高內(nèi)聚敌土、封裝性高的特點(diǎn))
    實(shí)現(xiàn)當(dāng)一些重要函數(shù)執(zhí)行時(shí)镜硕,打印日志到一個(gè)文件中,同時(shí)發(fā)送一個(gè)通知給用戶
class LogTool(object): 
    def __init__(self, logfile='out.log'): 
        self.logfile = logfile # 指定日志記錄文件 

    def __call__(self, func): # __call__作為裝飾器函數(shù) 
        @functools.wraps(func) 
        def wrapper(*args, **kwargs): 
            log_string = func.__name__ + " was called" 
            print(log_string) # 輸出日志 
            with open(self.logfile, 'a') as fw: 
                fw.write(log_string + '\n') # 保存日志 
            self.notify() # 發(fā)送通知
            return func(*args, **kwargs) 
         return wrapper 
    # 在類中實(shí)現(xiàn)通知功能的封裝
    def notify(self): 
        pass 

@LogTool() # 單獨(dú)使用__call__函數(shù)實(shí)現(xiàn)時(shí)返干,別忘了添加括號(hào)兴枯,進(jìn)行類的初始化 
def bill_func(): 
    pass

進(jìn)一步擴(kuò)展,給LogTool創(chuàng)建子類犬金,來添加email的功能:

class EmailTool(LogTool): 
     """ 
     LogTool的子類念恍,實(shí)現(xiàn)email通知功能,在函數(shù)調(diào)用時(shí)發(fā)送email給用戶 
     """ 
    def __init__(self, email='admin@myproject.com', *args, **kwargs): 
        self.email = email
        super(EmailTool, self).__init__(*args, **kwargs) 

    # 覆蓋父類的通知功能晚顷,實(shí)現(xiàn)發(fā)送一封email到self.email 
    def notify(self): 
        pass 

@EmailTool() 
def bill_func():
    pass

4).裝飾函數(shù) -> 裝飾類
  • 函數(shù)層面的裝飾器很常見峰伙,以一個(gè)函數(shù)作為輸入,返回一個(gè)新的函數(shù)该默;
  • 類層面的裝飾其實(shí)也類似瞳氓,已一個(gè)類作為輸入,返回一個(gè)新的類栓袖;

例如:給一個(gè)已有的類添加長(zhǎng)度屬性和getter匣摘、setter方法

def Length(cls): 
    class NewClass(cls): 
        @property 
        def length(self): 
            if hasattr(self, '__len__'):
                self._length = len(self)
            return self._length 

        @length.setter 
        def length(self, value): 
            self._length = value
     return NewClass 

@Length 
class Tool(object): 
     pass 

t = Tool() 
t.length = 10 
print(t.length) # 10

5.上古神器

1) @property -> getter/setter方法

示例:給一個(gè)Student添加score屬性的getter、setter方法

class Student(object): 
    @property 
    def score(self): 
       return self._score 

    @score.setter 
    def score(self, value): 
       if not isinstance(value, int): 
          raise ValueError('score must be an integer') 
       if value < 0 or value > 100:
          raise ValueError('score must between 0~100!') 
       self._score = value 

s = Student() 
s.core = 60 
print('s.score = ', s.score) 
s.score = 999 # ValueError: score must between 0~100!

2). @classmethod裹刮、@staticmethod
  • @classmethod 類方法:定義備選構(gòu)造器音榜,第一個(gè)參數(shù)是類本身(參數(shù)名不限制,一般用cls)
  • @staticmethod 靜態(tài)方法:跟類關(guān)系緊密的函數(shù)

簡(jiǎn)單原理示例:

class A(object):
    @classmethod
    def method(cls):
        pass

等價(jià)于

class A(object):
    def method(cls):
        pass
        method = classmethod(method)

3).@functools.wraps

裝飾器極大地復(fù)用了代碼捧弃,但它有一個(gè)缺點(diǎn):因?yàn)榉祷氐氖乔短椎暮瘮?shù)對(duì)象wrapper赠叼,不是原函數(shù),導(dǎo)致原函數(shù)的元信息丟失违霞,比如函數(shù)的docstring嘴办、name、參數(shù)列表等信息买鸽。不過呢涧郊,辦法總比困難多,我們可以通過@functools.wraps將原函數(shù)的元信息拷貝到裝飾器里面的func函數(shù)中眼五,使得裝飾器里面的func和原函數(shù)有一樣的元信息妆艘。

def timethis(func):
       """ 
       Decorator that reports the execution time. 
       """ 
      @wraps(func) 
      def wrapper(*args, **kwargs): 
          start = time.time() 
          result = func(*args, **kwargs) 
          print(func.__name__, time.time() - start) 
          return result 
       return wrapper

@timethis
def countdown(n: int):
      """Counts down"""
      while n > 0:
           n -= 1
countdown(10000000)  # 1.3556335
print(countdown.__name__, ' doc: ', countdown.__doc__, ' annotations: ', countdown.__annotations__)

@functools.wraps讓我們可以通過屬性wrapped直接訪問被裝飾的函數(shù)彤灶,同時(shí)讓被裝飾函數(shù)正確暴露底層的參數(shù)簽名信息

countdown.__wrapped__(1000)  # 訪問被裝飾的函數(shù)
print(inspect.signature(countdown))  # 輸出被裝飾函數(shù)的簽名信息
4).Easter egg
  • 定義一個(gè)接受參數(shù)的包裝器
@decorator(x, y, z)
def func(a, b):
      pass

等價(jià)于

func = decorator(x, y, z)(func)

即:decorator(x, y, z)的返回結(jié)果必須是一個(gè)可調(diào)用的對(duì)象,它接受一個(gè)函數(shù)作為參數(shù)并包裝它双仍。

  • 一個(gè)函數(shù)可以同時(shí)定義多個(gè)裝飾器枢希,比如:
@a
@b
@c
def f():
    pass

等價(jià)于

f = a(b(c(f)))

即:它的執(zhí)行順序是從里到外,最先調(diào)用最里層朱沃,最后調(diào)用最外層的裝飾器苞轿。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市逗物,隨后出現(xiàn)的幾起案子搬卒,更是在濱河造成了極大的恐慌,老刑警劉巖翎卓,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件契邀,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡失暴,警方通過查閱死者的電腦和手機(jī)坯门,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來逗扒,“玉大人古戴,你說我怎么就攤上這事【丶纾” “怎么了现恼?”我有些...
    開封第一講書人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)黍檩。 經(jīng)常有香客問我叉袍,道長(zhǎng),這世上最難降的妖魔是什么刽酱? 我笑而不...
    開封第一講書人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任喳逛,我火速辦了婚禮,結(jié)果婚禮上棵里,老公的妹妹穿的比我還像新娘润文。我一直安慰自己,他們只是感情好衍慎,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著皮钠,像睡著了一般稳捆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上麦轰,一...
    開封第一講書人閱讀 51,708評(píng)論 1 305
  • 那天乔夯,我揣著相機(jī)與錄音砖织,去河邊找鬼。 笑死末荐,一個(gè)胖子當(dāng)著我的面吹牛侧纯,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播甲脏,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼眶熬,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了块请?” 一聲冷哼從身側(cè)響起娜氏,我...
    開封第一講書人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎墩新,沒想到半個(gè)月后贸弥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡海渊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年绵疲,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片臣疑。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡盔憨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出朝捆,到底是詐尸還是另有隱情般渡,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布芙盘,位于F島的核電站驯用,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏儒老。R本人自食惡果不足惜蝴乔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望驮樊。 院中可真熱鬧薇正,春花似錦、人聲如沸囚衔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽练湿。三九已至猴仑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間肥哎,已是汗流浹背辽俗。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工疾渣, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人崖飘。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓榴捡,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親朱浴。 傳聞我的和親對(duì)象是個(gè)殘疾皇子吊圾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355

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