本笔记为阿里云天池龙珠计划Docker训练营的学习内容,学习链接为:https://tianchi.aliyun.com/specials/promotion/aicamppython
阿里天池——python训练营学习随记
is和==的区别
is
对比的是两个变量的内存地址==
对面的是两个变量的值
a = "hello"
b = "hello"
print(a is b, a == b)
# True True
a = ["hello"]
b = ["hello"]
print(a is b, a == b)
# False True
type和isinstance
type()
不会认为子类是一种父类类型,不考虑继承关系。isinstance()
会认为子类是一种父类类型,考虑继承关系。
print(type(1)) # <class 'int'>
print(type(5.2)) # <class 'float'>
print(type(True)) # <class 'bool'>
print(type('5.2')) # <class 'str'>
print(isinstance(1, int)) # True
print(isinstance(5.2, float)) # True
print(isinstance(True, bool)) # True
print(isinstance('5.2', str)) # True
关键词assert——断言
assert
这个关键词我们称之为“断言”,当这个关键词后边的条件为False
时,程序自动崩溃并抛出AssertionError
的异常。- 在进行单元测试时,可以用来在程序中置入检查点,只有条件为
True
才能让程序正常工作。
assert 3 > 7
#AssertionError
while循环的特别之处
- 可以写入
str、list
或任何序列,长度非零则视为真值,执行循环体;否则视为假值,不执行循环体。 while
可以接else
,跳出循环后执行else
while
中执行break
的话,else
不执行
string = 'abcd'
while string:
print(string)
string = string[1:]
else:
print('over')
# abcd
# bcd
# cd
# d
# over
for循环与dict、enumerate
for
循环是迭代循环,在Python中相当于一个通用的序列迭代器,可以遍历任何有序序列,如str、list、tuple
等,也可以遍历任何可迭代对象,如dict
。
dic = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
for key, value in dic.items():
print(key, value, sep=':', end=' ')
# a:1 b:2 c:3 d:4
for value in dic.values():
print(value, end=' ')
# 1 2 3 4
for key in dic.keys():
print(key, end=' ')
# a b c d
- 当对一个列表需要按顺序产生索引时,可以用
enumerate
a = ['a','b','c','d']
for n, value in enumerate(a,1):
print(n, value, sep=':', end=' ')
# 1:a 2:b 3:c 4:d
- 当
for
循环正常执行完的情况下,执行else
输出,如果for
循环中执行了跳出循环的语句,比如break
,将不执行else
代码块的内容,与while - else
语句一样。
#求10-20之间的质数
for num in range(10, 20): # 迭代 10 到 20 之间的数字
for i in range(2, num): # 根据因子迭代
if num % i == 0: # 确定第一个因子
j = num / i # 计算第二个因子
print('%d 等于 %d * %d' % (num, i, j))
break # 跳出当前循环
else: # 循环的 else 部分
print(num, '是一个质数')
# 10 等于 2 * 5
# 11 是一个质数
# 12 等于 2 * 6
# 13 是一个质数
# 14 等于 2 * 7
# 15 等于 3 * 5
# 16 等于 2 * 8
# 17 是一个质数
# 18 等于 2 * 9
# 19 是一个质数
推导式
1. 列表推导式
[ expr for value in collection [if condition] ]
x = [i for i in range(100) if (i % 2) != 0 and (i % 3) == 0]
print(x)
# [3, 9, 15, 21, 27, 33, 39, 45, 51, 57, 63, 69, 75, 81, 87, 93, 99]
x = [[i, j] for i in range(0, 3) for j in range(0, 3)]
print(x)
# [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2]]
x[0][0] = 10
print(x)
# [[10, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2]]
2. 字典推导式
{ key_expr: value_expr for value in collection [if condition] }
b = {i: i % 2 == 0 for i in range(10) if i % 3 == 0}
print(b)
# {0: True, 3: False, 6: True, 9: False}
- 使用字典推导式将字符串变为字典格式
str1 = 'name=zhangsan;age=17;gender=boy;phone=1309998890'
dict1 = {temp.split('=')[0]:temp.split('=')[1] for temp in str1.split(';')}
print(dict1)
# {'name': 'zhangsan', 'age': '17', 'gender': 'boy', 'phone': '1309998890'}
生成器
- ( expr for value in collection [if condition] ),是生成器,不是“元组推导式”
- 生成器自动创建了
_iter_()
和_next_()
内置方法仅仅保存了一套生成数值的算法,调用时,才去计算然后返回一个值。生成器一定是迭代器,而迭代器不一定是生成器,一边循环一边计算的机制称为生成器,含有yield语句的函数,可以减少内存空间。
a=(n for n in range(1,7))
print(a)
print(next(a))
for n in a:
print(n,end='...')
print('\n',tuple(a))# 前面循环已经遍历完了
# <generator object <genexpr> at 0x000002342D1E8270>
#1
#2...3...4...5...6...
# ()
- 还有一种生成器是yield,特性如下
def fun():
"函数生成器"
yield 100
print("python")
yield 1000
print("hello")
yield 10000
print(fun()) #<generator object fun at 0x101464150>
res = fun()
print(next(res)) #函数运行到yield,输出100,在此处暂停
print(next(res)) #再次运行,从第一个yield处释放,运行print("python"),继续运行到yield输出数据,又暂停
print(next(res)) #同理,从第二个yield处释放,运行到最后。函数生成器的全部数据已经取完,再执行就会报错。
#<generator object fun at 0x1090eb150>
# 100
# python
# 1000
# hello
# 10000
- 举个例子:用生成器实现费布那契数列(1,1,2,3,5,8,13,21……)
#费布那契数列的实现
def Fibonacci():
a = 0
b = 1
while True:
a,b = b,a + b
yield a
for i in Fibonacci():
if i < 100: #100以内的费布那契数列
print(i)
迭代器
- 迭代器是一个可以记住遍历的位置的对象。
- 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
- 迭代器有两个基本的方法:
iter()
和next()
。 - 使用时首先判断是否是可以迭代,用
isinstance()
方法判断或者可以for
循环的遍历的对象是可迭代对象,可以被next()
函数调用,并不断返回下一个值得对象。 - 任何实现了
__next__
方法 (python2 是 next)的对象都可以称为迭代器。
list=[1,2,3,4]
it = iter(list) # 创建迭代器对象
print(next(it))
for x in it:
print (x, end=" ")
# 1
# 2 3 4
异常处理 try except
异常就是运行期检测到的错误。计算机语言针对可能出现的错误定义了异常类型,某种错误引发对应的异常时,异常处理程序将被启动,从而恢复程序的正常运行。
1. Python 标准异常总结
-
BaseException:所有异常的 基类
-
Exception:常规异常的 基类
-
StandardError:所有的内建标准异常的基类
-
ArithmeticError:所有数值计算异常的基类
-
FloatingPointError:浮点计算异常
-
OverflowError:数值运算超出最大限制
-
ZeroDivisionError:除数为零
-
AssertionError:断言语句(assert)失败
-
AttributeError:尝试访问未知的对象属性
-
EOFError:没有内建输入,到达EOF标记
-
EnvironmentError:操作系统异常的基类
-
IOError:输入/输出操作失败
-
OSError:操作系统产生的异常(例如打开一个不存在的文件)
-
WindowsError:系统调用失败
-
ImportError:导入模块失败的时候
-
KeyboardInterrupt:用户中断执行
-
LookupError:无效数据查询的基类
-
IndexError:索引超出序列的范围
-
KeyError:字典中查找一个不存在的关键字
-
MemoryError:内存溢出(可通过删除对象释放内存)
-
NameError:尝试访问一个不存在的变量
-
UnboundLocalError:访问未初始化的本地变量
-
ReferenceError:弱引用试图访问已经垃圾回收了的对象
-
RuntimeError:一般的运行时异常
-
NotImplementedError:尚未实现的方法
-
SyntaxError:语法错误导致的异常
-
IndentationError:缩进错误导致的异常
-
TabError:Tab和空格混用
-
SystemError:一般的解释器系统异常
-
TypeError:不同类型间的无效操作
-
ValueError:传入无效的参数
-
UnicodeError:Unicode相关的异常
-
UnicodeDecodeError:Unicode解码时的异常
-
UnicodeEncodeError:Unicode编码错误导致的异常
-
UnicodeTranslateError:Unicode转换错误导致的异常
异常体系内部有层次关系,Python异常体系中的部分关系如下所示:
2. Python标准警告总结 -
Warning:警告的基类
-
DeprecationWarning:关于被弃用的特征的警告
-
FutureWarning:关于构造将来语义会有改变的警告
-
UserWarning:用户代码生成的警告
-
PendingDeprecationWarning:关于特性将会被废弃的警告
-
RuntimeWarning:可疑的运行时行为(runtime behavior)的警告
-
SyntaxWarning:可疑语法的警告
-
ImportWarning:用于在导入模块过程中触发的警告
-
UnicodeWarning:与Unicode相关的警告
-
BytesWarning:与字节或字节码相关的警告
-
ResourceWarning:与资源使用相关的警告
3. try except
【例一】
try-except-else
语句尝试查询不在dict
中的键值对,从而引发了异常。这一异常准确地说应属于KeyError
,但由于KeyError
是LookupError
的子类,且将LookupError
置于KeyError
之前,因此程序优先执行该except
代码块。所以,使用多个except
代码块时,必须坚持对其规范排序,要从最具针对性的异常到最通用的异常。
dict1 = {'a': 1, 'b': 2, 'v': 22}
try:#检测范围
x = dict1['y']
except LookupError:
print('查询错误')
except KeyError:
print('键错误')
else:#没有错误执行else
print(x)
# 查询错误
【例2】
一个 except
子句可以同时处理多个异常,这些异常将被放在一个括号里成为一个元组。
try:
s = 1 + '1'
int("abc")
f = open('test.txt')
print(f.read())
f.close()
except (OSError, TypeError, ValueError) as error:
print('出错了!\n原因是:' + str(error))
# 出错了!
# 原因是:unsupported operand type(s) for +: 'int' and 'str'
4. try except finally
- 不管
try
子句里面有没有发生异常,finally
子句都会执行。 - 如果一个异常在
try
子句里被抛出,而又没有任何的except
把它截住,那么这个异常会在finally
子句执行后被抛出。
def divide(x, y):
try:
result = x / y
print("result is", result)
except ZeroDivisionError:
print("division by zero!")
finally:
print("executing finally clause")
divide(2, 1)
# result is 2.0
# executing finally clause
divide(2, 0)
# division by zero!
# executing finally clause
divide("2", "1")
# executing finally clause
# TypeError: unsupported operand type(s) for /: 'str' and 'str'
5. raise
Python 使用raise
语句抛出一个指定的异常。
try:
raise NameError('HiThere')
except NameError:
print('An exception flew by!')
# An exception flew by!
较为特别的格式化操作
print('%5.1f' % 27.658) # ' 27.7'
print('%.2e' % 27.658) # 2.77e+01
print('%10d' % 10) # ' 10' 格式为d,填充空格使长度为10,即右对齐
print('%-10d' % 10) # '10 ' 格式为d,反向填充空格使长度为10,即左对齐
print('%+d' % 10) # +10
print('%#o' % 10) # 0o12 '#'在八进制数前面显示零('0')
print('%#x' % 108) # 0x6c '#'在十六进制前面显示'0x'或者'0X'(取决于用的是'x'还是'X')
print('%010d' % 5) # 0000000005 用0填充而不是空格
列表LIST
append和extend以及insert
append(obj)
:元素如果是一个 list,那么这个 list 将作为一个整体进行追加extend(obj)
:在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)- 严格来说
append
是追加,把一个东西整体添加在列表后,而extend
是扩展,把一个东西里的所有元素添加在列表后。
x = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
x.append(['Thursday', 'Sunday'])
# ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', ['Thursday', 'Sunday']]
x = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
x.extend(['Thursday', 'Sunday'])
# ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Thursday', 'Sunday']
- INSERT
list.insert(index, obj)
在编号index
位置插入obj
。index
就是插入后的位置
remove和pop
remove
和pop
都可以删除元素,前者是指定具体要删除的元素,后者是指定一个索引。pop
默认删除最后一位并返回该值,也可以直接制定index索引值进行删除
a = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Thursday', 'Sunday']
a.remove('Tuesday')
print(a)#['Monday', 'Wednesday', 'Thursday', 'Friday', 'Thursday', 'Sunday']
a.pop()
print(a)#['Monday', 'Wednesday', 'Thursday', 'Friday', 'Thursday']
a.pop(0)
print(a)#['Wednesday', 'Thursday', 'Friday', 'Thursday']
列表的操作
- 切片
- SQL中
BETWEEN m and n
是闭合区间 - 而切片中的
[a:b]
是不包含b
的区间
- SQL中
- 运算
list1 + list2
:两个list组成一个新的listlist1*3
:x = [a] * 4
操作中,只是创建4个指向list的引用,所以一旦a改变,x中4个a也会随之改变
x = [[0] * 3] * 4
print(x, type(x))
# [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]] <class 'list'>
x[0][0] = 1
print(x, type(x))
# [[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0]] <class 'list'>
前面三种方法(append
, extend
, insert
)可对列表增加元素,它们没有返回值,是直接修改了原数据对象。 而将两个list
相加,需要创建新的 list
对象,从而需要消耗额外的内存,特别是当 list
较大时,尽量不要使用 “+” 来添加list
。
列表的其他操作
- COUNT
list.count(obj)
统计某个元素在列表中出现的次数 - INDEX
list.index(x[, start[, end]])
从列表中找出某个值第一个匹配项的索引位置
LIST不支持rindex
,字符串才支持
list1 = [123, 456] * 5
print(list1.index(123)) # 0
print(list1.index(123, 1)) # 2
print(list1.index(123, 3, 7)) # 4
- RESERVE
list.reverse()
将列表(可迭代对象通用)方向,改变原列表 - SORT
list.sort(key=None, reverse=False)
对原列表(可迭代对象通用)进行排序。默认升序且以第一个数进行排序。
x = [(2, 2), (3, 4), (4, 1), (1, 3)]
x.sort()#默认升序且以第一个数进行排序
print(x)
# [(1, 3), (2, 2), (3, 4), (4, 1)]
x.sort(key=lambda a: a[1],reverse = True)#以第二个数进行倒序排序的方法
print(x)
# [(4, 1), (2, 2), (1, 3), (3, 4)]
- ZIP
zip(iter1 [,iter2 [...]])
用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的对象,这样做的好处是节约了不少的内存。
我们可以使用 list() 转换来输出列表。
如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。
a = [1, 2, 3]
b = [4, 5, 6]
c = [4, 5, 6, 7, 8]
zipped = zip(a, b)
print(zipped) # <zip object at 0x000000C5D89EDD88>
print(list(zipped)) # [(1, 4), (2, 5), (3, 6)]
zipped = zip(a, c)
print(list(zipped)) # [(1, 4), (2, 5), (3, 6)]
a1, a2 = zip(*zip(a, b))
print(list(a1)) # [1, 2, 3]
print(list(a2)) # [4, 5, 6]
元组
- 元组有不可更改 (immutable) 的性质,因此不能直接给元组的元素赋值,但是只要元组中的元素可更改 (mutable),那么我们可以直接更改其元素
t1 = (1, 2, 3, [4, 5, 6])
print(t1) # (1, 2, 3, [4, 5, 6])
t1[3][0] = 9
print(t1) # (1, 2, 3, [9, 5, 6])
- 元组可以用
+
和*
进行拼接,和list一样 - 元组可以用
COUNT
和INDEX
,和list一样 - 解压元组的几种方法
#解压一元元组
t = (1, 10.31, 'python')
(a, b, c) = t
print(a, b, c)
# 1 10.31 python
#解压二元元组
t = (1, 10.31, ('OK', 'python'))
(a, b, (c, d)) = t
print(a, b, c, d)
# 1 10.31 OK python
#把多个元素丢给一个变量,形成一个列表
t = 1, 2, 3, 4, 5
a, b, *rest, c = t
print(a, b, c) # 1 2 5
print(rest) # [3, 4]
#不在于剩余变量时
a, b, *_ = t
print(a, b) # 1 2
字符串
字符串的表达实例
print("let's go") # let's go
print('C:\\now') # C:\now
print(r'C:\Program Files\Intel\Wifi\Help')
# C:\Program Files\Intel\Wifi\Help
para_str = '''这是一个多行字符串的实例
多行字符串可以使用制表符
TAB ( \t )。
也可以使用换行符 [ \n ]。
'''
print(para_str)
# 这是一个多行字符串的实例
# 多行字符串可以使用制表符
# TAB ( )。
# 也可以使用换行符 [
# ]。
字符串常用操作
大小写变换
str.capitalize()
将字符串首字母变为大写str.lower()
全部变为小写str.upper()
全部变为大写str.swapcase()
大小写互换
查找操作
str.count(temp, beg= 0,end=len(str))
返回temp
在str
里面出现的次数str.endswith(suffix, beg=0, end=len(str))
检查字符串是否以指定子字符串suffix
结束,如果是,返回True
,否则返回False
。如果beg
和end
指定值,则在指定范围内检查。str.startswith(substr, beg=0,end=len(str))
检查字符串是否以指定子字符串substr
开头,如果是,返回True
,否则返回False
。如果beg
和end
指定值,则在指定范围内检查。str.find(temp, beg= 0,end=len(str))
如果包含,返回第一个找到的左侧的索引值,否则返回 -1。str.rfind(temp, beg= 0,end=len(str))
反向查找,返回第一个的左侧的索引值str.index(temp)
和str.rindex(temp)
操作也一致,但是找不到时候报错
str2 = "DAXIExiaoxie"
print(str2.rfind('ix')) # -1
print(str2.rindex('ix')) #ValueError
格式判断
isdigit()
isnumeric()
isdecimal()
的区别isdigit()
True: Unicode数字,byte数字(单字节),全角数字(双字节),罗马数字,带圈数字
False: 汉字数字
Error: 无isdecimal()
True: Unicode数字,,全角数字(双字节)
False: 罗马数字,汉字数字
Error: byte数字(单字节)isnumeric()
True: Unicode数字,全角数字(双字节),罗马数字,汉字数字
False: 无
Error: byte数字(单字节)
isalpha()
大小写英文和中文都为True
(汉字的unicode范围是\n4e00 ~ \n9ffff
)
a = 'aA中'
for n in a:
print(a.isalpha(),end=' ') # True True True
isupper()
islower()
istitle()
大写、小写、首字母大写的判断函数
对齐
ljust(width[, fillchar])
返回一个原字符串左对齐,并使用fillchar
(默认空格)填充至长度width
的新字符串。不影响原字符串。rjust(width[, fillchar])
返回一个原字符串右对齐,并使用fillchar
(默认空格)填充至长度width
的新字符串。不影响原字符串。
str4 = '1101'
print(str4.ljust(8, '0')) # 11010000
print(str4.rjust(8, '0')) # 00001101
空格操作
lstrip([chars])
截掉字符串左边的空格或指定字符。不影响原字符串。rstrip([chars])
删除字符串末尾的空格或指定字符。不影响原字符串。strip([chars])
删除字符串两侧的空格或指定字符。不影响原字符串。
str5 = ' I Love LsgoGroup '
print(str5.lstrip()) # 'I Love LsgoGroup '
print(str5.lstrip().strip('I')) # ' Love LsgoGroup '
print(str5.rstrip()) # ' I Love LsgoGroup'
print(str5.strip()) # 'I Love LsgoGroup'
print(str5.strip().strip('p')) # 'I Love LsgoGrou'
** 分割替换**
partition(sub)
找到子字符串sub
,把字符串分为一个三元组(pre_sub,sub,fol_sub)
,如果字符串中不包含sub
则返回('原字符串','','')
仅替换了一次,不影响原字符串。replace(old, new [, max])
把 将字符串中的old
替换成new
,如果max
指定,则替换不超过max
次。不影响原字符串。split(str=" ", num)
不带参数默认是以空格为分隔符切片字符串,如果num
参数有设置,则仅分隔num
个子字符串,返回切片后的子字符串拼接的列表。不影响原字符串。
a = 'a=1;b=2;c=3;d=4'
print(a.partition(';'))# ('a=1', ';', 'b=2;c=3;d=4')
print(a.replace('a','e'))# e=1;b=2;c=3;d=4
print(a.split(';'))# ['a=1', 'b=2', 'c=3', 'd=4']
dict1 = {temp.split('=')[0]:temp.split('=')[1] for temp in a.split(';')}
print(dict1)# {'a': '1', 'b': '2', 'c': '3', 'd': '4'}
print(a)# a=1;b=2;c=3;d=4
- 例:取出字符串中[ ]之间的字符串
string = "hello boy<[www.baidu.com]>byebye"
print(string.split('[')[1].split(']')[0]) # www.baidu.com
print(string.split('[')[1].split(']')[0].split('.')) # ['www', 'baidu', 'com']
splitlines([keepends])
按照行('\r', '\r\n', \n')
分隔,返回一个包含各行作为元素的列表,如果参数keepends
为False
,不包含换行符,如果为True
,则保留换行符。
字符串映射及转换
maketrans(intab, outtab)
创建字符映射的转换表,第一个参数是字符串,表示需要转换的字符,第二个参数也是字符串表示转换的目标。大小写敏感。translate(table, deletechars="")
根据参数table
给出的表,转换字符串的字符,要过滤掉的字符放到deletechars
参数中。
str1 = "I love China, I'm a Chinese."
intab = 'acei'
outtab = '1234'
trantab = str1.maketrans(intab,outtab)
print(trantab)
str2 = str1.translate(trantab)
print(str2)
# {97: 49, 99: 50, 101: 51, 105: 52}
# I lov3 Ch4n1, I'm 1 Ch4n3s3.
字典
一些基本概念
- 序列是以连续的整数为索引,与此不同的是,字典以"关键字"为索引,关键字可以是任意不可变类型,通常用字符串或数值
- 字典是 Python 唯一的一个 映射类型,字符串、元组、列表属于序列类型。
- dict 内部存放的顺序和 key 放入的顺序是没有关系的。
- dict 查找和插入的速度极快,不会随着 key 的增加而增加,但是需要占用大量的内存
比较特别的4种字典生成方式
slogan[brand.index(key)]
两个序列产生索引关系dict(mapping)
二维列表或元组作为字典“地图”dict(**kwargs)
用a=b的固定组合生成dict.fromkeys(seq[, value])
以序列 seq 中元素做字典的键,value 为字典所有键对应的初始值。
brand = ['李宁', '耐克', '阿迪达斯']
slogan = ['一切皆有可能', 'Just do it', 'Impossible is nothing']
print('耐克的口号是:', slogan[brand.index('耐克')])
# 耐克的口号是: Just do it
dic1 = dict([('apple', 4139), ('peach', 4127), ('cherry', 4098)])
print(dic1) # {'cherry': 4098, 'apple': 4139, 'peach': 4127}
dic2 = dict((('apple', 4139), ('peach', 4127), ('cherry', 4098)))
print(dic2) # {'peach': 4127, 'cherry': 4098, 'apple': 4139}
dic = dict(name='Tom', age=10)
print(dic) # {'name': 'Tom', 'age': 10}
seq = ('name', 'age', 'sex')
dic1 = dict.fromkeys(seq)
print(dic1)
# {'name': None, 'age': None, 'sex': None}
dic2 = dict.fromkeys(seq, 10)
print(dic2)
# {'name': 10, 'age': 10, 'sex': 10}
dic3 = dict.fromkeys(seq, ('小马', '8', '男'))
print(dic3)
# {'name': ('小马', '8', '男'), 'age': ('小马', '8', '男'), 'sex': ('小马', '8', '男')}
常用内置方法
dict.keys()
返回一个可迭代对象,可以使用list()
来转换为列表,列表为字典中的所有键。dict.values()
返回一个可迭代对象,可以使用list()
来转换为列表,列表为字典中的所有值。dict.items()
返回一个可迭代对象,可以使用list()
来转换为列表,以列表返回可遍历的 (键, 值) 元组数组。
dic = {'Name': 'Lsgogroup', 'Age': 7}
print(dic.items())
# dict_items([('Name', 'Lsgogroup'), ('Age', 7)])
print(list(dic.items()))
# [('Name', 'Lsgogroup'), ('Age', 7)]
dict.get(key,default=None)
、dict.setdefault(key,default=None)
返回指定键的值,如果值不在字典中返回默认值,默认无返回值,可设定。区别于dict[key]
的是,dict[key]
如果不在字典中会报错。dict.pop(key[,default])
删除字典给定键key
所对应的值,返回值为被删除的值。key
值必须给出。若key
不存在,则返回default
值,不设置default
值会报错。
del dict[key]
删除字典给定键key
所对应的值。dict.popitem()
返回并删除字典中最后一对键和值,如果字典已经为空,却调用了此方法,就报出KeyError
异常。dict.clear()
用于删除字典内所有元素。dict.update(dict2)
把字典参数dict2
的key:value
对 更新到字典dict
里。
dic = {'Name': 'Lsgogroup', 'Age': 7}
dic2 = {'Sex': 'female', 'Age': 8}
dic.update(dic2)
print(dic)
# {'Sex': 'female', 'Age': 8, 'Name': 'Lsgogroup'}
集合
Python 中set与dict类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在set中,没有重复的key。key为不可变类型,即可哈希的值。
- 要先创建集合对象再加入元素。
- 在创建空集合的时候只能使用
s = set()
,因为s = {}
创建的是空字典。 - 重复元素在set中会被自动被过滤。
- 可以使用
set(value)
工厂函数,把列表或元组转换成集合。 - set 存储的是无序集合,所以我们不可以为集合创建索引或执行切片操作,也没有key可用来获取集合中元素的值,但是可以判断一个元素是否在集合中。
一些内置用法
frozenset([iterable])
返回一个冻结的集合,冻结后集合不能再添加或删除任何元素,但是可以进行集合操作。
添加删除操作
set.add(elmnt)
用于给集合添加元素,如果添加的元素在集合中已存在,则不执行任何操作。set.update(set)
用于修改当前集合,可以添加新的元素或集合到当前集合中,如果添加的元素在集合中已存在,则该元素只会出现一次,重复的会忽略。
fruits = {"apple", "banana", "cherry"}
fruits.add("orange")
fruits.update(['apple','strawberry'])
print(fruits)
# {'cherry', 'strawberry', 'orange', 'apple', 'banana'}
set.remove(item)
用于移除集合中的指定元素。如果元素不存在,则会发生错误。set.discard(value)
用于移除指定的集合元素。remove()
方法在移除一个不存在的元素时会发生错误,而discard()
方法不会。set.pop()
随机移除一个元素,因为set是无序的。
集合操作
set1 & set2
返回两个集合的交集。set1 | set2
返回两个集合的并集。set1 - set2
返回集合的差集。set1 ^ set2
返回集合的异或。产生不重复元素的集合set1 <= set2
判断集合是不是完全被其他集合包含,如果是则返回True
,否则返回False
。set.isdisjoint(set)
用于判断两个集合是否不相交,如果是返回True
,否则返回False
。
函数
函数参数
def printinfo(arg1,arg2=2,*args, a, b, **kwargs):
print(arg1)
print(arg2)
print(args)
print(a)
print(b)
print(kwargs)
printinfo(1,4,1,2,3,a=8,b=3,c=11,d=14)
# 1
# 4
# (1, 2, 3, 4, 5)
# 8
# 3
# {'c': 11, 'd': 14}
- 位置参数:
arg1
,这些参数在调用函数 (call function) 时位置要固定。 - 默认参数:
arg2
,调用函数时,默认参数的值如果没有传入,则被认为是默认值。默认参数一定要放在位置参数 后面,不然程序会报错。 - 可变参数:
*args
,可以是从零个到任意个,自动组装成元组。加了星号(*)
的变量名会存放所有未命名的变量参数。 - 命名关键字参数:
*, nkw
,限制关键字参数的名字时使用。要特别注意调用时不能缺少参数名。 - 关键字参数:
**kwargs
,可以是从零个到任意个,自动组装成字典。
- 参数组合
- 当可变参数和命名关键字参数同时存在时,只要最前面有个
*
就可以了,后面的命名关键字参数不需要再加*
。 - 命名顺序必须是按以上顺序。
- 虽然可以组合多达 5 种参数,但不要同时使用太多的组合,否则函数很难懂。
- 当可变参数和命名关键字参数同时存在时,只要最前面有个
变量作用域
- Python 中,程序的变量并不是在哪个位置都可以访问的,访问权限决定于这个变量是在哪里赋值的。
- 定义在函数内部的变量拥有局部作用域,该变量称为局部变量。
- 定义在函数外部的变量拥有全局作用域,该变量称为全局变量。
- 局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。
- 当内部作用域想修改外部作用域的变量时,就要用到
global
和nonlocal
关键字。global
用于一般的函数内部作用域修改外部作用域,nonlocal
用于闭包或内嵌函数作用域中的变量。
num = 1
def fun1():
global num # 需要使用 global 关键字声明
print(num) # 1
num = 123
print(num) # 123
fun1()
print(num) # 123
- 内嵌函数
内嵌的函数只能在函数内部被调用
(这个例子其实算是闭包)
def outer():
num = 10
def inner():
nonlocal num # nonlocal关键字声明
num = 100
print(num)
inner()
print(num)
outer()
# 100
# 100
闭包
* 是函数式编程的一个重要的语法结构,是一种特殊的内嵌函数。
* **如果在一个内部函数里对外层非全局作用域的变量进行引用,那么内部函数就被认为是闭包。**
* 通过闭包可以访问外层非全局作用域的变量,这个作用域称为闭包作用域。
* **闭包的返回值通常是函数**。
def funX(x):
def funY(y):
return x * y
return funY
i = funX(8)
print(type(i)) # <class 'function'>
print(i(5)) # 40
另一栗子,将闭包4个内部函数名返回。这里将counter
定义为一个列表,使内部函数调用的时候避免了nonlocal
声明。
def make_counter(init):
counter = [init]
def inc(): counter[0] += 1
def dec(): counter[0] -= 1
def get(): return counter[0]
def reset(): counter[0] = init
return inc, dec, get, reset
inc, dec, get, reset = make_counter(0)
inc()
inc()
inc()
print(get()) # 3
dec()
print(get()) # 2
reset()
print(get()) # 0
递归
如果一个函数在内部调用自身本身,这个函数就是递归函数。这里用两个例子对比递归和循环的处理方式。可以看出,递归的做法更直观体现了函数本身的特性。
- 例1:n! = 1 x 2 x 3 x … x n,即f(n) = n * f(n-1)
# 利用循环
n = 5
for k in range(1, 5):
n = n * k
print(n) # 120
# 利用递归
def factorial(n):
if n == 1:
return 1
return n * factorial(n - 1)
print(factorial(5)) # 120
- 例2:斐波那契数列 f(n) = f(n-1) + f(n-2), f(0) = 0,f(1) = 1
# 利用循环
i = 0
j = 1
lst = list([i, j])
for k in range(2, 11):
k = i + j
lst.append(k)
i = j
j = k
print(lst)
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
# 利用递归
def recur_fibo(n):
if n <= 1:
return n
return recur_fibo(n - 1) + recur_fibo(n - 2)
lst = list()
for k in range(11):
lst.append(recur_fibo(k))
print(lst)
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
lambda 表达式
- 用
lambda
关键词来创建匿名函数,而非def
关键词,它没有函数名。 lambda
不需要return
来返回,表达式本身结果就是返回值。- 函数参数可以是位置参数、默认参数、关键字参数,和正规函数里的参数类型一样。
- 匿名函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
- 常常应用于函数式编程的高阶函数。
odd = lambda x: x % 2 == 1
templist = filter(odd, [1, 2, 3, 4, 5, 6, 7, 8, 9])
print(list(templist)) # [1, 3, 5, 7, 9]
类与对象
对象 = 属性 + 方法
对象是类的实例。换句话说,类主要定义对象的结构,然后我们以类为模板创建对象。类不但包含方法定义,而且还包含所有实例共享的数据。
Python 的 self
相当于 C++ 的 this
指针。类的方法与普通的函数只有一个特别的区别 —— 它们必须有一个额外的第一个参数名称(对应于该实例,即该对象本身),按照惯例它的名称是self
。在调用方法时,我们无需明确提供与参数self
相对应的参数。
class Turtle: # Python中的类名约定以大写字母开头
"""关于类的一个简单例子"""
# 属性
color = 'green'
weight = 10
legs = 4
shell = True
mouth = '大嘴'
# 方法
def climb(self):
print('我正在很努力的向前爬...')
def run(self):
print('我正在飞快的向前跑...')
def bite(self):
print('咬死你咬死你!!')
def eat(self):
print('有得吃,真满足...')
def sleep(self):
print('困了,睡了,晚安,zzz')
tt = Turtle()
print(tt)# <__main__.Turtle object at 0x0000007C32D67F98>
print(type(tt))# <class '__main__.Turtle'>
print(tt.__class__)# <class '__main__.Turtle'>
print(tt.__class__.__name__)# Turtle
tt.climb()# 我正在很努力的向前爬...
tt.run()# 我正在飞快的向前跑...
tt.bite()# 咬死你咬死你!!
# Python类也是对象。它们是type的实例
print(type(Turtle))
# <class 'type'>
子类自动共享父类之间数据和方法的机制
class MyList(list):
pass
lst = MyList([1, 5, 2, 7, 8])
lst.append(9)
lst.sort()
print(lst)
# [1, 2, 5, 7, 8, 9]
公有和私有
在 Python 中定义私有变量只需要在变量名或函数名前加上__
两个下划线,那么这个函数或变量就会为私有的了。私有的函数或变量外部(正常情况下)无法调用。
class JustCounter:
__secretCount = 0 # 私有变量
publicCount = 0 # 公开变量
def count(self):
self.__secretCount += 1
self.publicCount += 1
print(self.__secretCount)
counter = JustCounter()
counter.count() # 1
counter.count() # 2
print(counter.publicCount) # 2
# Python的私有为伪私有
print(counter._JustCounter__secretCount) # 2
print(counter.__secretCount)
# AttributeError: 'JustCounter' object has no attribute '__secretCount'
父类、子类、继承
如果子类中定义与父类同名的方法或属性,则会自动覆盖父类对应的方法或属性。可以调用未绑定的父类方法Fish.__init__(self)
或者super().__init__()
解决子类覆盖父类构造函数的问题。
#类定义
class people:
#定义基本属性
name = ''
age = 0
#定义私有属性,私有属性在类外部无法直接访问
__weight = 0
#定义构造方法
def __init__(self, n, a, w):
self.name = n
self.age = a
self.__weight = w
def speak(self):
print('%s 说:我 %d 岁。' % (self.name,self.age))
#子类继承
class student(people):
grade = ''
def __init__(self, n, a, w, g):
#调用父类的构造函数
people.__init__(self, n, a, w)
#还可以用super().__init__(n, a, w)
self.grade = g
# 覆写父类的方法
def speak(self):
print("%s 说: 我 %d 岁了,我在读 %d 年级" % (self.name, self.age, self.grade))
s = student('sean', 10, 60, 3)
s.speak()
# sean 说: 我 10 岁了,我在读 3 年级
类的组合
用另一个类组合两个不同的类,避免多重继承的复杂。
class Turtle:
def __init__(self, x):
self.num = x
class Fish:
def __init__(self, x):
self.num = x
class Pool:
def __init__(self, x, y):
self.turtle = Turtle(x)
self.fish = Fish(y)
def print_num(self):
print("水池里面有乌龟%s只,小鱼%s条" % (self.turtle.num, self.fish.num))
p = Pool(2, 3)
p.print_num()
# 水池里面有乌龟2只,小鱼3条
类、类对象和实例对象
类对象:创建一个类,其实也是一个对象也在内存开辟了一块空间,称为类对象,类对象只有一个。
实例对象:就是通过实例化类创建的对象,称为实例对象,实例对象可以有多个。
class A(object):
pass
# 实例化对象 a、b、c都属于实例对象。
a = A()
b = A()
c = A()
类属性:类里面方法外面定义的变量称为类属性。类属性所属于类对象并且多个实例对象之间共享同一个类属性,说白了就是所有的通过该类实例化的对象都能共享类属性。
实例属性:实例属性和具体的某个实例对象有关系,并且一个实例对象和另外一个实例对象是不共享属性的,说白了实例属性只能在自己的对象里面使用,其他的对象不能直接使用,因为self
是谁调用,它的值就属于该对象。
# 创建类对象
class Test(object):
class_attr = 100 # 类属性
def __init__(self):
self.sl_attr = 100 # 实例属性
def func(self):
print('类对象.类属性的值:', Test.class_attr) # 调用类属性
print('self.类属性的值', self.class_attr) # 相当于把类属性 变成实例属性
print('self.实例属性的值', self.sl_attr) # 调用实例属性
a = Test()
a.func()
# 类对象.类属性的值: 100
# self.类属性的值 100
# self.实例属性的值 100
b = Test()
b.func()
# 类对象.类属性的值: 100
# self.类属性的值 100
# self.实例属性的值 100
a.class_attr = 200
a.sl_attr = 200
a.func()
# 类对象.类属性的值: 100
# self.类属性的值 200
# self.实例属性的值 200
b.func()
# 类对象.类属性的值: 100
# self.类属性的值 100
# self.实例属性的值 100
Test.class_attr = 300
a.func()
# 类对象.类属性的值: 300
# self.类属性的值 200
# self.实例属性的值 200
b.func()
# 类对象.类属性的值: 300
# self.类属性的值 300
# self.实例属性的值 100
什么是绑定
Python 严格要求方法需要有实例才能被调用,这种限制其实就是 Python 所谓的绑定概念。
Python 对象的数据属性通常存储在名为__ dict__
的字典中,我们可以直接访问__dict__
,或利用 Python 的内置函数vars()
获取__ dict__
。
类相关函数
issubclass(class, classinfo)
用于判断参数class
是否是类型参数classinfo
的子类。一个类被认为是其自身的子类。classinfo
可以是类对象的元组,只要class
是其中任何一个候选类的子类,则返回True
。
class A:
pass
class B(A):
pass
print(issubclass(B, A)) # True
print(issubclass(B, B)) # True
print(issubclass(A, B)) # False
print(issubclass(B, object)) # True
isinstance(object, classinfo)
方法用于判断一个对象是否是一个已知的类型,类似type()。type()
不会认为子类是一种父类类型,不考虑继承关系。isinstance()
会认为子类是一种父类类型,考虑继承关系。
a = 2
print(isinstance(a, int)) # True
print(isinstance(a, str)) # False
print(isinstance(a, (str, int, list))) # True
class A:
pass
class B(A):
pass
print(isinstance(A(), A)) # True
print(type(A()) == A) # True
print(isinstance(B(), A)) # True
print(type(B()) == A) # False
hasattr(object, name)
用于判断对象是否包含对应的属性。
class Coordinate:
x = 10
y = -5
z = 0
point1 = Coordinate()
print(hasattr(point1, 'x')) # True
print(hasattr(point1, 'y')) # True
print(hasattr(point1, 'z')) # True
print(hasattr(point1, 'no')) # False
getattr(object, name[, default])
用于返回一个对象属性值。setattr(object, name, value)
对应函数getattr()
,用于设置属性值,该属性不一定是存在的。delattr(object, name)
用于删除属性。
class A(object):
bar = 1
a = A()
print(getattr(a, 'bar')) # 1
setattr(a, 'bar', 5)
print(a.bar) # 5
setattr(a, "age", 28)
print(a.age) # 28
delattr(a,'age')
print(a.age) # AttributeError