第二章:数据类型与转化

1. Python基础语法

Python中变量的命名规则:

  • 变量名的第一个字符不能是数字

赋值

Python允许你同时为多个变量赋值 , 也可以为多个对象指定多个变量。

Python中对变量没有显式的类型定义,但是在使用一个变量前,必须先对其进行赋值,通过赋值完成变量的定义。从本质上讲,Python中由值的特征决定了空间分配和解析方式,变量只是对值的所在空间的引用。简而言之,Python是以值为中心的。

值为一个对象,为值分配空间,变量只是引用。

2. Python基本数据类型:

Python中提供了6种基本数据类型,None表示空对象,无类型。

2.1 数字

Python3 支持 int、float、bool(布尔)、complex(复数) 4种数字类型。布尔类型只有TrueFalse两个值。

Python中:没有数值范围的限制。

 #type()函数用于获取变量的类型

Python中的数值运算基本与c相同,增加了整除(//)和幂(**)两种运算。

4.3 - 2 # => 2.3
3 * 7 # => 21
2 / 4 # => 0.5 除法,得到一个浮点数
2 // 4 # => 0 整数除法,得到一个整数
17 % 3 # => 2 取余
2 ** 5 # => 32 乘方

2.2 字符串(String)

字符串的创建和基本运算

字符串间可以通过 + 号进行连接

"Hello " + "world!" => "Hello world!"

可以通过 * 号,对字符串进行复制,比如:

"Hello" * 3 => "HelloHelloHello"

Python的字符串有两种索引方式,第一是从左往右,从0开始依次增加,第二种是从右往左,从-1开始依次减少。

Python没有单独的字符类型,一个字符就是长度为1的字符串。

可以对字符串进行切片,获取一段子串冒号分隔两个索引:

变量[头下标:尾下标:步长]

两个索引都可以省略。

字符串的切片是原字符串的副本,对切片的修改不影响原字符串

s = 'ILovePython'
s[1:10:2] # => 'LvPto'
s[:] # => 'ILovePython'
s[5:] # => 'Python'
s[-10:-6] # => 'Love'

采用函数len()获取字符串的长度

len()方法同样可以用于其他数据类型,例如查看列表、元组以及字典中元素的多少。

2.2.1 关于字母的内置函数

方法 参数 描述
capitalize() 将字符串的第一个字符转换为大写
title() NA 单词都是以大写开始,其余字母均为小写
upper() NA 转换字符串中的小写字母为大写
swapcase() NA 将字符串中大写转换为小写,小写转换为大写

2.2.2 关于判断的内置函数

isalnum() 字符串中只有字母或数字
isalpha() 检测字符串是否只由字母组成
isdigit() 字符串是否只由数字组成
islower() 检测字符串是否由小写字母组成
isspace() 字符串是否只由空白字符组成
istitle() 检测字符串中所有的单词拼写首字母是否为大写,且其他字母为小写。
isupper() 字符串中所有的字母是否都为大写

2.2.3 常用功能

1.replace(old, new[, max]) old – 将被替换的子字符串。new – 新字符串,用于替换old子字符串。max – 可选字符串, 替换不超过 max 次 |把字符串中的 old(旧字符串) 替换成 new(新字符串),如果指定第三个参数max,则替换不超过 max 次
2.join(sequence) sequence – 要连接的元素序列。用于将序列中的元素以指定的字符连接生成一个新的字符串。

     1.str = "-";
     2.seq = ("a", "b", "c"); # 字符串序列
     3.print str.join( seq );
     4.a-b-c

3.split(str=””, num=string.count(str)) |1.str – 分隔符,默认为所有的空字符,包括空格、换行(\n)、制表符(\t)等。2.num – 分割次数。默认为 -1, 即分隔所有。通过指定分隔符对字符串进行切片,如果第二个参数 num 有指定值,则分割为 num+1 个子字符串。
4.count(sub, start= 0,end=len(string)) |sub – 搜索的子字符串start – 字符串开始搜索的位置。默认为第一个字符,第一个字符索引值为0。end – 字符串中结束搜索的位置。字符中第一个字符的索引为 0。默认为字符串的最后一个位置。|用于统计字符串里某个字符出现的次数。可选参数为在字符串搜索的开始与结束位置。

2.2.4 位置对齐

方法 参数 描述
zfill(width) width – 指定字符串的长度。原字符串右对齐,前面填充0。 返回指定长度的字符串,原字符串右对齐,前面填充0。
rjust(width[, fillchar]) 1.width – 指定填充指定字符后中字符串的总长度.2.fillchar – 填充的字符,默认为空格。 返回一个原字符串右对齐,并使用空格填充至长度 width 的新字符串。如果指定的长度小于字符串的长度则返回原字符串。
center(width[, fillchar]) width – 字符串的总宽度。fillchar – 填充字符。 返回一个指定的宽度 width 居中的字符串,fillchar 为填充的字符,默认为空格。
ljust(width[, fillchar]) width – 指定字符串长度。fillchar – 填充字符,默认为空格。 返回一个原字符串左对齐,并使用空格填充至指定长度的新字符串。如果指定的长度小于原字符串的长度则返回原字符串。

2.2.5 检查查找

方法 参数 描述
startswith(substr, beg=0,end=len(string)) str – 检测的字符串。substr – 指定的子字符串。strbeg – 可选参数用于设置字符串检测的起始位置。strend – 可选参数用于设置字符串检测的结束位置。 用于检查字符串是否是以指定子字符串开头,如果是则返回 True,否则返回 False。如果参数 beg 和 end 指定值,则在指定范围内检查。
endswith(suffix[, start[, end]]) suffix – 该参数可以是一个字符串或者是一个元素。start – 字符串中的开始位置。end – 字符中结束位置。 用于判断字符串是否以指定后缀结尾,如果以指定后缀结尾返回 True,否则返回 False。可选参数 “start” 与 “end” 为检索字符串的开始与结束位置。
find(str, beg=0, end=len(string)) str – 指定检索的字符串beg – 开始索引,默认为0。end – 结束索引,默认为字符串的长度 检测字符串中是否包含子字符串 str ,如果指定 beg(开始) 和 end(结束) 范围,则检查是否包含在指定范围内,如果指定范围内如果包含指定索引值,返回的是索引值在字符串中的起始位置。如果不包含索引值,返回-1。
rfind(str, beg=0 end=len(string)) str – 查找的字符串beg – 开始查找的位置,默认为0end – 结束查找位置,默认为字符串的长度。 返回字符串最后一次出现的位置,如果没有匹配项则返回-1

2.2.6 删除空白符

方法 参数 描述
rstrip([chars]) chars – 指定删除的字符(默认为空格) 删除 string 字符串末尾的指定字符(默认为空格)
lstrip([chars]) chars – 指定删除的字符(默认为空格) 删除 string 字符串开头的指定字符(默认为空格)
strip([chars]) chars – 移除字符串头尾指定的字符序列。 用于移除字符串头尾指定的字符(默认为空格)或字符序列。

2.3 列表(List)

List(列表) 是 Python 中使用最频繁的数据类型,可以实现大多数集合类的数据结构。列表中元素的类型可以不相同,它支持数字,字符串甚至可以包含列表(即嵌套列表)。列表是写在方括号[]之间、用逗号分隔开的元素列表。

和字符串一样,列表同样可以被索引和截取,列表被截取后返回一个包含所需元素的新列表(副本),使用语法形式与字符串完全相同。

tinylist = [123, 'upc']

print(list) # => ['abcd', 786, 2.23, 'upc', 70.2] 输出完整列表
print(list[0]) # => abcd 输出列表第一个元素
print(list[1:3]) # => [786, 2.23] 从第二个开始输出到第三个元素
print(list[2:]) # => [2.23, 'upc', 70.2] 输出从第三个元素开始的所有元素
print(tinylist * 2) # => [123, 'upc', 123, 'runoob'] 输出两次列表
print(list + tinylist) # => ['abcd', 786, 2.23, 'upc', 70.2, 123, 'upc'] 连接列表

与Python字符串不一样的是,列表中的元素是可以改变的:

a = [1, 2, 3, 4, 5, 6]
a[0] = 9
a[2:5] = [13, 14, 15]
print(a) => [9, 2, 13, 14, 15, 6]
a[2:5] = [] 将对应的元素值设置为 []
print(a) => [9, 2, 6]
a.append(7)
print(a) => [9, 2, 6, 7]
b=a.pop()
print(b) => 7
print(a) => [9, 2, 6]

以下是列表的常用函数,函数定义中的方括号表示这个参数是可选的。

函数定义 描述
list.append(x) 把一个元素添加到列表的结尾,相当于 a[len(a):] = [x]。
list.extend(L) 通过添加指定列表的所有元素来扩充列表,相当于 a[len(a):] = L。
list.insert(i, x) 在指定位置插入一个元素。第一个参数是准备插入到其前面的那个元素的索引,例如 a.insert(0, x) 会插入到整个列表之前,而 a.insert(len(a), x) 相当于 a.append(x) 。
list.remove(x) 删除列表中值为 x 的第一个元素。如果没有这样的元素,就会返回一个错误。
list.pop([i]) 从列表的指定位置移除元素,并将其返回。如果没有指定索引,a.pop()返回最后一个元素。元素随即从列表中被移除。
list.clear() 移除列表中的所有项,等于del a[:]。
list.index(x) 返回列表中第一个值为 x 的元素的索引。如果没有匹配的元素就会返回一个错误。
list.count(x) 返回 x 在列表中出现的次数。
list.sort() 对列表中的元素进行排序。
list.reverse() 倒排列表中的元素。
list.copy() 返回列表的浅复制,等于a[:]。

a = [66.25, 333, 333, 1, 1234.5]
print(a.count(333), a.count(66.25), a.count('x')) # => 2 1 0
a.insert(2, -1)
a.append(333)
print(a) # => [66.25, 333, -1, 333, 1, 1234.5, 333]
print(a.index(333)) # => 1
a.remove(333)
print(a) # => [66.25, -1, 333, 1, 1234.5, 333]
a.reverse()
print(a) # => [333, 1234.5, 1, 333, -1, 66.25]
a.sort()
print(a) # => [-1, 1, 66.25, 333, 333, 1234.5]
a = [9, 2, 6]
a.append([1, 2, 3]) #append the new list as one element
print(a) # => [9, 2, 6, [1, 2, 3]]
a = [9, 2, 6]
a.extend([1, 2, 3]) #append each element in the new list
print(a) # => [9, 2, 6, 1, 2, 3]

在一个列表中添加另外一个列表时,注意extend()append() 两个函数的异同点

通过空格将字符串分隔符,把各个单词分隔为列表,split的参数表示分隔的字符

inputWords = input.split(" ")
print(inputWords) # => ['I', 'like', 'upc']

inputWords[::-1] 有三个参数

前两个参数为空,表示取列表中的所有元素

第三个参数为步长,-1 表示逆向

inputWords=inputWords[::-1]
print(inputWords) # => ['upc', 'like', 'I']

重新组合字符串,在几个字符串之间用空格进行连接

output = ' '.join(inputWords) #join函数只能将多个字符串进行连接
print(output) # => upc like I
</pre>

通过split()函数将字符串分隔成一个列表,然后可以用个join()函数将列表中每个字符串进行拼接。

split(str=””, num=string.count(str))函数原型中有两个参数,str表示分隔符,num表示分割次数。默认为 -1, 即分隔所有。

2.4 元组(Tuple)

元组(Tuple)与列表类似,不同之处在于元组的元素不能修改。元组写在小括号 () 里,元素之间用逗号隔开。元组中的元素类型也可以不相同, 可以把字符串看作一种特殊的元组。

虽然tuple的元素不可改变,但它可以包含可变的对象,比如list列表。

构造包含 0 个或 1 个元素的元组比较特殊,所以有一些额外的语法规则:

tup0 = () # 空元组
tup1 = (20,) # 一个元素,需要在元素后添加逗号

在Python中很多地方使用隐式元组,它使Python更具有灵活性。例如

a, b, c = 1, 2, "upc"

可以理解为

(a, b, c) = (1, 2, "upc")

即两个元组的对应元素逐个赋值

在C语言中,很多地方都规定必须唯一,比如:赋值号的左侧只能有一个变量,函数的返回值只能有一个值,Python借助隐式元组完美的解决了这些问题。

利用隐式元组,可以非常简单的实现两个变量的值交换。

a,b=3,5 #多变量赋值
a,b=b,a #交换a和b的值
print(a,b) # => 5 3

2.5 集合(Set)

集合(set)是由一个或数个形态各异的大小整体组成的,构成集合的事物或对象称作元素或是成员。基本功能是进行成员关系测试和删除重复元素。可以使用大括号 { } 或者 set() 函数创建集合,注意:创建一个空集合必须用 set() 而不是 { },因为 { } 是用来创建一个空字典。

student = {'Tom', 'Jim', 'Mary', 'Tom', 'Jack', 'Rose'}

输出集合,重复的元素被自动去掉

print(student) # => {'Mary', 'Jim', 'Rose', 'Jack', 'Tom'}

成员测试

if 'Rose' in student :
print('Rose 在集合中') # => Rose 在集合中
else :
print('Rose 不在集合中')

set可以进行集合运算

a = set('abracadabra')
b = set('alacazam')

print(a) # => {'b', 'a', 'c', 'r', 'd'}

a 和 b 的差集

print(a - b) # => {'b', 'd', 'r'}

a 和 b 的并集

print(a | b) # => {'l', 'r', 'a', 'c', 'z', 'm', 'b', 'd'}

a 和 b 的交集

print(a & b) # => {'a', 'c'}

a 和 b 中不同时存在的元素

print(a ^ b) # => {'l', 'r', 'z', 'm', 'b', 'd'}

集合中的元素是无序的,注意以上例子中,输入的集合和输出的集合顺序是不一致的。

集合(set)常用来抽取一系列元素中的唯一值。但因为集合是无序的,不能保证元素顺序的不变性。
适用于可变集合set和不可变集合frozenset的函数(方法):

集合类型的通用函数(方法)
函数(方法) 描述
s.copy() 复制集合s
a.difference(b,c,d...) 求差集
a.intersection(b,c,d...) 求交集
s.isdisjoint(b) 判断集合s和集合b有没有相同项(元素)
a.issubset(b) 判断集合a是否是集合b的子集
a.issuperset(b) 判断集合a是否是集合b的超集
a.symmetric_difference(b) 求对称差集
a.union(b,c,d...) 求并集
len(s) 求集合s中项(元素)的数量

仅适用于可变集合的函数(方法):
可变集合函数(方法)用法
函数(方法) 描述
s.add(x) 将x添加到集合s中
s.clear() 删除集合s中所有元素(项)
s.discard(value) 从集合s中删除元素value
s.remove(value) 从集合s中删除元素value
s.pop() 返回集合s中任意一个元素,并将其删除
s.difference_update(x) 从集合s中删除同时也在x中出现的所有元素
s.update(x) 将x中的所有元素添加到集合s中
s.symmetric_difference_update(x) 计算集合s与x的对称差集,并将结果保存在集合s中
s.intersection_update(x) 计算集合s与x的交集,并将结果保存在集合s中

2.6 字典(Dictionary)

字典(dictionary)是Python中另一个非常有用的内置数据类型。列表是有序的对象集合,字典是无序的对象集合。两者之间的区别在于:字典当中的元素是通过键来存取的,而不是通过偏移存取。字典是一种映射类型,字典用 { } 标识,它是一个无序的 键(key) : 值(value) 的集合。键(key)必须使用不可变类型,而且在同一个字典中,键(key)必须是唯一的。

aDict = {}
aDict['one'] = "中国石油大学"
aDict[2]     = "智能科学系"
tinydict = {'name': 'upc','code':1, 'site': 'www.upc.edu.cn'}#典型的键和值组成的集合
 
print(aDict['one'])    # => 中国石油大学        输出键为 'one' 的值
print(aDict[2])        # => 智能科学系          输出键为 2 的值
print(tinydict)        # => {'name': 'upc', 'code': 1, 'site': 'www.upc.edu.cn'}
print(tinydict.keys())   # => dict_keys(['name', 'code', 'site'])  
print(list(tinydict.keys()))    # => ['name', 'code', 'site']   将键值集合转换为列表
print(tinydict.values()) # => dict_values(['upc', 1, 'www.upc.edu.cn']) 
print(list(tinydict.values()))  # => ['upc', 1, 'www.upc.edu.cn'] 将值集合转换为列表

Attention 字典的键就是一个集合(set),因此也是无序的

2.7 类型转换

Python中采用函数进行类型转换:

函数 描述
int(x[,base]) 将x转换为一个整数,base默认为十进制
float(x) 将x转换到一个浮点数
str(x) 将对象 x 转换为字符串
eval(str) 用来计算在字符串中的有效Python表达式,并返回一个对象
tuple(s) 将序列 s 转换为一个元组
list(s) 将序列 s 转换为一个列表
set(s) 转换为可变集合
dict(d) 创建一个字典。d 必须是一个 (key, value)元组序列。
frozenset(s) 转换为不可变集合

3. 数据的输入和输出

3.1 输入

input([prompt]) 函数用来从标准输入读取一行文本。prompt 表示输入提示,可省略。input() 函数将一个回车之前的内容全部读入,返回值是文本类型。

s = input("Please input: ");        # => Please input:中国石油大学
print ("The content is: ", s)       # => The content is: 中国石油大学

当输入内容是一个非字符串类型时,需要进行强制类型转换

num = int(input())   #if the input is 56 and you wanna get an integer
print(num)      # => 56
print(type(num))    # => <class 'int'>

当输入是多个相同类型的变量时,可以采用map()函数进行批量转换。map(function, iterable, ...)函数的第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表。

s = input()   #if the input is '3.4, 5.6, 8.7' and you wanna get 3 float number
numLst = s.split(',')       # split 's' to a list with seperator ','
#make a list of return values of function 'float' for each element in 'numLst'
resultLst = map(float,numLst)    
a,b,c = resultLst   #set a,b,c with 3 elements in list 'resultLst'
print(a,b,c)  # => 3.4 5.6 8.7
print(type(a),type(b),type(c))  # => <class 'float'> <class 'float'> <class 'float'>

变量s 把'3.4, 5.6, 8.7'作为一个字符串接收,通过split函数,以逗号为分隔符,形成了一个列表numLst,然后其中的每一个元素受函数float的作用,将返回值形成了一个新列表resultLst,resultLst中的每一个元素都是float类型,最后将列表中的三个元素对应赋值给变量a,b,c。可以将以上代码简化为一条语句:

a,b,c = map(float,input().split(','))   #if the input is “3.4, 5.6, 8.7” 
print(a,b,c)  # => 3.4 5.6 8.7

3.2 输出

3.2.1 print的参数

print函数可以添加参数sep和end,sep表示输出多个对象时的分隔符号,默认为空格,end表示结束符号,默认为回车。

print(1,2,3)    # => 1 2 3
print(1,2,3,sep=',')    # => 1,2,3 逗号作为分隔符
#左对齐,居中对齐,右对齐
print(str(1).ljust(3),'|',str(2).center(3),'|',str(3).rjust(3),'|',sep='')
#=>1  | 2 |  3|
print(str(12).zfill(5))     # => 00012     左侧补0

3.2.2 字符串格式化

Python用 str.format() 函数进行输出的格式化

#大括号及其里面的字符 (称作格式化字段) 将会被 format() 中的参数替换。
print('{}网址: {}'.format('中国石油大学', 'www.upc.edu.cn'))
# => 中国石油大学网址: www.upc.edu.cn

#在大括号中的数字用于指向传入对象在 format() 中的位置
print('{0} {1}'.format('intelligence', 'technology'))
# => intelligence technology
print('{1} {0}'.format('intelligence', 'technology'))
# => technology intelligence

#如果在 format() 中使用了关键字参数, 那么它们的值会指向使用该名字的参数
print('{name}网址: {site}'.format(name='中国石油大学', site='www.upc.edu.cn'))
# => 中国石油大学网址: www.upc.edu.cn

#位置及关键字参数可以任意的结合
print('{0} {1} {dept}'.format('intelligence', 'technology', dept='department'))
# => intelligence technology department

3.2.3 f-string格式化

从Python 3.6开始,提供了一种f-string的输出方法,是当前最佳的拼接字符串的形式,拥有更强大的功能,使输出更加简洁。它的基本语法格式为:

f'<text> {<expression>[:format specifier]} <text> ...'

<text>指一些文本内容,experession是Python变量或表达式,format specifier指格式控制。格式控制可以省略,其中的df参数分别指十进制和浮点数,具体用法与C语言相同。

name='ben'
age=30
sex='male'
mm,dd=7,3
job='IT'
salary=12000

print(f'My name is {name.capitalize()}.')  # => My name is Ben.
print(f'I am {age:*^10} years old.')  # => I am ****30**** years old.
print(f'I am a {sex}.')  # => I am a male.
print(f'My birthday is {mm:02d}/{dd:02d}.')  # => My birthday is 07/03.
print(f'My salary is ${salary:10.2f}.')  # => My salary is $  12000.00.
print(f'The result is {dd*5+2}.')  # => The result is 17.

从执行时间角度,f-string是目前效率最高的字符串拼接方法。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,482评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,377评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,762评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,273评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,289评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,046评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,351评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,988评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,476评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,948评论 2 324
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,064评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,712评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,261评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,264评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,486评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,511评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,802评论 2 345

推荐阅读更多精彩内容