Python

Python基础常识

python 区分大小写 Andy != andy
print("\r", end="") end="" 关闭print的自动\n "\r" 返回行首打印
"\r" end="" 可以实现在shell中始终在一行的开头打印
temp = """string""" 实际上是一个可以换行的字符串 可以让变量来保存 如果在类或者函数里就是类和函数的说明文档
input("请输入:") 接收键盘输入的信息 返回字符串
type(对象) 查看数据类型
id(对象) 查看对象的引用地址以10进制
dir(对象) 查看对象的所有属性和方法 包括继承的
代码太长可以在需要换行的地方输入\然后换行或者使用()
TODO(作者) 标签 提示还没开发完成的功能
pass 占位符保证程序结构正确
while True: 循环入口 当while后的值为逻辑真时 进入无限循环
+= 可以合并列表 元组 字符串 针对列表的+= 实际上是调用了extend方法 所以在函数内需要注意(可变数据类型)
变量保存着程序在自身内存空间中为数据提供的空间的引用
关键字就是python内置的功能 特点是后面不跟括号 直接使用(区别于property)
函数就是封装好的功能 特点是后面跟一个括号
方法就是针对面向对象的函数 对象.函数()
cpython37.pyc结尾的文件是python解释器编译过的代码 以二进制的形式储存在电脑 目的是加快代码运行速度
代码的结构 shebang==>import==>定义的常量==>定义的函数==>代码

变量与常量

用来存储数值时变量 变化的量 常量 不变化的量
变量的命名所有字母小写用下划线连接单词
常量的命名所有字符大写用下划线连接单词
不要在代码中直接出现数字而应该使用常量

数据类型

数字型 int float bool complex 布尔属于数字型
非数字型 str list tuple dict

数据类型转换

int(str|float) 转换小数向下取整 无法转换带.字符串类型小数 可以 int(float(str))
float(str|int)
bool(0即假 值为空即假 None即假)
str(num)
tuple(list)
list(tuple)
None 表示空对象 什么都没有
值为空不是None 是空数据的对象

拼接字符串

str * num str + str
list * num list + list
tuple *num tuple + tuple
list + tuple不能交叉合并

格式化字符串

%s 字符串
%d 十进制数字
%x 十六进制数字
%f 浮点型
%05.2f 保留2位小数并且保证整体宽度为5不足的以0占位 03.00
格式化字符串输出%使用%%
格式化字符串的参数本质上就是一个元组 可以用元组替换 print("%s年龄是%d身高是%.2f" % (tuple))

转义字符

\n 换行
\r 回到行首
\t \v 制表符
\u 转义unicode字符串 \u00b2

分支语句

例1

if xxx: (判断的是逻辑真假)
    xxx
else:
    xxx

例2

if xxx:
    xxx
elif xxx:
    xxx
else:
    xxx
IF嵌套

例3

if xxx:
    xxx
    if xxx:
        xxx
    else:
        xxx
else:
    xxx

三元表达式

方法一: 为真时的结果 if 判定条件 else 为假时的结果

d = b if a else c  #如果a为真,结果是b,否则结果是c
print('方法一输出结果:' + d)  

方法二: 判定条件 and 为真时的结果 or 为假时的结果

d = a and b or c  #如果a为真,结果是b,否则结果是c
print('方法二输出结果:' + d)  

以上两种方法方法等同于if ... else ...

if a:  
    d = b  
else:  
    d = c  
print('if语句的输出结果:' + d)

循环语句

例1

i = 0
while i (判断) xxx: (判断的是逻辑真假)
    xxx
    i += 1  # 设置循环换出口 在循环体外部设置计数器在内部每次迭代为计数器+1

例2

i = 0
while i (判断) xxx:
    if i (判断) m:
        xxx
        break  # 当程序满足某个条件 直接结束本层循环 不执行本层循环体的后续代码
    i += 1

例3

i = 0
while i (判断) xxx:
    if i (判断) m:
        xxx
        i += 1
        continue  # 当程序满足某个条件 重新循环本层循环体的下一个迭代 不执行本层循环体的后续代码
    xxx
    i += 1
WHILE嵌套

例4

i = 0
while i (判断) xxx:
    m = 0
    while m (判断) i:
        xxx
        m += 1
        break  # 只影响当前的循环体 不影响上一层的循环体
    xxx
    i += 1

break continue 只影响当前的循环体 不影响上一层的循环体

迭代遍历

for num in list(): 实际上执行list对象的__iter__方法如果有此方法说明对象是一个可迭代对象如果没有说明无法迭代
__iter__会返回一个对象如果这个对象有__next__方法实现for循环每循环依次取__next__的返回值给num
可迭代对象如果没有通过iter返回一个具有next方法实现的对象 那么无法实现迭代

完整的FOR循环
for i in 集合:
    print(i)
    if i == x:
        break
else:
    print(break后不执行)
print(结束遍历)

遍历结束后执行else后的代码但如果break则不会执行

函数

函数的定义
def 函数名():
    """注释 define 上要要留两行空行pycharm中cltr + q 可以查看注释"""
函数的封装

文件保存的名字fun_file是模块的名字
函数名是模块的方法 fun_file.方法()
不主动调用 封装的内容不会执行

函数的调用

import fun_file 用来加载定义的模块
fun_file.函数() 用来调用模块的方法

函数的参数
def 函数名(形参1, 形参2, …):
    result = 形参1*形参2
    return result
i = 函数名(实参1, 实参2, …)
print(i)

return 把结果返回给外部调用函数的函数名
return 可以结束函数和方法 下方的代码不会被执行
return 也可以终止循环体 并且不管多少层都直接终止
返回时: 可使用元组来返回多个结果 return (结果1, 结果2, 结果3) 可以省略括号
接收时: 返回的是元组 使用多个变量接收 变量1, 变量2, 变量3 = 函数()(实际是一个元组 拆包)

函数的递归

在函数内部 调用函数自己 叫做函数的递归如果不指定出口会死循环
函数的递归求1到100的累加结果

def sum_num(num):
    if num == 1:
        return 1
    temp = sum_num(num-1)
        return num + temp
sum_ = sum_num(100)
print(sum_)
eval()函数

eval()函数会计算字符串中的表达式并返回结果
不要滥用eval()转换input的内容

enumerate()函数

可以对list tuple str 有序合集枚举 无法对dict枚举
enumerate(seq, start=num) 返回的是一个对象 也可以通过start=num指定序号起始数字
每个元组内容为 (0, H), (1, e), (2, l)
通常配合遍历使用

list = [1, 2, 3, 4, 5]
for i, num in enumerate(list):
    print(i)  # 序号
    print(num)  # 元素

列表 list

定义列表

list = ["张三", "李四", "王五"]

列表的方法

取值 list[下标]下标也就是索引 从0开始
取索引 list.index("char") char的索引是几就返回几
list[index] = "char" 把下标index的数据修改为char
list.append("char") 在列表末尾追加一个数据 list.append(list2) 是追加一个元素会显示为[1, 2, 3, [1, 2, 3]]
list.insert(0, "char") 向索引0的前面插入一个char
list.extend(list_2) 把列表2合并到list末尾 是合并一个列表会显示为[1, 2, 3, 1, 2, 3]
del list 删除列表
list.remove("char") 从列表中删除这个数据
list.pop(index) 删除这个索引下的数据
list.clear() 清空列表
list.pop() 删除最后一个索引的数据
len(list) 显示列表长度
list.count("char") 查看某个数据在列表中出现的次数
list.sort() 升序排列
list.sort(reverse=True) 降序排列
list.reverse() 逆序 颠倒排列

元组 tuple

定义元组

tuple = () 空元组
tuple = (char,) 单元素元组

元组的方法

取值 tuple[index]
取索引 tuple.index("char") 查询char的索引下标
tuple.count("char") 统计char在元组里出现的次数
len(tuple) 查询元组的长度

字典 dict

字典是以 key: value 键值对对应 特点是无序 列表元组有序

定义字典

dict = {"name": "Lee", "age": 18, "height": 1.75}
key必须唯一 value不必唯一

字典的方法

取值 dict["key"]
修改 dict["key"] = "value"
增加 dict["key"] = "value"key不存在表示添加键值对
删除键值对 dict.pop("key")
清空 dict.clear()
合并 dict.update(dict2)
删除字典 del dict
len(dict) 有多少组键值
dict.keys() 显示所有键 以列表形式
dict.values() 显示所有值 以列表方式
dict.items() 显示所有键值对 以列表方式

集合 set

在 Python 中,集合分为两类:

  • set 可变集合 可以原地修改 是 unhashable(不可哈希)的
  • frozenset 不可变集合 顾名被“冻结”的集合 不能原地修改 是 hashable(可哈希)的

集合(set) 是一个无序不重复元素的序列并且是不可变类型 集合不支持索引
可以使用大括号{ }或者set()函数创建集合
创建一个空集合必须用 set()而不是 { } 因为 { } 是用来创建一个空字典

推导式

推导式comprehensions(又称解析式) 推导式是可以从一个数据序列构建另一个新的数据序列的结构体 共有三种推导式

  • 列表(list)推导式
  • 字典(dict)推导式
  • 集合(set)推导式

推到式的格式: [表达式 for 变量 in 列表] 或者 [表达式 for 变量 in 列表 if 条件]
推导式不仅让代码更简洁执行速度也更快

列表推导式
lst = [i for i in range(10)]  # 生成列表[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
lst = [i*2 for i in range(10) if i >= 5]  # 生成当i大于5时i平方的列表[25, 36, 49, 64, 81]
type(lst)  # list
元组(生成器)推导式
gen = (i for i in range(10))  # 生成生成器通过next()函数或者gen.__next__()方法取值
type(gen)  # generator
集合推导式
lst = [ 9, 1, 1, 3, 5, 5, 7, 7, 7, 0]
seting = {i for i in lst}  # 生成一个无序的集合并且去重{0, 1, 3, 5, 7, 9}
type(seting)  # set

字符串

定义字符串

string = "abcde"

字符串的方法

取值 string[num]
取索引 string.index("char") 显示char子字符的下标
len(string) 统计字符串的长度
string.count("char") 统计子字符char的出现次数

判断空格和空白字符

string.isspace() 字符串只有空白字符则true (空字符串则false)
string.isalnum() 字符串有字符且没有空白字符则true (空字符串则false)

判断字母

string.isalpha() 字符串只包含字母且没有空白字符则true (空字符串则flase)

判断数字

string.isdecimal() 字符串只包含数字则true 可判断 半角 全角数字
string.isdigit() 字符串只包含数字则true 可判断 半角 全角数字 unicode特殊数字
string.isnumeric() 字符串只包含数字则true 可判断 半角 全角数字 unicode特殊数字 中文数字
这三个方法都不能判断小数点认为小数点是英文字符

判断大小写

string.istitle() 如果字符串的每个单词首字母大写则true 有空格没关系
string.islower() 如果字符串中有哪怕一个是能区分大小写的字符被小写则true 有空格没关系
string.isupper() 如果字符串中有哪怕一个是能区分大小写的字符被大写则true 有空格没关系

查找字符串

string.startswith("char") 如果是以char开头则true
string.endswith("char") 如果是以char结尾则true
string.find (str, start=0, end=len(str)) 查询字符串是否包含子字符串可指定范围 有则返回下标 没有返回-1
string.rfind(str) 反向查询
string.index(str) 返回字符串中子字符串的下标 没有则报错
string.rindex(str) 反向查询

替换字符串

string.capitalize() 将字符串首字符大写
string.title() 将字符串中每个单词首字母大写
string.upper() 将字符串中所有小写字符改为大写
string.lower() 将字符串中所有大写字符改为小写
string.swapcase() 翻转字符串中的字母大小写
string.replace(old_str, new_str, num=string.count(str)) 返回一个新的字符串 一次性修改字符串内所有子字符串 可以指定修改个数

文本对齐

string.center(num, "char") 居中对齐并且填充宽度 还可以填充字符
string.ljust(num, "char") 向左对齐以字符填充
string.rjust(num, " ") 向右对齐以空格填充

去除空白字符

string.strip("\t\n") 去掉字符串左右的空白字符
string.lstrip("\n") 去掉左边空白字符
string.rstrip(" ") 去掉右边空白字符
\t \n 也可以被去掉

拆分和链接

new_list = string.split(str)str为点拆分字符串 输出一个列表 如果str不指定就默认包含\r \n \t空格
list_lines = string.splitlines() 如果string有换行使用splitlines()可以以行为单位返回一个字符串列表
new_string = str.join(seq) 将序列中的每个元素组成一个字符串用str间隔
new_string = " ".join(seq) 以空格链接序列 seq 可以是列表 元组 字符串

切片

可以对list tuple str 有序集合切片 无法对dict切片
string[开始索引: 结束索引: 步长] 返回一个字符串
如果不指定切片开始结束 string[:] 就是切len(string)

字符串的逆序

string[-1::-1] 从-1向后切再向前移动直到头

公共方法

就是列表 元组 字符串 字典 都可以使用的方法
len() 统计元素个数
del() 删除变量 或者删除变量内部的元素
max() 显示容器中最大的值 字典只针对keys
min() 显示容器中最小的值 字典只针对keys

运算符

+ 合并 * num 重复
可以合并 重复 str list tuple 字典不可以合并 字典使用update()方法合并并且会去重
不能交叉合并 list + tuple

逻辑运算符

and or not 与 或 非
and 遇到假立即返回假
or 遇到真立即返回真
and自左向右扫描布尔表达式 如果所有表达式为真 则返回最后一个为真的表达式 如果有表达式为假 立即返回假并且不再向后执行

1 and 0 and 3/0  # 立即返回 0 并且不再向后执行除0错误
1 and "0"  # 返回最后一个为真的表达式结果

or与and正好相反 自左向右扫描布尔表达式 如果所有表达式为假 则返回最后一个为假的表达式 如果有表达式为真 立即返回真并且不再向后执行

0 or 1 or 3/0  # 立即返回 1 并且不再向后执行除0错误
0 or ""  # 返回最后一个为假的表达式结果

利用and or完成三元表达式
表达式 and 表达式 or 表达式 计算的是表达式的逻辑真假 输出的是表达式的结果

a = 25
b = 5
a > b and a or b  # 计算and两边 左右都为真返回第二个真(a) 第二次计算 真(a) or b 立即返回真a的值
a < b and a or b  # 计算and两边 左边为假立即返回假(a<b) 第二次计算 假(a<b) or b 返回真b的值
数学运算符

+ - * / % // ** 加 减 乘 除 求余 整除 幂运算

成员运算符

4 in [1,2,3,4] 返回 true 元素在列表内
4 not in (1,2,3) 返回 true 元素不在元组内
可以判断 str list tuple dict 字典只针对keys

比较运算符

比较数据的值
== != > < <= >= 返回 True False
可以比较 str list tuple 不能比较字典
注意字符串的比较符合以下规则 0 < A < a

身份运算符

比较数据的内存地址
is is not 返回 True False

a = [1,2,3]
b = [1,2,3]
a == b True 
a is b False

变量进阶

变量引用数据后变量就储存了数据的地址 变量记录数据的地址叫做引用
id() 可以查看变量中引用数据的内存地址
如果变量已经被赋值 再次赋值变量 本质上是修改变量的引用
函数的参数和返回值 都是通过引用传递

可变和不可变数据类型

内存地址不变的情况下的内容的可变和不可变

不可变类型

int float bool complex str tuple

可变类型

list dict
list dict 的内容可以通过方法改变 而且数据的地址不会发生改变
从内存地址的角度讲
不可变类型被创建后不可以改变内容
可变类型可以通过方法改变内容而内存地址不改变
hash() 哈希是一种算法 作用是提取数据的唯一特征码
哈希只能接收不可变类型的数据
创建字典的键值对时python会对key进行hash决定如何在内存中保存字典的数据
所以字典的key必须是不可变数据类型
字典中字典和key储存在一个内存空间中而value储存在其他空间中 value只是保存了字典的值数据的引用

局部变量

在函数中定义的变量无法在其他位置使用
不同函数内部可以定义相同名字的变量而不相互影响

全局变量

在函数外部定义的变量可以在函数内部使用
在函数内部定义已有全局变量名称的变量只是定义局部变量
global num 在函数内申明num是全局变量 然后对变量的重新赋值会修改全局变量
全局变量的命名一般加上 g_ 或者 gl_

可变参数和不可变参数

函数的参数通过引用传递
在函数内部重新赋值形参变量只是定义局部变量 不会影响实参
在函数内部使用形参变量的方法改变变量数据时会修改外部的实参 可变类型数据
使用列表为参数传递给函数再在函数内部使用 += 本质上属于 extend 方法会改变全局变量中列表的值

函数的缺省值

函数的某个参数相对固定时 可以设置一个缺省值
缺省参数应该放在函数形参的最后一个
如果函数有多个缺省参数 在调用指定缺省参数时需要输入完整缺省参数的形参名

多值参数

参数可以存放多个数据
*args 存放元组参数
**kwargs 存放字典参数
在函数外传入字典实参时候要使用key=value不能使用key: value 类似 增加键值对的操作 dict["key"] = value

装包

如果需要将多个值传递给多值参数时装包可以简化参数的传递
形参 *tuple **dict
实参 (1, 2, 3, name="Lee", age=18)

拆包

在函数内部针对形参使用*tuple **dict 又可以拆包
字典的拆包*kwargs只得到key **kwargs得到key:value
a, b = (11, 22) 这也是拆包

操作文件的函数

file = open("文件名", "访问方式", encoding="UTF8") 打开文件 区分大小写 默认"r"模式打开
文件如果存在 返回文件操作对象 文件如果不存在 抛出异常
在访问方式参数上加上b代表用二进制方式打开文件 理论上open可以打开任何文件 "rb" "wb"

文件指针

文件指针标记了从哪个位置开始读取数据
第一次操作文件前指针默认指向文件开始的位置

操作文件的方法

read() 一次性读取所有内容 读取后文件指针会在文件末尾
readline() 一次读取一行内容 读取后文件指针会在下一行的开始
write() 将指定内容写入文件 写入后指针会在文件末尾
close() 关闭文件关闭文件句柄 fd
如果没有关闭文件 会消耗系统资源 并且影响后续对文件的访问

打开文件的参数

"r" 只读方式打开文件 文件指针将会放在文件的开头 如果文件不存在 抛出异常
"w" 只写模式打开文件 文件指针将会放在文件的末尾 如果文件存在会覆盖内容 如果文件不存在会创建文件并写入
"a" 追加只写模式打开文件 文件指针将会放在文件的末尾 如果文件存在会追加内容 如果文件不存在会创建文件并写入
"r+" 读写方式打开文件 文件指针将会放在文件的开头 如果文件不存在 抛出异常
"w+" 读写方式打开文件 文件指针将会放在文件的末尾 如果文件存在会覆盖内容 如果文件不存在会创建文件并写入
"a+" 追加读写方式打开文件 文件指针将会放在文件的末尾 如果文件存在会追加内容 如果文件不存在会创建文件并写入

分行读取文件

readline() 方法一次读取一行文件对象的内容 执行后文件指针会在读取行的末尾
readline 分行读取大文件降低内存压力

file = open("file_path", "r")
while True:
    text = file.readline()
    if not text:
        break
    print(text)
file.close()
复制文件
file_read = open("file_path", "r")
file_write = open("file_path_复件", "w")
text = file_read.read()
file_write.write(text)
file_read.close()
file_write.close()
分行复制文件
file_read = open("file_path", "r")
file_write = open("file_path_复件", "w")
while True:
    text = file_read.readline()
    file_write.write(text)
    if not text:
        break
file_read.close()
file_write.close()

文件/目录的常用管理操作

导入os模块 import os
os.system("shell命令")
system方法可以在python解释器中执行终端命令

文件操作

os.rename("文件名", "新文件名") 重命名文件
os.remove("文件名") 删除文件

目录操作

os.listdir("目录名") 查看目录内容 返回一个列表
os.mkdir("目录名") 创建目录
os.rmdir("目录名") 删除目录
os.getcwd() 获取工作目录
os.chdir("目标目录") 修改工作目录
os.path.isdir("文件路径") 判断是不是文件夹 返回bool

文本编码

python2.x默认ascii编码格式
python3.x默认UTF-8编码格式
UTF-8unicode编码的一种编码格式
汉字在UTF-8中占3字节
*.py 第一行加入 # *-* coding:utf8 *-* 或者 # coding=utf8 指定解释器使用的编码
在遍历或者切片字符串时即使第一行指定了编码格式还是会出错 需要在UTF-8编码格式的字符串前加上u"hello世界"

字符串的编码

string.encode("utf-8") 返回编码后的字符串 是一个utf8bytes对象
data.decode("gbk") 把某种bytes数据解码成gbk编码的字符串
utf8bytesgbkbytes长度不同

数据结构

​链表(linkdelist)

链表由一系列不必在内存中相连的结构构成 这些对象按线性顺序排序 每个结构含有表元素和指向后继元素的指针 最后一个单元的指针指向NULL 为了方便链表的删除与插入操作 可以为链表添加一个表头

栈(stack)

是一种受限的线性表 仅允许在表的一端进行插入和删除运算 这一端被称为栈顶 另一端称为栈底 向一个栈插入新元素又称作进栈压栈 它是把新元素放到栈顶元素的上面 使之成为新的栈顶元素 从一个栈删除元素又称作出栈退栈 它是把栈顶元素删除掉 使其相邻的元素成为新的栈顶元素

队列(queue)

是一种特殊的线性表 是一种先进先出的数据结构 只允许在表的前端进行删除操作而在表的后端进行插入操作 进行插入操作的端称为队尾进行删除操作的端称为队头 队列中没有元素时称为空队列

魔法属性

对象.__dict__ 可以查看对象的所有属性
对象.__doc__ 可以查看doc描述
对象.__class__ 查看谁创建了该对象
对象.__moulde__ 查看这个对象是由哪个模块创建的

def __new__(cls) 创建对象的内存空间
def __init__(self) 初始化实例对象的属性
newinit 一起完成了构造方法 构造方法包括创建内存和初始化属性
def __del__(self): 当对象被销毁时会自动调用此方法
def __call__(self) 当执行实例对象obj() 时 会调用__call__ 方法
def __str__(self)print对象时str方法返回什么就打印什么 此外 "%s" % 对象 默认调用对象的str方法

class Foo(object):
    def __init__(self):
        pass
    def __str__(self):
        return "test"
    def __call__(self, num):
        print(num)
    def __del__(self):
        print("death")  # 当对象被自动销毁时会自动调用del方法
obj = Foo()  # 当创建对象时会调用init方法
obj(10)  # 当实例对象使用()时 调用的是call方法
print(obj)  # 打印的结果就是str返回的字符串

with和上下文管理器

with as 一般用来简化操作文件时的清理工作
with 后面的代码返回的对象内必须有__enter__方法和__exit__方法 exit方法一般包含"清理"代码(异常处理和退出)

with open("file_path", "r") as f:  # 调用open返回的对象的enter方法然后把__enter__的返回值赋值给f
    print(f)  # 如果有异常会被f的exit方法捕获并且退出(出错也会关闭句柄)

with后的代码被求值后返回一个对象并且这个对象的__enter__()方法会被调用然后把enter的返回值赋值给as后的变量f
f对象运行时不管异常还是完成运行都会调用f__exit__()方法进行"清理"

上下文管理器

当一个对象被用作上下文管理器时他创建的对象必须包含这两个方法:

  • __enter__方法将在进入代码块前被调用(类似init但是仅用作上下文管理器)
  • __exit__方法则在离开代码块之后被调用(即使在代码块中遇到了异常)
contextlib模块
from contextlib import contextmanager
@contextmanager
def my_open(path, mode):
    f = open(path, mode)
    yield f
    f.close()
with my_open("out.txt", "w") as f:
    f.write("hello,the simplest context manager")

当装饰器为@contextmanager标记为上下文管理器时
yield 之前的相当于上文yield 后的f 类似enter返回的对象
yield 下面的相当于下文 用作执行完write后的"清理"

isinstance()函数

isinstance(object, Classinfo) 判断obj是不是Class的实例 或者obj是不是Class的子类的实例 返回bool

判断对象是不是可迭代对象

collectionspython内建的一个集合模块 包含许多集合类
Iterablecollections 模块中的一个类 所有可以迭代的对象都来自Iterable
通过 isinstance(a, Iterable) 判断a是不是一个可迭代对象

迭代器(iterator)

对于没有索引的数据类型 必须提供一种不依赖索引的迭代方式
python中实现了__iter__()方法的对象是可迭代的 实现了__next__()方法的对象是迭代器 所以让一个迭代器工作 至少要实现__iter__方法和__next__方法
如果一个类的对象想被用于for..in循环迭代 就必须实现一个__iter__()方法 该方法返回一个迭代器对象 for循环就会不断调用该迭代器对象的__next__()方法拿到循环的下一个值 直到遇到StopIteration错误时退出循环

可迭代对象和迭代器
class A(object):    可迭代对象
    def __init__(self):
        self.list = list()
    def add(self, new):
        self.list.append(new)
    def __iter__(self):
        return B(self.list)
class B(object):   迭代器
    def __init__(self, list):
        self.list = list
            num = 0
        def __iter__(self):  # 此方法表示是一个可迭代对象 迭代器必须是一个可迭代对象
            return None
        def __next__(self):
            if self.num < len(self.list):
                ret = self.list[self.num]
                self.num += 1
                return ret
            else:
                raise StopIteration

可迭代对象必须包含__iter__方法
__iter__返回值必须返回一个迭代器才可以实现迭代
包含__iter__方法和__next__方法的叫做迭代器也是可迭代对象
for循环或者next()函数取值时会每次取对象的iter方法所返回的对象里的next方法实现迭代

简化实现迭代器
class Iterable_A(object):
    def __init__(self):
        self.list = [11, 22, 33]
        self.num = 0
    def __iter__(self):
        return self
    def __next__(self):
        if self.num < len(self.list)
            ret = self.list[self.num]
            self.num += 1
            return ret
        else:
            raise StopIteration
使用迭代器的好处

python2range(x) 生成x个元素的列表 占用大量内存空间
xrange(x) 返回一个对象 这个对象保存了生成x个元素列表的方法 使用一个生成一个 节约内存空间
python3中已经用xrange替换了range

生成器(generator)

yield 生成器的特点 让代码暂停
生成器也是一个迭代器(特殊的迭代器) 使用一次生成一个对象 节约内存空间
如果一个函数中有yield语句 那么他会变为一个创建生成器的类
for循环这个生成器对象取值或者使用next(obj)函数取值时 程序执行到yield会返回yield后的值并暂停下次循环时会从yield后开始执行 直到循环结束退出
obj.send(None)同样具有next(obj)的功能并且可以传入生成器一个值
send()的参数如果不为None则是把yield xx 这个整体当做一个表达式 并把参数传入表达式 然后可以赋值给yield xx 左边的变量
如果第一次启动生成器时就用send()并且传入一个值 会报错 第一次执行暂停在yield xx 因此传入的值没有变量保存 所以启动生成器时用next()后续才可以使用send(msg)传入参数

通过next()函数取值生成器
def fib(nums):
    a = 0 
    b = 1
    count = 0
    while count < nums:
        yield a
        a, b = b, a+b
        count += 1
    return "done...."

nums_obj = fib(10)

while True:
    try:
        ret = next(nums_obj)
            print(ret)
        except Exception as x:
            print(x.value)
            break

此时nums_obj 是一个yield模板创建的生成器对象 使用next()函数取值生成器
如果要在迭代结束后返回一个值就在创建生成器的函数中使用return返回内容
并且在next取值结束时捕获异常并调用捕获到异常的对象的value属性就可以显示return的结果了

next()函数

next()函数可以取值迭代器也可以取值生成器
迭代器: next(迭代器) 每次取值时执行迭代器__next__方法并返回给外部的next()
生成器: next(生成器) 每次取值时 yielda 的值返回给外部的 next()

send(msg)函数

send()函数只可以取值生成器
send(msg) 的过程分为2步

  • msg被传入函数内的yield a这个整体 并赋值给yield a左边的变量
  • yielda 的值返回给外部的send()

深拷贝浅拷贝

copy模块
import copy
deepcopy 可以完成深拷贝
b = copy.deepcopy(a)
copy 可以完成浅拷贝
d = copy.copy(c)

[11,22,[33,44]]
浅拷贝可变数据类型只是拷贝第一层到新的内存空间而嵌套的数据不拷贝还是仅仅是指向
深拷贝可变数据类型时是递归拷贝所有数据到一个新的内存空间
(11,22,(33,44))
当拷贝一个完全是由不可变数据类型组成的数据时 浅拷贝和深拷贝都只是拷贝引用
(11,22,[33,44])
浅拷贝一个不可变数据类型包含可变数据类型的数据时只是拷贝第一层
深拷贝一个不可变数据类型只要其中包含任何可变数据类型都会全部递归拷贝到一个新的内存空间

面相对象基础

面相过程 是以过程为中心编程思想 以什么正在发生为主要目标进行编程
面向对象 是把过程中的事物分解成各个对象并赋予对象在解决问题过程中事物的行为

面向对象的三大特点

封装 根据职责将对象的属性和方法封装到抽象的类中
继承 子类拥有父类的所有属性和方法从而实现代码的复用
多态 不同的子类的对象调用相同的父类方法产生不同的执行结果(通过重写父类方法)

面向对象的方法

dir(对象) 可以查看针对对象的所有方法和属性
print(对象) 显示对象是由哪个类创建的以及类的内存地址(前提是对象没有实现__str__方法)
id(对象) 以十进制方式显示对象的内存地址

内置方法

__doc__ 查看类内部的说明文档
​__new__ 为对象分配内存空间 return父类的new方法实现返回对象的引用为了后续传入init方法self初始化对象属性
__init__ 初始化实例对象的属性 用作定义实例属性
__del__ 对象被从内存删除时会自动调用此方法
__str__ 返回对象的描述信息 print对象时输出指定字符串 配合return返回字符串

具有相同属性或者方法的事物的统称 不能直接使用
类命名的时候要满足大坨峰命名法
被使用的类应该先开发
对象的属性可以是另一个类创建的对象 新兵的枪属性是由枪类创建的枪对象
python3.x中所有类的父类都是object
新式类:以object为基类的类
经典类:不以object为基类的类

定义类
class Human(object):
    def __new__(cls):
        return super().__new__(cls)
    def __init__(self, name):
        self.name = name
        self.age = 18
    def work(self):
        print("working")

在对象方法内部使用self.可以访问和调用对象自己的属性和方法
在初始化方法中设置对象属性 self.name = "tom"
在主程序中临时设置对象属性 实例对象.name = "tom"

对象

创建出来的一个具体存在
哪个类创建出来的对象就拥有哪个类包含的属性和方法
可以创建多个对象 多个对象的属性和方法互不干扰作用域为对象自己

创建对象的过程

man = Human("士兵") 实例化Human
__new__(cls) 为对象分配内存空间 返回对象的引用self
__init__(self, 参数....) 获取new返回的对象引用 接收外部传入的参数 为实例对象初始化属性

单继承

class 类名(父类名):
子类拥有父类所有的方法和属性
子类可以直接使用父类中已经封装好的属性和方法
子类应该继续根据职责封装子类特有的属性和方法

多继承

class 子类(父类1, 父类2,....):
多个父类有同名属性和方法 子类调用属性和方法依据 MRO方法解决顺序 执行
尽量避免多继承有同名属性和方法的父类

MRO方法解决顺序

print(类().__mro__) 查看类的方法搜索顺序

继承的传递性

子类拥有父类的属性和方法 子类的子类也拥有父类的父类的属性和方法

方法的重写

覆盖

父类的方法无法满足子类时在子类中重新定义同名方法 调用时会调用子类重写的方法不会调用原先父类的方法

扩展

在覆盖的基础上使用 super().方法()调用父类方法实现 再添加扩展内容

重写new方法
class 类(object):
    def __new__(cls):  # 定义cls变量保存类的引用
        return super(类, 类对象).__new__(cls)  # cls 表示要让哪一个对象实现此方法

返回父类的new方法实现得到当前类的实现对象的引用给cls变量 变量内容会在new执行完毕传递给当前类的self
如果返回的不是方法实现而是一个其他类创建的实例引用那么会执行其他类的init方法 不会执行当前类的init方法
super(类, 对象).init() 对象在类中的MRO列表的下一个搜索类中init的方法实现

私有属性和私有方法

通过名字重整的方式改变设置的私有属性名而达到无法直接访问私有属性或方法的目的
无法在外界直接访问 只能在类范围中访问
self.__age 私有属性
self.__secret() 私有方法
强行访问私有属性demo._Women__age
强行访问私有方法demo._Women__secret()
​子类的对象 不能在自己的方法内部 直接访问父类的私有属性或私有方法
子类的对象 可以通过继承自父类的公有方法 间接访问到父类的私有属性或私有方法
x 公有属性或方法
_x 属性或者方法 在使用import * 导入的时候不会被导入
__x 私有属性或方法 无法被继承
__x__ 内置属性或方法 可以被继承
x_ 属性或方法 用于避免名称与关键字名冲突 比如list_ = [1,2,3]

多态

调用方法的技巧 不会影响类的内部设计
通过重写扩展父类方法 以不同子类的对象 调用相同的父类方法产生不同的执行结果

实例对象

定义实例对象

obj = 类()
使用类()创建实例对象的步骤有两步:

  • 在内存中为对象分配空间
  • 调用init方法为对象初始化属性

类创建出来的对象叫做类的实例
类创建实例对象的动作叫做实例化
实例对象的属性叫做实例属性
实例对象调用的方法叫做实例方法
实例对象各自拥有自己的实例属性 保存在各自的内存中
实例方法只有一份 保存在类对象的内存中
实例对象通过self.传递引用到类对象实现自己的方法
在调用属性时把实例对象的引用传递到实例对象的内部
在调用方法时把实例对象的引用传递到类对象的内部

类对象

定义类对象

class 类(object):
类在运行时也会被加载到内存中 ==>类对象
类对象的内存中保存着实例对象的方法 方法只有一份 实例分别传递引用调用方法
除了封装实例对象的属性和方法外 类对象还可以拥有自己的类属性类方法

类属性

针对类对象定义的属性 只用来描述类对象的特征

定义类属性

count = 0
使用赋值语句在类中定义类属性

调用类属性
  • 类对象.类属性
  • 实例.类属性() 不推荐 容易混淆 实例.类属性 = value 会创建一个同名实例属性 而不会修改类属性

python中属性的获取遵循向上查找机制 如果此类中没有该类属性会向上在父类中查找
实例在调用属性时在init中找不到同名属性会到类中查找属性 但是访问的实际是类属性

类方法

针对类对象定义的方法 用来实现类对象的行为
要在类中使用类本身 就使用类方法 因为类方法的第一个参数就是类本身

定义类方法
@classmethod
def 方法名(cls):

使用装饰器@classmethod 声明这是一个类方法
类方法的第一个参数是cls
哪一个类调用的方法cls就是哪一个类的引用

调用类方法

类对象.类方法()
类方法不需要实例化类就可以通过类对象来调用

静态方法

类中封装的方法没有访问实例属性类属性的需求应该定义为静态方法

定义静态方法
@staticmethod
def 方法名():

使用修饰器@staticmethod 声明这是一个静态方法
静态方法的第一个参数不需要定义
方法内部无法访问实例属性类属性
实例方法默认第一个参数是self 类方法默认第一个参数是cls 静态方法默认没有参数

调用静态方法

类.静态方法()
静态方法不需要实例化类就可以通过类来调用该方法
特点是不需要创建对象就可以调用 高效率

定义方法的规则

实例方法---当方法内部需要访问实例属性和类属性
类方法---当方法内部只需要访问类属性
静态方法---当方法内部不需要访问实例属性和类属性

property装饰器

让一个类中的方法经过复杂计算后返回一个值并且在调用时变得简单直观
调用时直接使用对象.方法名 而不使用对象.方法()
调用一个方法像调用一个属性一样 并且property装饰器让方法在调用时避免了是否要传参的疑问
新式类property装饰器有三种分别get setdel
@property本身又会创建其他的装饰器@xxx.setter @xxx.deleter
@property 用于get返回的值 通过对象.方法名 get
@xxx.setter 用于set变量的值 通过对象.方法名 = num set
@xxx.deleter 用于del设置的变量 通过 del 对象.方法名 del

class Goods(object):
    def __init__(self):
        self.original_price = 100
        self.discount = 0.8
    @property
    def price(self):
        new_price = self.original_price * self.discount
        return new_price
    @price.setter
    def price(self, value):
        self.original_price = value
    @price.deleter
    def price(self):
        del self.original_price
obj = Goods()
obj.price  # get价格
obj.price = 200  # set价格
del obj.price  # 删除商品价格
通过类属性设置property

在类中property()函数设置property属性 返回一个property对象
类属性BARBAR = property(fget=None, fset=None, fdel=None, doc=None)
property函数有四个参数
第一个参数填入方法名 调用obj.BAR 时自动调用fset设置的方法
第二个参数填入方法名 调用obj.BAR = xxx 时自动调用fset设置的方法将xxx传入第二个参数
第三个参数填入方法名 调用del obj.BAR 时自动调用fdel方法
第四个参数填入字符串 Foo.BAR.__doc__ 返回一个字符串对象

class Foo():
    def get_bar(self):
        bar = "python"
        return bar
    def set_bar(self, value):
        bar = value
        return bar
    def del_bar(self):
        del bar
    BAR = property(get_bar, set_bar, del_bar, "description..")
obj = Foo()
obj.BAR  # 调用property参数(将get_bar方法变为了property属性)
obj.BAR = "World"  # 调用第二个参数
del obj.BAR  # 调用第三个参数
desc = Foo.BAR.__doc__  # 获取第四个参数中设置的字符串
print(desc)

单例模式

让类创建的对象只有一个实例 对象的内存地址每次返回都是相同的

super()类

super()调用父类方法实现的方式区别于直接使用父类名调用父类方法
通过C3算法的结果保存在MRO中 通过MRO顺序可以避免钻石问题时实现一个父类方法会多次调用多继承的父类方法实现
C3算法避免了多继承时子类多次调用父类方法实现
super().__init__(参数1,参数2,*args,**kwargs) 避免多继承报错 可以使用不定长参数接收参数

定义单例模式
class 类(object):
    i = None  # 设置空对象
    def __new__(cls):  # 实例化类时首先读取这行代码
        if cls.i is None:
            cls.i = super().__new__(cls)
            return cls.i
        return cls.i
单次初始化
class 类(object):
    init_flag = False  # 创建类属性初始设置为False
    def __init__(self):
        if 类.init_flag is False:
        .........
        类.init_flag = True  # 当init执行后更改类属性值为True
        return

创建类属性init_flag 标记是否执行过初始化动作

异常

解释器遇到错误会停止并提示错误信息
提示错误信息的动作叫做抛出raise异常
错误信息的第一个单词是错误类型

捕获异常基本语法
try:
    pass
except:
    pass
捕获类型异常
try:
    pass
except 错误类型:
    pass
捕获未知异常

Exception 是一个错误的基类
except Exception 可以捕获所有预想到的异常以外的异常
except Exception as 变量: 把捕获到的异常赋值给as后的变量

try:
    pass
except Exception as 变量:
    print(变量)
捕获异常的完整语法

try语法中只有except才会捕获异常 被捕获的异常不会继续传递 finally不会终止传递异常
上下文管理器exit方法类似于finally虽然会执行一些代码 但是不会捕获异常

try:
    pass  # 尝试的代码
except:
    pass  # 有异常会执行的代码
except 错误类型1:
    pass  # 有错误类型1会执行的代码
except (错误类型2, 错误类型3):
    pass  # 有错误类型2 或 错误类型3 会执行的代码
except Exception as 变量:  # 以上捕获异常都没有预料到的异常会在捕获未知异常里被捕获
    print(变量)  # 有未知异常时会执行的代码 打印错误信息
else:
    pass  # 尝试的代码没有异常会执行的代码
finally:
    pass  # 无论有没有异常都会执行的代码
异常的传递

函数方法出现错误 会将异常传递给 函数方法的调用一方 当异常传递到主程序时仍没有处理异常 程序才会终止
为保证函数方法中的代码简洁 一般在主程序中捕获异常

主动抛出raise异常

针对特有的业务需求主动抛出异常 再由其他专门捕获异常的程序处理异常

  • 函数中以条件抛出异常:
def xxx():
    if (条件)xxx:  # 设置当达到某个条件后就是异常
        ex = Exception("自定义异常信息")  # 创建异常包含此错误信息的异常
        raise ex  # 抛出异常
    return xxx # 抛出异常后不会执行后续代码 如果没有异常return正常结果
  • 捕获异常:
try:
    xxx() # 内部抛出了异常 还需要捕获
except Exception as 变量:  # 捕获xxx()传递的未知异常
    print(变量)  # 打印自定义异常信息

模块

导入模块
import 模块1
import 模块2  # (PEP8)
import 模块1, 模块2  # (不推荐使用)

如果变量中存储了模块名 直接使用import导入的是变量名.py 此时需要使用__import__()来导入
__import__(变量名)返回一个对象 这个对象就是模块的引用
使用getattr(obj, name[, default])函数 返回一个对象的属性值
obj -- 对象。
name -- 字符串,对象属性。 name 只是名字 而返回值 是这个属性的引用
default -- 默认返回值,如果不提供该参数,在没有对应属性时,将触发 AttributeError。

module_ = ___import___(变量名)
method_ = getattr(module_, name)
导入模块时的顺序

1.官方标准模块
2.第三方模块
3.应用程序模块
首先从当前目录下搜索要导入的模块 再从系统目录搜索要导入的内置模块
模块.__file__ 内置属性 可以查看模块的完整路径
sys模块中sys.path 是一个列表其中的顺序表示导入模块时搜索模块的顺序
使用列表的sys.path.insert(0, "./")来插入一个新模块包路径
使用sys.path.append("/") 来追加一个路径
程序在执行期间对程序导入过的模块的修改不会生效
需要在程序中使用 imp模块中的reload()方法来重新加载修改过的模块reload(模块)

导入一个模块的两个步骤 定义一个common的变量 common指向一个模块中的文件

from common import A
import common

common.A = 1
A = 1

这两种方式的区别在于
common.A = 1会修改commonA的值为1
A = 1让一个变量A指向1

调用模块中的工具
模块.全局变量
模块.函数()
obj = 模块.类()
指定模块的别名
import 模块 as 模块别名

模块别名要满足大驼峰命名法
有重名冲突的导入时使用as 设置模块别名

导入部分工具
from 模块 import 工具

导入模块的指定工具 调用时直接使用导入的工具名

from 模块 import *

导入所有工具 调用时直接使用模块内的工具名
使用import导入多个同名模块会执行后导入的模块内容

模块测试代码

模块被导入时所有没有缩进的代码都会被执行
模块.__name__ 内置属性 可以输出模块名 如果在模块内部调用会输出__main__
在其他文件中执行输出模块名

if __name__ == "__main__":

判断__name__被执行时是不是输出__main__来决定是否输出下方测试代码

包(Package)

包含多个模块的特殊目录
包文件夹命名时遵循变量命名规则
import 包 可以导入包中所有的模块
在包目录下创建__init__.py 对外界提供包内模块的列表
__init__.py

from ./ import 模块1
from ./ import 模块2
发布模块

在包的同级目录下创建 setup.py
setup.py

from distutils.core import setup
setup(name="st_message",  # 包名
    version="1.0",  # 版本号
    description="发送和接收消息模块",  # 描述信息
    long_description="完整的发送和接收消息模块",  # 完整描述信息
    author="lee",  # 作者
    author_email="lee@lee.com",  # 作者邮箱
    url="lee.com",  # 主页
    py_modules=[
        "st_message.send_message",
        "st_message.receive_message"
    ])
构建模块
$ python3 setup.py build

会构建出需要打包发布的文件

生成发布压缩包
$ python3 setup.py sdist

会打包构建出的文件 使用不同解释器打包不同版本的发布压缩包

安装模块
$ tar -zxvf st_message.tar.gz
$ sudo python3 setup.py install
卸载模块
$ sudo rm -r /usr/local/lib/python3.7/dist-package/st_message*
安装python3第三方模块

pip3 是用来安装python3第三方模块的工具

$sudo pip3 install pygame  # 安装模块
$sudo pip3 uninstall pygame  # 卸载模块
$pip3 list  # 查看安装的所有包
$pip3 freeze  # 查看安装的所有包并显示版本号 用于迁移
$pip3 install django==1.8.2  # 指定包的版本

虚拟环境

安装虚拟环境插件

真实python环境的复制版本 只有Python的环境被复制

$sudo pip3 install virtualenv  安装虚拟环境
$sudo pip3 install virtualenvwrapper 安装虚拟环境扩展包 用于简化虚拟环境的使用
配置插件

编辑.bashrc 环境变量文件

export WORKON_HOME=$HOME/.virtualenvs  # 设置虚拟环境文件位置
export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3  # 设置python位置
export VIRTUALENVWRAPPER_VIRTUALENV=/usr/local/bin/virtualenv  # 设置virtualenv位置
source /usr/local/bin/virtualenvwrapper.sh  # 加载virtualenvwrapper插件

运行source .bashrc 重新加载.bashrc文件使设置生效

创建虚拟环境
$mkvirtualenv -p python3 环境名  # 创建python3虚拟环境
删除虚拟环境
$rmvirtualenv 环境名  # 删除指定虚拟环境
查看所有虚拟环境
$lsvirtualenv  # 显示所有虚拟环境
切换虚拟环境
$workon 环境名  # 切换虚拟环境
退出虚拟环境
$deactivate  # 退出虚拟环境

注意: 在虚拟环境中不能使用sudo来安装 使用sudo pip安装 会安装到真实python环境

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

推荐阅读更多精彩内容

  • http://python.jobbole.com/85231/ 关于专业技能写完项目接着写写一名3年工作经验的J...
    燕京博士阅读 7,540评论 1 118
  • 一、python 变量和数据类型 1.整数 Python可以处理任意大小的整数,当然包括负整数,在Python程序...
    绩重KF阅读 1,609评论 0 1
  • 最近在慕课网学习廖雪峰老师的Python进阶课程,做笔记总结一下重点。 基本变量及其类型 变量 在Python中,...
    victorsungo阅读 1,652评论 0 5
  • 时间限制:1秒 空间限制:32768K 题目描述 LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大...
    cherryleechen阅读 274评论 0 0
  • 我的童年是星星火炬照耀下的童年。 回望童年,充满童真。 童真代表纯洁,...
    冰夫阅读 178评论 0 0