阿里天池——python训练营学习笔记

本笔记为阿里云天池龙珠计划Docker训练营的学习内容,学习链接为:https://tianchi.aliyun.com/specials/promotion/aicamppython

is和==的区别

  1. is对比的是两个变量的内存地址
  2. ==对面的是两个变量的值
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

  1. type() 不会认为子类是一种父类类型,不考虑继承关系。
  2. 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——断言

  1. assert这个关键词我们称之为“断言”,当这个关键词后边的条件为False时,程序自动崩溃并抛出AssertionError的异常。
  2. 在进行单元测试时,可以用来在程序中置入检查点,只有条件为 True才能让程序正常工作。
assert 3 > 7
#AssertionError

while循环的特别之处

  1. 可以写入str、list或任何序列,长度非零则视为真值,执行循环体;否则视为假值,不执行循环体。
  2. while可以接else,跳出循环后执行else
  3. while中执行break的话,else不执行
string = 'abcd'
while string:
    print(string)
    string = string[1:]
else:
	print('over')
# abcd
# bcd
# cd
# d
# over

for循环与dict、enumerate

  1. 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 
  1. 当对一个列表需要按顺序产生索引时,可以用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 
  1. 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,但由于KeyErrorLookupError的子类,且将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 位置插入 objindex就是插入后的位置

remove和pop

  • removepop 都可以删除元素,前者是指定具体要删除的元素,后者是指定一个索引。
  • 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的区间
  • 运算
    • list1 + list2:两个list组成一个新的list
    • list1*3x = [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一样
  • 元组可以用COUNTINDEX,和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)) 返回tempstr里面出现的次数
  • str.endswith(suffix, beg=0, end=len(str)) 检查字符串是否以指定子字符串 suffix结束,如果是,返回 True,否则返回 False。如果begend指定值,则在指定范围内检查。
  • str.startswith(substr, beg=0,end=len(str))检查字符串是否以指定子字符串 substr 开头,如果是,返回True,否则返回 False。如果begend指定值,则在指定范围内检查。
  • 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')分隔,返回一个包含各行作为元素的列表,如果参数keependsFalse,不包含换行符,如果为 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)把字典参数 dict2key: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 中,程序的变量并不是在哪个位置都可以访问的,访问权限决定于这个变量是在哪里赋值的。
  • 定义在函数内部的变量拥有局部作用域,该变量称为局部变量。
  • 定义在函数外部的变量拥有全局作用域,该变量称为全局变量。
  • 局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。
  • 当内部作用域想修改外部作用域的变量时,就要用到globalnonlocal关键字。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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值