《Python指南》学习笔记 一
更新时间:2018-06-14
《Python指南》原文在这里。本篇笔记主要是划重点。
Python 3.6.3
1、简单入门
1.1 编码
默认情况下,Python 源文件是 UTF-8 编码。
你也可以为源文件指定不同的字符编码。
# -*- coding: encoding -*-
1.2 注释
Python 中的注释以 #
字符起始,直至实际的行尾。类似java的//
单行注释
1.3 算术运算
整数的类型是int
,浮点数的类型是float
。整数和浮点数的混合计算中,整数会被转换为浮点数。
除法(/
)永远返回一个浮点数。
floor除法(//
)并且得到整数结果(丢掉任何小数部分)。
%
用来计算余数。
**
运算符计算幂乘方。
5 ** 2 # 5的2次方,结果是25
变量在使用前必须 “定义”(赋值)。
除了 int
和 float
,Python 还支持其它数字类型,例如 Decimal
和 Fraction
。
1.4 字符串
Python提供了几种不同方式表示的字符串。它们可以用单引号 ('...'
) 或双引号 ("..."
) 标识。\
可以用来转义引号。
当字符中带有\
时可能会出现错误,例如\n
会换行。你可以使用 原始字符串,方法是在第一个引号前面加上一个 r
>>> print(r'C:\some\name')
C:\some\name
字符串文本能够分成多行。一种方法是使用三引号:"""..."""
或者 '''...'''
。
行尾换行符会被自动包含到字符串中,但是可以在行尾加上 \
来避免这个行为。下面的示例: 可以使用反斜杠为行结尾的连续字符串,它表示下一行在逻辑上是本行的后续内容:
print("""\
Usage: thingy [OPTIONS]
-h Display this usage message
-H hostname Hostname to connect to
""")
将输出以下内容:
Usage: thingy [OPTIONS]
-h Display this usage message
-H hostname Hostname to connect to
字符串可以由 +
操作符连接(粘到一起),可以由 *
表示重复:
>>> 3 * 'un' + 'ium'
'unununium'
相邻的两个字符串文本自动连接在一起:
>>> 'Py' 'thon'
'Python'
它只用于两个字符串文本,不能用于字符串表达式:
>>> prefix = 'Py'
>>> prefix 'thon'
...
SyntaxError: invalid syntax
>>> ('un' * 3) 'ium'
...
SyntaxError: invalid syntax
字符串也可以被截取(检索)。字符串的第一个字符索引为 0 。Python没有单独的字符类型;一个字符就是一个简单的长度为1的字符串。:
>>> word = 'Python'
>>> word[0] # 获取索引为0的字符
'P'
索引也可以是负数,这将导致从右边开始计算。例如:
>>> word = 'Python'
>>> word[-1]
'n'
请注意 -0 实际上就是 0。
除了索引,还支持 切片。索引用于获得单个字符,切片 让你获得一个子字符串:
>>> word = 'Python'
>>> word[0:2] # 截取索引从0开始到1(2的前一位)的字符串
'Py'
切片的索引有非常有用的默认值;省略的第一个索引默认为零,省略的第二个索引默认为切片的字符串的大小。
>>> word = 'Python'
>>> word[:2]
'Py'
>>> word[4:]
'on'
试图使用太大的索引会导致错误:
IndexError: string index out of range
Python 能够优雅地处理那些没有意义的切片索引:一个过大的索引值(即下标值大于字符串实际长度)将被字符串实际长度所代替,当上边界比下边界大时(即切片左值大于右值)就返回空字符串。
>>> word = 'Python'
>>> word[4:42]
'on'
>>> word[42:]
''
Python字符串不可以被更改 — 它们是不可变的。因此,赋值给字符串索引的位置会导致错误:
>>> word[0] = 'J'
...
TypeError: 'str' object does not support item assignment
内置函数 len() 返回字符串长度:
>>> s = 'supercalifragilisticexpialidoc'
>>> len(s)
30
1.5 列表(list)
Python 有几个复合数据类型,用于表示其它的值。最通用的是list,它可以写作中括号之间的一列逗号分隔的值。列表的元素不必是同一类型。
>>> squares = [1, 4, 9, 16, 25]
>>> squares
[1, 4, 9, 16, 25]
就像字符串(以及其它所有内建的 序列 类型)一样,列表可以被索引和切片:
>>> squares[0]
1
>>> squares[-1]
25
>>> squares[-3:] # 切片返回一个新list(浅拷贝)
[9, 16, 25]
列表也支持连接这样的操作:
>>> squares + [36, 49, 64, 81, 100]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
你还可以使用 append()
方法在列表的末尾添加新的元素:
>>> cubes = [1, 8, 27, 65, 125]
>>> cubes.append(216)
>>> cubes.append(7 ** 3)
>>> cubes
[1, 8, 27, 64, 125, 216, 343]
也可以对切片赋值,此操作可以改变列表的尺寸,或清空它:
>>> letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> letters[2:5] = ['C', 'D', 'E']
>>> letters
['a', 'b', 'C', 'D', 'E', 'f', 'g']
>>> letters[2:5] = []
>>> letters
['a', 'b', 'f', 'g']
>>> # 清空list
>>> letters[:] = []
>>> letters
[]
内置函数 len()
同样适用于列表:
>>> letters = ['a', 'b', 'c', 'd']
>>> len(letters)
4
允许嵌套列表:
>>> a = ['a', 'b', 'c']
>>> n = [1, 2, 3]
>>> x = [a, n]
>>> x
[['a', 'b', 'c'], [1, 2, 3]]
>>> x[0]
['a', 'b', 'c']
>>> x[0][1]
'b'
1.6 更复杂的例子
例如,我们可以写一个生成菲波那契子序列的程序,如下所示:
>>> # Fibonacci series:
... a, b = 0, 1
>>> while b < 10:
... print(b)
... a, b = b, a+b
这个例子介绍了几个新功能。
- 第一行包括了一个 多重赋值:变量
a
和b
同时获得了新的值 0 和 1 最后一行又使用了一次。 - 条件(这里是
b < 10
)为true
时,while
循环执行。在 Python 中,类似于 C,任何非零整数都是true
;0 是false
。条件也可以是字符串或列表,实际上可以是任何序列;所有长度不为零的是true
,空序列是false
。 - 循环体是缩进的:缩进是 Python 组织语句的方法。Python (还)不提供集成的行编辑功能,所以你要为每一个缩进行输入
TAB
或空格。 - 交互式录入复合语句时,必须在最后输入一个空行来标识结束(因为解释器没办法猜测你输入的哪一行是最后一行),需要 注意的是同一个语句块中的每一行必须缩进同样数量的空白。
- 关键字 print() 语句输出给定表达式的值。
用一个逗号结尾就可以禁止输出换行:
>>> a, b = 0, 1
>>> while b < 1000:
... print(b, end=',')
... a, b = b, a+b
...
1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,
2、深入 Python 流程控制
2.1 if 语句
>>> x = int(input("Please enter an integer: "))
Please enter an integer: 42
>>> if x < 0:
... x = 0
... print('Negative changed to zero')
... elif x == 0:
... print('Zero')
... elif x == 1:
... print('Single')
... else:
... print('More')
可能会有零到多个 elif
部分,else
是可选的。
2.2 for 语句
Python 的 for 语句可以依据任意序列(链表或字符串)中的子项,按它们在序列中的顺序来进行迭代。
>>> # Measure some strings:
... words = ['cat', 'window', 'defenestrate']
>>> for w in words:
... print(w, len(w))
...
cat 3
window 6
defenestrate 12
在迭代过程中修改迭代序列不安全(只有在使用链表这样的可变序列时才会有这样的情况)。如果你想要修改你迭代的序列(例如,复制选择项),你可以迭代它的复本。使用切割标识就可以很方便的做到这一点:
>>> for w in words[:]: # 循环一个完整的 list副本
... if len(w) > 6:
... words.insert(0, w)
...
>>> words
['defenestrate', 'cat', 'window', 'defenestrate']
2.3. range() 函数
如果你需要一个数值序列,内置函数 range()
会很方便,它生成一个等差级数链表:
>>> for i in range(5):
... print(i)
...
0
1
2
3
4
range(10)
生成了一个包含 10 个值的链表,它用链表的索引值填充了这个长度为 10 的列表,所生成的链表中不包括范围中的结束值。也可以让 range()
操作从另一个数值开始,或者可以指定一个不同的步进值(甚至是负数,有时这也被称为 “步长”):
range(5, 10)
5 到 9
range(0, 10, 3)// (从几开始,到几,每次增加多少)
0, 3, 6, 9
range(-10, -100, -30)
-10, -40, -70
需要迭代链表索引的话,如下所示结合使 用 range()
和 len()
:
>>> a = ['Mary', 'had', 'a', 'little', 'lamb']
>>> for i in range(len(a)):
... print(i, a[i])
...
0 Mary
1 had
2 a
3 little
4 lamb
不过,这种场合可以方便的使用 enumerate()
:
>>> for i, v in enumerate(['tic', 'tac', 'toe']):
... print(i, v)
...
0 tic
1 tac
2 toe
如果你只是打印一个序列的话会发生奇怪的事情:
>>> print(range(10))
range(0, 10)
在不同方面 range()
函数返回的对象表现为它是一个列表,但事实上它并不是。当你迭代它时,它是一个能够像期望的序列返回连续项的对象;但为了节省空间,它并不真正构造列表。
我们称此类对象是 可迭代的,即适合作为那些期望从某些东西中获得连续项直到结束的函数或结构的一个目标(参数)。我们已经见过的 for
语句就是这样一个迭代器。list()
函数是另外一个( 迭代器 ),它从可迭代(对象)中创建列表:
>>> list(range(5))
[0, 1, 2, 3, 4]
2.4. break 和 continue 语句, 以及循环中的 else 子句
循环可以有一个 else
子句;它在循环迭代完整个列表(对于 for )或执行条件为 false
(对于 while
)时执行,但循环被 break
中止的情况下不会执行。以下搜索素数的示例程序演示了这个子句:
>>> for n in range(2, 10):
... for x in range(2, n):
... if n % x == 0:
... print(n, 'equals', x, '*', n//x)
... break
... else:
... # loop fell through without finding a factor
... print(n, 'is a prime number')
...
2 is a prime number
3 is a prime number
4 equals 2 * 2
5 is a prime number
6 equals 2 * 3
7 is a prime number
8 equals 2 * 4
9 equals 3 * 3
2.5. pass 语句
pass
语句什么也不做。它用于那些语法上必须要有什么语句,但程序什么也不做的场合,例如:
>>> while True:
... pass # Busy-wait for keyboard interrupt (Ctrl+C)
...
2.6. 定义函数
我们可以创建一个用来生成指定边界的斐波那契数列的函数:
>>> def fib(n):
... """Print a Fibonacci series up to n."""
... a, b = 0, 1
... while a < n:
... print(a, end=' ')
... a, b = b, a+b
... print()
...
>>> # Now call the function we just defined:
... fib(2000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
关键字 def
引入了一个函数 定义。在其后必须跟有函数名和包括形式参数的圆括号。函数体语句从下一行开始,必须是缩进的。
函数体的第一行语句可以是可选的字符串文本,这个字符串是函数的文档字符串,或者称为 docstring。在你的代码中包含 docstrings 是一个好的实践,让它成为习惯吧。
函数 调用 会为函数局部变量生成一个新的符号表。确切的说,所有函数中的变量赋值都是将值存储在局部符号表。变量引用首先在局部符号表中查找,然后是包含函数的局部符号表,然后是全局符号表,最后是内置名字表。因此,全局变量不能在函数中直接赋值(除非用 global 语句命名),尽管他们可以被引用。
函数引用的实际参数在函数调用时引入局部符号表,因此,实参总是 传值调用 (这里的 值 总是一个对象 引用 ,而不是该对象的值)。[1] 一个函数被另一个函数调用时,一个新的局部符号表在调用过程中被创建。
一个函数定义会在当前符号表内引入函数名。函数名指代的值(即函数体)有一个被 Python 解释器认定为 用户自定义函数 的类型。 这个值可以赋予其他的名字(即变量名),然后它也可以被当做函数使用。这可以作为通用的重命名机制:
>>> fib
<function fib at 10042ed0>
>>> f = fib
>>> f(100)
0 1 1 2 3 5 8 13 21 34 55 89
如果你使用过其他语言,你可能会反对说:fib 不是一个函数,而是一个方法,因为它并不返回任何值。事实上,没有 return
语句的函数确实会返回一个值,虽然是一个相当令人厌烦的值(指 None )。这个值被称为 None
(这是一个内建名称)。如果 None
值是唯一被书写的值,那么在写的时候通常会被解释器忽略(即不输出任何内容)。如果你确实想看到这个值的输出内容,请使用 print()
函数:
>>> fib(0)
>>> print(fib(0))
None
定义一个返回斐波那契数列数字列表的函数,而不是打印它,是很简单的:
>>> def fib2(n):
... """Return a list containing the Fibonacci series up to n."""
... result = []
... a, b = 0, 1
... while a < n:
... result.append(a)
... a, b = b, a+b
... return result
...
>>> f100 = fib2(100)
>>> f100
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
return
语句从函数中返回一个值,不带表达式的 return
返回 None
。
2.7. 深入 Python 函数定义
2.7.1. 默认参数值
最常用的一种形式是为一个或多个参数指定默认值。再使用时有默认值的参数就可以不传。
def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
while True:
ok = input(prompt)
if ok in ('y', 'ye', 'yes'):
return True
if ok in ('n', 'no', 'nop', 'nope'):
return False
retries = retries - 1
if retries < 0:
raise OSError('uncooperative user')
print(complaint)
这个函数可以通过几种不同的方式调用:
只给出必要的参数:
ask_ok('Do you really want to quit?')
给出一个可选的参数:
ask_ok('OK to overwrite the file?', 2)
或者给出所有的参数:
ask_ok('OK to overwrite the file?', 2, 'Come on, only yes or no!')
这个例子还介绍了 in
关键字。它测定序列中是否包含某个确定的值。
默认值在函数 定义 作用域被解析,如下所示:
i = 5
def f(arg=i):
print(arg)
i = 6
f()
将会输出 5。
重要警告: 默认值只被赋值一次。当默认值是可变对象时会有所不同,比如列表、字典或者大多数类的实例。例如,下面的函数在后续调用过程中会累积(前面)传给它的参数:
def f(a, L=[]):
L.append(a)
return L
print(f(1))
print(f(2))
print(f(3))
这将会输出:
[1]
[1, 2]
[1, 2, 3]
如果你不想让默认值在后续调用中累积,你可以像下面一样定义函数:
def f(a, L=None):
if L is None:
L = []
L.append(a)
return L
2.7.2. 关键字参数
函数可以通过 关键字参数 的形式来调用,形如 keyword = value。例如,以下的函数:
def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
print("-- This parrot wouldn't", action, end=' ')
print("if you put", voltage, "volts through it.")
print("-- Lovely plumage, the", type)
print("-- It's", state, "!")
接受一个必选参数 (voltage) 以及三个可选参数 (state, action, 和 type)。可以用以下的任一方法调用:
parrot(1000)
parrot(voltage=1000)
parrot(voltage=1000000, action='VOOOOOM')
parrot(action='VOOOOOM', voltage=1000000)
parrot('a million', 'bereft of life', 'jump')
parrot('a thousand', state='pushing up the daisies')
任何参数都不可以多次赋值。下面的示例由于这种限制将失败:
>>> def function(a):
... pass
...
>>> function(0, a=0)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: function() got multiple values for keyword argument 'a'
引入一个形如 **name
的参数时,它接收一个字典(参见 Mapping Types — dict ),该字典包含了所有未出现在形式参数列表中的关键字参数。这里可能还会组合使用一个形如 *name
(下一小节详细介绍) 的形式参数,它接收一个元组(下一节中会详细介绍),包含了所有没有出现在形式参数列表中的参数值( *name
必须在 **name
之前出现)。 例如,我们这样定义一个函数:
def cheeseshop(kind, *arguments, **keywords):
print("-- Do you have any", kind, "?")
print("-- I'm sorry, we're all out of", kind)
for arg in arguments:
print(arg)
print("-" * 40)
keys = sorted(keywords.keys())
for kw in keys:
print(kw, ":", keywords[kw])
它可以像这样调用:
cheeseshop("Limburger", "It's very runny, sir.",
"It's really very, VERY runny, sir.",
shopkeeper="Michael Palin",
client="John Cleese",
sketch="Cheese Shop Sketch")
当然它会按如下内容打印:
-- Do you have any Limburger ?
-- I'm sorry, we're all out of Limburger
It's very runny, sir.
It's really very, VERY runny, sir.
----------------------------------------
client : John Cleese
shopkeeper : Michael Palin
sketch : Cheese Shop Sketch
注意在打印关键字参数之前,通过对关键字字典 keys()
方法的结果进行排序,生成了关键字参数名的列表;如果不这样做,打印出来的参数的顺序是未定义的。
2.7.3. 参数列表的分拆
当你要传递的参数已经是一个列表,但要调用的函数却接受分开一个个的参数值。这时候你要把已有的列表拆开来。例如内建函数 range()
需要要独立的 start,stop 参数。你可以在调用函数时加一个 *
操作符来自动把参数列表拆开:
>>> list(range(3, 6)) # 直接使用独立参数
[3, 4, 5]
>>> args = [3, 6]
>>> list(range(*args)) # 从一个list里拆分参数
[3, 4, 5]
以同样的方式,可以使用 **
操作符分拆关键字参数为字典:
>>> def parrot(voltage, state='a stiff', action='voom'):
... print("-- This parrot wouldn't", action, end=' ')
... print("if you put", voltage, "volts through it.", end=' ')
... print("E's", state, "!")
...
>>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"}
>>> parrot(**d)
-- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised !
2.7.4. Lambda 形式
通过 lambda 关键字,可以创建短小的匿名函数。这里有一个函数返回它的两个参数的和: lambda a, b: a+b
。 Lambda 形式可以用于任何需要的函数对象。出于语法限制,它们只能有一个单独的表达式。语义上讲,它们只是普通函数定义中的一个语法技巧。类似于嵌套函数定义,lambda 形式可以从外部作用域引用变量:
>>> def make_incrementor(n):
... return lambda x: x + n
...
>>> f = make_incrementor(42)
>>> f(0)
42
>>> f(1)
43
2.8. 编码风格
1.使用 4 空格缩进,而非 TAB
在小缩进(可以嵌套更深)和大缩进(更易读)之间,4空格是一个很好的折中。TAB 引发了一些混乱,最好弃用
2.折行以确保其不会超过 79 个字符
这有助于小显示器用户阅读,也可以让大显示器能并排显示几个代码文件
3.使用空行分隔函数和类,以及函数中的大块代码
4.可能的话,注释独占一行
5.统一函数和类命名
推荐类名用 驼峰命名, 函数和方法名用 小写和_下划线。总是用
self` 作为方法的第一个参数
《Python指南》学习笔记 一的更多相关文章
- 《Hadoop》大数据技术开发实战学习笔记(二)
搭建Hadoop 2.x分布式集群 1.Hadoop集群角色分配 2.上传Hadoop并解压 在centos01中,将安装文件上传到/opt/softwares/目录,然后解压安装文件到/opt/mo ...
- 《Hadoop大数据技术开发实战》学习笔记(一)
基于CentOS7系统 新建用户 1.使用"su-"命令切换到root用户,然后执行命令: adduser zonkidd 2.执行以下命令,设置用户zonkidd的密码: pas ...
- 超人学院Hadoop大数据技术资源分享
超人学院Hadoop大数据技术资源分享 http://bbs.superwu.cn/forum.php?mod=viewthread&tid=807&fromuid=645 很多其它精 ...
- java大数据最全课程学习笔记(1)--Hadoop简介和安装及伪分布式
Hadoop简介和安装及伪分布式 大数据概念 大数据概论 大数据(Big Data): 指无法在一定时间范围内用常规软件工具进行捕捉,管理和处理的数据集合,是需要新处理模式才能具有更强的决策力,洞察发 ...
- hadoop大数据技术架构详解
大数据的时代已经来了,信息的爆炸式增长使得越来越多的行业面临这大量数据需要存储和分析的挑战.Hadoop作为一个开源的分布式并行处理平台,以其高拓展.高效率.高可靠等优点越来越受到欢迎.这同时也带动了 ...
- 除Hadoop大数据技术外,还需了解的九大技术
除Hadoop外的9个大数据技术: 1.Apache Flink 2.Apache Samza 3.Google Cloud Data Flow 4.StreamSets 5.Tensor Flow ...
- 大数据技术之_09_Flume学习_Flume概述+Flume快速入门+Flume企业开发案例+Flume监控之Ganglia+Flume高级之自定义MySQLSource+Flume企业真实面试题(重点)
第1章 Flume概述1.1 Flume定义1.2 Flume组成架构1.2.1 Agent1.2.2 Source1.2.3 Channel1.2.4 Sink1.2.5 Event1.3 Flum ...
- 大数据技术之_19_Spark学习_01_Spark 基础解析 + Spark 概述 + Spark 集群安装 + 执行 Spark 程序
第1章 Spark 概述1.1 什么是 Spark1.2 Spark 特点1.3 Spark 的用户和用途第2章 Spark 集群安装2.1 集群角色2.2 机器准备2.3 下载 Spark 安装包2 ...
- 大数据技术之_16_Scala学习_01_Scala 语言概述
第一章 Scala 语言概述1.1 why is Scala 语言?1.2 Scala 语言诞生小故事1.3 Scala 和 Java 以及 jvm 的关系分析图1.4 Scala 语言的特点1.5 ...
- 大数据技术之_16_Scala学习_04_函数式编程-基础+面向对象编程-基础
第五章 函数式编程-基础5.1 函数式编程内容说明5.1.1 函数式编程内容5.1.2 函数式编程授课顺序5.2 函数式编程介绍5.2.1 几个概念的说明5.2.2 方法.函数.函数式编程和面向对象编 ...
随机推荐
- 详解shuffle过程(转载)
http://langyu.iteye.com/blog/992916 shuffle本意是洗牌的意思.在mapreduce中描述的是怎么将map task 的输出结果有效的传送到reduce tas ...
- kmp java implement--转
http://cs.nyu.edu/~yap/classes/basic/progs/patternMatching/KMP.java /** * @file KMP.java * @synopsis ...
- 数据库索引--------B/B+树、聚集、非聚集、符合索引
摘录自博客:http://www.cnblogs.com/morvenhuang/archive/2009/03/30/1425534.html 一.引言 对数据库索引的关注从未淡出我的们的讨论,那么 ...
- 非科班双非本科投的337家Java后台(励志)
考试结束,班级平均分只拿到了年级第二,班主任于是问道:大家都知道世界第一高峰珠穆朗玛峰,有人知道世界第二高峰是什么吗?正当班主任要继续发话,只听到角落默默想起来一个声音:”乔戈里峰” 前言 文章出自h ...
- JAVA-3NIO之Buffer和Buffer之Scatter/Gather
注意:转载自并发编程网,java nio系列教程 1.Buffer Java NIO中的Buffer用于和NIO通道进行交互.如你所知,数据是从通道读入缓冲区,从缓冲区写入到通道中的. 缓冲区本质上是 ...
- [转]WxEmojiView
本文转自:https://github.com/icindy/WxEmojiView 来源信息 author: Di (微信小程序开发工程师) organization: WeAppDev(微信小程序 ...
- [转]jquerUI Dialog中隐藏标题栏的关闭"X"按钮
本文转自:http://blog.chinaunix.net/uid-144593-id-2804206.html 方法1. 在CSS文件中添加如下样式既可 .ui-dialog-titlebar-c ...
- 使用 csc.exe 编译C#代码
csc.exe是C#的编译器,可以将C#代码编译为IL中间语言代码(exe.dll),然后再通过.net framework中的clr内的JIT(即时编译器)将中间语言代码编译为机器语言,然后再由机器 ...
- 初识JSP,第一天
1.什么JSP java Server Page java 服务端的页面,它和servlet 一样可以提供动态的html 响应. 不同的是 servlet 以 java 代码 为主 jsp 以html ...
- SqlServer常用语句
首先,写这个的原因是我其实sql语句不太行,总觉得自己写得很乱,好像也没有系统学习过,借此复习和与大家探讨 No.1 关于查询时间区间是否重叠的sql语句 问题是这样:插入之前,想查询同User是否其 ...