Python基础学习

263 阅读14分钟

在Python的学习过程中,总会断断续续遇到一些比较重要、或者容易遗忘的知识点,需要在笔头记忆,时常翻阅,温故知新。

1、关于转义:

Python允许用r''表示''内部的字符串默认不转义。

>>> print('\\\t\\')
\       \
>>> print(r'\\\t\\')
\\\t\\
2、关于换行:

Python允许用'''...'''的格式表示多行内容。

>>> print('''line1
... line2
... line3''')
line1
line2
line3
3、关于空值:

空值是Python里一个特殊的值,用None表示。None不能理解为0,因为0是有意义的,而None是一个特殊的空值。

4、关于极小(大)值:

注意:Python的整数没有大小限制,而某些语言的整数根据其存储长度是有大小限制的,例如Java对32位整数的范围限制在-2147483648-2147483647。Python的浮点数也没有大小限制,但是超出一定范围就直接表示为inf

5、关于list获取元素:

如果要取最后一个元素,除了计算索引位置外,还可以用-1做索引,直接获取最后一个元素:

>>>classmates[-1]
'Tracy'

以此类推,可以获取倒数第2个、倒数第3个:

>>>classmates[-2]
'Bob'
>>>classmates[-3]
'Michael'
6、关于一个元素的tuple:

只有1个元素的tuple定义时必须加一个逗号,,来消除歧义:

>>> t = (1,)
>>> t
(1,)
7、注意tuple不可变,但是仅指tuple指向的元素地址不可变:
>>> t = ('a', 'b', ['A', 'B'])
>>> t[2][0] = 'X'
>>> t[2][1] = 'Y'
>>> t
('a', 'b', ['X', 'Y'])
8、函数默认参数:
  • 必选参数在前,默认参数在后.
  • 定义默认参数要牢记一点:默认参数必须指向不变对象!
  • 要注意定义可变参数和关键字参数的语法:args是可变参数,args接收的是一个tuple;**kw是关键字参数,kw接收的是一个dict。使用args和**kw是Python的习惯写法,当然也可以用其他参数名,但最好使用习惯用法。 详情了解
9、Python的整数没有大小限制:

但是某些语言的整数根据其存储长度是有大小限制的,例如Java对32位整数的范围限制在-2147483648-2147483647

10、现在计算机系统通用的字符编码工作方式:

在计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为UTF-8编码。用记事本编辑的时候,从文件读取的UTF-8字符被转换为Unicode字符到内存里,编辑完成后,保存的时候再把Unicode转换为UTF-8保存到文件。

11、关于tuple:
  • tuple一旦初始化就不能修改,不可变的tuple意义在于:因为tuple不可变,所以代码更安全。如果可能,能用tuple代替list就尽量用tuple。

  • Python在显示只有1个元素的tuple时,也会加一个逗号,,以免你误解成数学计算意义上的括号,来消除歧义:

>>> t = (1,)
>>> t
(1,)
  • tuple的“可变性”:
>>> t = ('a', 'b', ['A', 'B'])
>>> t[2][0] = 'X'
>>> t[2][1] = 'Y'
>>> t
('a', 'b', ['X', 'Y'])
12、eval()函数:

含义:eval() 函数用来执行一个字符串表达式,并返回表达式的值。

语法:eval(expression[, globals[, locals]])

# 示例1
>>> b = eval('{"a":1}')
>>> b
{'a': 1}
>>> print(type(b))
<class 'dict'>

# 示例2
>>> b = eval('3*3')
>>> b
9
13、如果有必要,可以先对参数的数据类型做检查;函数可以同时返回多个值,但其实就是一个tuple。
14、函数中定义默认参数要牢记一点:默认参数必须指向不变对象!
def add_end(L=[]):
    L.append('END')
    return L

>>> add_end()
['END', 'END']
>>> add_end()
['END', 'END', 'END']

原因解释如下:Python函数在定义的时候,默认参数L的值就被计算出来了,即[],因为默认参数L也是一个变量,它指向对象[],每次调用该函数,如果改变了L的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时的[]了。

15、Python中如果要对list实现类似Java那样的下标循环怎么办:

Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身:

 for i, value in enumerate(['A', 'B', 'C']):
...     print(i, value)
...
0 A
1 B
2 C
16、列表生成式,生成器,迭代器关系:

一类是集合数据类型,如list、tuple、dict、set、str等;一类是generator,包括生成器和带yield的generator function。这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。

17、高阶函数:函数本身也可以赋值给变量,即:变量可以指向函数;
>>> f = abs
>>> f(-10)
10

既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。

def add(x, y, f):
    return f(x) + f(y)

print(add(-5, 6, abs))
18、高阶函数的一种写法:
from functools import reduce

DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}

def str2int(s):
    def fn(x, y):
        return x * 10 + y
    def char2num(s):
        return DIGITS[s]
    return reduce(fn, map(char2num, s))
19、返回函数:

一个函数可以返回一个计算结果,也可以返回一个函数;返回一个函数时,牢记该函数并未执行,返回函数中不要引用任何可能会变化的变量。

20、偏函数:

当函数的参数个数太多,需要简化时,使用functools.partial可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单。

from functools import partial
 
def mod( n, m ):
  return n % m
 
mod_by_100 = partial( mod, 100 )
 
print mod( 100, 7 )  # 2
print mod_by_100( 7 )  # 2
21、reversed 函数:

返回一个反转的迭代器:

reversed(seq) # seq -- 要转换的序列,可以是 tuple, string, list 或 range。

# 字符串
seqString = 'Runoob'
print(list(reversed(seqString)))
22、Python的赋值、拷贝:
import copy

dict1 = {1: 1, 'user': 'test', 'num': [1, 2, 3]}
# 直接赋值
dict2 = dict1
dict3 = dict1.copy()
dict4 = copy.deepcopy(dict1)

dict1[1] = 11
dict1['user'] = '123'
dict1['num'].remove(1)

print('------------------------------------')
print('原字典修改后:', dict1)
print('直接赋值:', dict2)
print('浅拷贝:', dict3)
print('深拷贝:', dict4)
print('------------------------------------')


输出:
------------------------------------
原字典修改后: {1: 11, 'user': '123', 'num': [2, 3]}
直接赋值: {1: 11, 'user': '123', 'num': [2, 3]}
浅拷贝: {1: 1, 'user': 'test', 'num': [2, 3]}
深拷贝: {1: 1, 'user': 'test', 'num': [1, 2, 3]}
------------------------------------
  • 对于字典、列表等非基本数据类型来说,直接赋值即给dict1对应的内存对象取了一个别名dict2,所以修改dict1即是修改dict2

  • 浅拷贝只拷贝了父目录(根目录)的数据,非容器类型数据本身拷贝的就是数据本身,容器类型(列表,元组,集合,字典)的数据拷贝的是容器的别名,所以修改dict1的非容器类型数据时,并没有修改dict3的对应数据,而修改dict1的列表元素时,dict3对应的列表元素也修改了。

  • 深拷贝递归拷贝所有目录的数据,完全在另外内存中复制了一份原字典,所以对dict1的修改不会影响dict4的数据。

23、and 和 or 的用法:
  • and:从左到右计算表达式,若所有的都为真,则返回最后一个值,若存在假,返回第一个假值.

  • or:从左到右计算表达式,只要遇到真值就返回那个真是,如果表达式结束依旧没有遇到真值,就返回最后一个假值.

print(1 or 3)  # 1
print(1 and 3)  # 3
print(0 and 2 and 1)  # 0
print(0 and 2 or 1)  # 1
print(0 and 2 or 1 or 4)  # 1
print(0 or False and 1)  # Flase
24、re 正则忽略大小写
re.search('test', 'TeSt', re.IGNORECASE)
re.match('test', 'TeSt', re.IGNORECASE)
re.findall(regex, word, re.IGNORECASE)
25、str.split VS re.split
  • str.split不支持正则及多个切割符号,不感知空格的数量,比如:

    >>> s1="aa bb  cc"
    >>> s1.split(" ")
    ['aa', 'bb', '', 'cc']
    
  • re.split,更强大,支持正则及多个字符切割;

    >>> print line
    abc aa;bb,cc | dd(xx).xxx 12.12'	xxxx
    # 按空格切
    >>> re.split(r' ',line)
    ['abc', 'aa;bb,cc', '|', 'dd(xx).xxx', "12.12'\txxxx"]
    # 加将空格放可选框内[]内
    >>> re.split(r'[ ]',line)
    ['abc', 'aa;bb,cc', '|', 'dd(xx).xxx', "12.12'\txxxx"]
    # 按所有空白字符来切割:\s([\t\n\r\f\v])\S(任意非空白字符[^\t\n\r\f\v]
    >>> re.split(r'[\s]',line)
    ['abc', 'aa;bb,cc', '|', 'dd(xx).xxx', "12.12'", 'xxxx']
    # 多字符匹配
    >>> re.split(r'[;,]',line)
    ['abc aa', 'bb', "cc | dd(xx).xxx 12.12'\txxxx"]
    >>> re.split(r'[;,\s]',line)
    ['abc', 'aa', 'bb', 'cc', '|', 'dd(xx).xxx', "12.12'", 'xxxx']
    # 使用括号捕获分组的适合,默认保留分割符
    re.split('([;])',line)
    ['abc aa', ';', "bb,cc | dd(xx).xxx 12.12'\txxxx"]
    
2.6、正则速查表
字符 描述
\ 将下一个字符标记为一个特殊字符、或一个原义字符、或一个向后引用、或一个八进制转义符。例如,“n”匹配字符“n”。“\n”匹配一个换行符。串行“\\”匹配“\”而“\(”则匹配“(”。
^ 匹配输入字符串的开始位置。如果设置了RegExp对象的Multiline属性,^也匹配“\n”或“\r”之后的位置。
$ 匹配输入字符串的结束位置。如果设置了RegExp对象的Multiline属性,$也匹配“\n”或“\r”之前的位置。
* **匹配前面的子表达式零次或多次。**例如,zo*能匹配“z”以及“zoo”。*等价于{0,}。
+ **匹配前面的子表达式一次或多次。**例如,“zo+”能匹配“zo”以及“zoo”,但不能匹配“z”。+等价于{1,}。
? **匹配前面的子表达式零次或一次。**例如,“do(es)?”可以匹配“does”或“does”中的“do”。?等价于{0,1}。
{n} n是一个非负整数。匹配确定的n次。例如,“o{2}”不能匹配“Bob”中的“o”,但是能匹配“food”中的两个o。
{n,} n是一个非负整数。至少匹配n次。例如,“o{2,}”不能匹配“Bob”中的“o”,但能匹配“foooood”中的所有o。“o{1,}”等价于“o+”。“o{0,}”则等价于“o*”。
{n,m} mn均为非负整数,其中n<=m。最少匹配n次且最多匹配m次。例如,“o{1,3}”将匹配“fooooood”中的前三个o。“o{0,1}”等价于“o?”。请注意在逗号和两个数之间不能有空格。
? 当该字符紧跟在任何一个其他限制符(*,+,?,{n},{n,},{n,m})后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串“oooo”,“o+?”将匹配单个“o”,而“o+”将匹配所有“o”。
. **匹配除“\n”之外的任何单个字符。**要匹配包括“\n”在内的任何字符,请使用像(.|\n)的模式。
(pattern) 匹配pattern并获取这一匹配。所获取的匹配可以从产生的Matches集合得到,在VBScript中使用SubMatches集合,在JScript中则使用$0…$9属性。要匹配圆括号字符,请使用“\(”或“\)”。
(?:pattern) 匹配pattern但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用或字符“(|)”来组合一个模式的各个部分是很有用。例如“industr(?:y|ies)”就是一个比“industry|industries”更简略的表达式。
(?=pattern) 正向肯定预查,在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,“Windows(?=95|98|NT|2000)”能匹配“Windows2000”中的“Windows”,但不能匹配“Windows3.1”中的“Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
(?!pattern) 正向否定预查,在任何不匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如“Windows(?!95|98|NT|2000)”能匹配“Windows3.1”中的“Windows”,但不能匹配“Windows2000”中的“Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始
(?<=pattern) 反向肯定预查,与正向肯定预查类拟,只是方向相反。例如,“(?<=95|98|NT|2000)Windows”能匹配“2000Windows”中的“Windows”,但不能匹配“3.1Windows”中的“Windows”。
(?<!pattern) 反向否定预查,与正向否定预查类拟,只是方向相反。例如“(?<!95|98|NT|2000)Windows”能匹配“3.1Windows”中的“Windows”,但不能匹配“2000Windows”中的“Windows”。
x|y **匹配x或y。**例如,“z|food”能匹配“z”或“food”。“(z|f)ood”则匹配“zood”或“food”。
[xyz] **字符集合。匹配所包含的任意一个字符。**例如,“[abc]”可以匹配“plain”中的“a”。
[^xyz] 负值字符集合。匹配未包含的任意字符。例如,“[^abc]”可以匹配“plain”中的“p”。
[a-z] 字符范围。匹配指定范围内的任意字符。例如,“[a-z]”可以匹配“a”到“z”范围内的任意小写字母字符。
[^a-z] 负值字符范围。匹配任何不在指定范围内的任意字符。例如,“[^a-z]”可以匹配任何不在“a”到“z”范围内的任意字符。
\b 匹配一个单词边界,也就是指单词和空格间的位置。例如,“er\b”可以匹配“never”中的“er”,但不能匹配“verb”中的“er”。
\B 匹配非单词边界。“er\B”能匹配“verb”中的“er”,但不能匹配“never”中的“er”。
\cx 匹配由x指明的控制字符。例如,\cM匹配一个Control-M或回车符。x的值必须为A-Z或a-z之一。否则,将c视为一个原义的“c”字符。
\d 匹配一个数字字符。等价于[0-9]。
\D 匹配一个非数字字符。等价于[^0-9]。
\f 匹配一个换页符。等价于\x0c和\cL。
\n 匹配一个换行符。等价于\x0a和\cJ。
\r 匹配一个回车符。等价于\x0d和\cM。
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于[ \f\n\r\t\v]。
\S 匹配任何非空白字符。等价于[^ \f\n\r\t\v]。
\t 匹配一个制表符。等价于\x09和\cI。
\v 匹配一个垂直制表符。等价于\x0b和\cK。
\w 匹配包括下划线的任何单词字符。等价于“[A-Za-z0-9_]”。
\W 匹配任何非单词字符。等价于“[^A-Za-z0-9_]”。
\xn 匹配n,其中n为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,“\x41”匹配“A”。“\x041”则等价于“\x04&1”。正则表达式中可以使用ASCII编码。.
*num* 匹配num,其中num是一个正整数。对所获取的匹配的引用。例如,“(.)\1”匹配两个连续的相同字符。
*n* 标识一个八进制转义值或一个向后引用。如果*n之前至少n个获取的子表达式,则n为向后引用。否则,如果n为八进制数字(0-7),则n*为一个八进制转义值。
*nm* 标识一个八进制转义值或一个向后引用。如果*nm之前至少有nm个获得子表达式,则nm为向后引用。如果*nm之前至少有n个获取,则n为一个后跟文字m的向后引用。如果前面的条件都不满足,若nm均为八进制数字(0-7),则*nm将匹配八进制转义值nm*。
*nml* 如果n为八进制数字(0-3),且m和l均为八进制数字(0-7),则匹配八进制转义值nml。
\un 匹配n,其中n是一个用四个十六进制数字表示的Unicode字符。例如,\u00A9匹配版权符号(©)。