第3章 CHAPTER 3 Python基础 Python是著名的工程师Guido van Rossum在1989年为了打发无聊的圣诞节而开发的一种编程语言。相较于晦涩难懂的C、C++语言,Python简洁易懂的代码和众多优秀的基础代码库,让它迅速跃迁为全世界最流行的语言之一。我们用它来开发应用软件无须从零开始,调用已有的库即可实现相应的功能。 3.1Python简介 视频讲解 对于刚刚从事编程工作或者刚开始学习编程的读者来说,Python简直是一种“除了不能生孩子,干什么都行的工具”。它就像是一把枪,只要装上子弹,扣扳机发射就可以了,而C、C++这些语言更像是倚天剑和屠龙刀,需要深厚的内力才能把它用起来。 当然,Python还是有它所不能企及的领域,例如编写操作系统,这个必须由C语言去完成,因为C语言是最贴近硬件的一门语言,用它编写的操作系统运行速度非常快。因此, Python这种被高度封装的语言,由于运行速度较慢,一般适合编写高级应用程序,相对底层的程序还是需要别的语言去完成。 运行速度慢只是Python其中一个缺点,不能加密能算得上它另外一个大缺点了,不过本着互联网开源免费的精神,代码不能加密在笔者看来也算不上缺点。 最后一个缺点就是版本了,目前Python有两个版本,2.X和3.X,它们有些不兼容,至于如何不兼容,笔者在此就不赘述了,因为Python的2.X版将在2020年被官方停止维护。因此,刚刚入门Python这门语言的读者直接上手Python 3.X版本即可。 3.2Python初阶学习 3.2.1变量赋值 1.#/chapter3/3_2_Basis.ipynb 2.a = 1# 单变量赋值 3.c = b = 2# 多变量赋值 4.print(a) 5.print(b, c) 1 2 2 1.# 变量类型 2.name ='Chile'# 字符串 3.miles = 1000.0# 浮点型 4.num = 100# 整形 5.# 打印变量类型 6.print(type(name)) 7.print(type(miles)) 8.print(type(num)) 3.2.2标准数据类型 1. Python有6个标准的数据类型 (1) Numbers(数字) (2) String(字符串) (3) List(列表) (4) Tuple(元组) (5) Dictionary(字典) (6) Set(集合) 其中,List、Tuple、Dictionary和Set可以放任意数据类型。 2. 数字 1.# Numbers: int & float 2.a = 1# int 3.b = 1.0# float 3. 字符串 1.# String 2.my_name ='Chile' 3.print(my_name[0])# 打印第0个字符 4.print(my_name[1: 3])# 打印第1个到第2个的字符 5.print(my_name[2:])# 打印第2个到最后1个的字符 6.print(my_name[-1])# 打印倒数第1个字符 C hi ile e 4. 列表 1.# List可以放任意类型的数据类型 2.num_list = [1, 2, 3, 4] 3.str_list = ['Chile', 'b', 'c'] 4.mix_list = ['a', 1, 1.0, num_list, str_list] 5.print(num_list) 6.print(str_list) 7.print(mix_list) [1, 2, 3, 4] ['Chile', 'b', 'c'] ['a', 1, 1.0, [1, 2, 3, 4], ['Chile', 'b', 'c']] 5. 元组 1.# Tuple可以放任意类型的数据类型 2.mix_tuple = ('chile', 111, 2.2, 'a', num_list)# 不可赋值 3.print(mix_list[1]) 4.print(mix_tuple) 5.mix_tuple[1] = 1# 不可赋值,否则报错 1 ('chile', 111, 2.2, 'a', [1, 2, 3, 4]) -------------------------------------------------------------------- TypeErrorTraceback (most recent call last) in () 3print(mix_list[1]) 4print(mix_tuple) ----> 5mix_tuple[1]=1# 不可赋值,否则报错 TypeError: 'tuple' object does not support item assignment 6. 字典 1.# Dictionary可以放任意类型的数据类型 2.test_dict = {'name': 'Chile', 'age': 18, 'num_list': num_list, 'tuple': mix_tuple} 3.print(test_dict) 4.print(test_dict.keys())# 打印键 5.print(test_dict.values())# 打印值 6.print(test_dict['name']) 7.print(test_dict['num_list']) 8.print(test_dict['tuple']) {'name': 'Chile', 'age': 18, 'num_list': [1, 2, 3, 4], 'tuple': ('chile', 111, 2.2, 'a', [1, 2, 3, 4])} dict_keys(['name', 'age', 'num_list', 'tuple']) dict_values(['Chile', 18, [1, 2, 3, 4], ('chile', 111, 2.2, 'a', [1, 2, 3, 4])]) Chile [1, 2, 3, 4] ('chile', 111, 2.2, 'a', [1, 2, 3, 4]) 7. 字典的赋值陷阱 1.# 直接字典赋值, 被赋值的字典的值改变,原字典也会改变 2.test_dict_copy = test_dict 3.test_dict_copy['name'] = 'alialili' 4.print(test_dict['name']) 5.print(test_dict_copy['name']) alialili alialili 1.# 使用深复制避免这种情况发生 2.from copy import deepcopy 3.test_dict_copy =deepcopy(test_dict) 4.test_dict_copy['name'] = 'Mary' 5.print(test_dict['name']) 6.print(test_dict_copy['name']) alialili Mary 8. 集合 1.# 可以放任意类型的基础数据类型 2.# Set集合: 与数学意义上的集合意义一致,集合内每一个值都是唯一的 3.test_set = {'abc', 1, 1, '1', 'chile'} 4.print(test_set)# 因为集合的去重功能,打印出来只有一个数字1 {1, 'chile', '1', 'abc'} 3.2.3数据类型转换 1.tr_a ='1' 2.int_b = int(tr_a)# 字符串转数字 3.str_c = str(int_b)# 数字转字符串 4.float_d = float(str_c)# 字符串转浮点 5.print(type(tr_a)) 6.print(type(int_b)) 7.print(type(str_c)) 8.print(type(float_d)) 9.print('---------------') 10.tr_list = [1, 2, 3] 11.set_a = set(tr_list)# 列表转集合 12.list_b = list(set_a)# 集合转列表 13.print(type(tr_list)) 14.print(type(set_a)) 15.print(type(list_b)) --------------- 3.2.4算术运算符 1.# 运算符 2.a = 2 3.b = a + 2 4.c = a - 1 5.d = a * b 6.e = d / c 7.f = d % c# 取余 8.g = 3 // 2# 整除(向下取整) 9.h = 2**3# 求幂 10.print('c:', c) 11.print('d:', d) 12.print('e:', e) 13.print('f:', f) 14.print('g:', g) 15.print('h:', h) c: 1 d: 8 e: 8.0 f: 0 g: 1 h: 8 3.2.5格式化 %s代表字符串,%d 代表整数,%f 代表浮点,%.2f 代表保留小数点后两位。 1.# 格式化 2.print('abc %d, dhfjdhfhdh, %s, sjdhsjhdhs, skdjskjsk%f,sdjsdhs' % (1, 'Chile', 1.0)) 3.# %.2f保留小数点后两位 4.print('abc %d, dhfjdhfhdh, %s, sjdhsjhdhs, skdjskjsk%.2f,sdjsdhs' % (1, 'Chile', 1.0)) abc 1, dhfjdhfhdh, Chile, sjdhsjhdhs, skdjskjsk1.000000,sdjsdhs abc 1, dhfjdhfhdh, Chile, sjdhsjhdhs, skdjskjsk1.00,sdjsdhs 视频讲解 3.3Python进阶学习 3.3.1循环 两种循环: for循环与while循环。 1. for循环打印List 1.# /chapter3/3_3_Basis_Advance.ipynb 2.str_list = ['Chile', 'b', 'c'] 3. 4.print('第1种循环取值方式:直接取值') 5.for sub_str in str_list: 6.print(sub_str) 7. 8.print('--------------------------') 9.print('第2种循环取值方式:索引取值') 10.for i in range(len(str_list)): 11.print(str_list[i]) 第1种循环取值方式:直接取值 Chile b c -------------------------- 第2种循环取值方式:索引取值 Chile b c 2. while循环打印List 1.str_list = ['Chile', 'b', 'c'] 2.i = 0 3.while i < len(str_list): 4.print(str_list[i]) 5.i += 1 Chile b c 3. for循环打印Tuple 1.str_list = ['Chile', 'b', 'c'] 2.mix_tuple = ('chile', 111, 2.2, 'a', str_list)# 不可赋值 3.print('第1种循环取值方式:直接取值') 4.for sub_tuple in mix_tuple: 5.print(sub_tuple) 6. 7.print('--------------------------') 8.print('第2种循环取值方式:索引取值') 9.for i in range(len(mix_tuple)): 10.print(mix_tuple[i]) 第1种循环取值方式:直接取值 chile 111 2.2 a ['Chile', 'b', 'c'] -------------------------- 第2种循环取值方式:索引取值 chile 111 2.2 a ['Chile', 'b', 'c'] 4. while循环打印Tuple 1.str_list = ['Chile', 'b', 'c'] 2.mix_tuple = ('chile', 111, 2.2, 'a', str_list)# 不可赋值 3.i = 0 4.while i < len(mix_tuple): 5.print(mix_tuple[i]) 6.i += 1 chile 111 2.2 a ['Chile', 'b', 'c'] 5. for循环打印Dictionary 1.str_list = ['Chile', 'b', 'c'] 2.mix_tuple = ('chile', 111, 2.2, 'a', str_list)# 不可赋值 3.num_list = [1, 2, 3, 4] 4.test_dict = {'name': 'Chile', 'age': 18, 'num_list': num_list, 'tuple': mix_tuple} 5.for key in test_dict.keys():# 键值对打印法 6.print('key:', key) 7.print('value:', test_dict[key]) 8.print('-------------') key: name value: Chile ------------- key: age value: 18 ------------- key: num_list value: [1, 2, 3, 4] ------------- key: tuple value: ('chile', 111, 2.2, 'a', ['Chile', 'b', 'c']) ------------- 6. for循环打印Set 1.test_set = {'abc', 1, 1, '1', 'chile'} 2.for value in test_set: 3.print(value, ' ', type(value)) abc 1 1 chile 3.3.2条件语句 ==: 恒等符号。 !=: 不等符号。 >: 大于号。 <: 小于号。 >=: 大于或等于号。 <=: 小于或等于号。 and: 与。 or: 或。 not: 非。 1.a = 1# 数字 2.b ='1'# 字符串 3.if a == b: 4.print('a == b') 5.else: 6.print('a != b') a != b 1.a = 1 2.b = 2 3.if a > b: 4.print('a > b') 5.elif a < b: 6.print('a < b') 7.else: 8.print('a == b') a < b 1.a = True 2.b = False 3.if a and b: 4.print('True') 5.else: 6.print('False') 7. 8.if a or b: 9.print('True') 10.else: 11.print('False') 12. 13.if a and (not b): 14.print('True') 15.else: 16.print('False') False True True 3.3.3文件I/O 权限有以下几种: w: 写权限。 r: 读权限。 a: 在原有文本的基础上追加文本的权限。 互联网上的文件有很多格式,这里只是举个例子让大家有个直观的感受。至于更多格式的读写,大家可以通过互联网去搜索,Python兼容很多文件格式的读写,且代码风格都差不多。 1.with open('text.txt', 'w') as fw:#只有文件名,默认文件在统计目录 2.string ='I am chile!' 3.for i in range(5): 4.fw.write(string +'\\n') 1.with open('text.txt', 'r') as fr: 2.for line in fr: 3.print(line) I am chile! I am chile! I am chile! I am chile! I am chile! 1.with open('text.txt', 'a') as fw: 2.string ='You are handsome!' 3.for i in range(5): 4.fw.write(string +'\\n') 1.with open('text.txt', 'r') as fr: 2.for line in fr: 3.print(line) I am chile! I am chile! I am chile! I am chile! I am chile! You are handsome! You are handsome! You are handsome! You are handsome! You are handsome! 3.3.4异常 try: 执行正常代码。 except: 发生异常,执行此处代码。 else: (这段代码可不加)无异常,则执行此处代码。 1.try: 2.with open('txr.txt', 'r') as fr: 3.text = fr.read() 4.except IOError: 5.print('The file does not exist!') 6. 7.else: 8.print('Succeed') The file does not exist! 异常处理的目的: 大家一开始写Python的时候可能并不需要异常处理机制,因为我们的代码简洁又高效,不过这并不代表你永远不需要。现代软件是非常庞大的,而代码又是人写的,难免会出错,如果不知道一个大型软件在运行过程中会在什么时候出现一个bug,这时异常处理机制就能让你快速定位自己软件的bug,缩短调试的时间,这就是异常处理机制的用途。 3.3.5导包 导包指令: import: 导入。 from ... import ...: 从……导入。 1. 导入本地包 首先创建test.py,功能是打印hello,接着通过以下代码导入: 1.from test import hello 2.hello() hello! 1.import test 2.test.hello() hello! 2. 导入系统包 1.import time # 引入时间模块 2.#格式化成year-month-day hour:min:sec形式 3.print (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) 2019-08-21 09:43:07 导包的目的: Python之所以被称为胶水语言,是因为它有很多优秀的第三方包,让我们在编程过程中只关注任务的解决,而不拘泥于代码的烦琐,提升代码的复用率,加快编程速度。因此,导包是Python不可或缺的重要技能。 视频讲解 3.4Python高阶学习 3.4.1面向过程编程 定义方法指令: def 面向过程编程是通过定义一个又一个的方法去确定的,在数学上我们更倾向于将方法称作函数。这么做的目的是将一个大的任务拆成一个又一个小的任务去实现,然后用搭积木似的操作去组装,从而完成任务。我们可以将积木看作方法,这些方法都是我们实现的,将一个又一个的积木组装成自己想要的形状,就是完成任务的过程。 1. 有返回值,无参数 1.#/chapter3/3_4_Basis_high_ranking.ipynb 2.def print_value(): 3.return 1 4.print_value()# 调用函数 1 2. 无返回值,无参数 1.def print_value(): 2.print('Chile') 3.print_value()# 调用函数 Chile 3. 无返回值,有参数 1.def print_value(a, b): 2.if a > b: 3.print('a > b') 4.elif a < b: 5.print('a < b') 6.else: 7.print('a == b') 8. 9.# 3种调用方式 10.print_value(1, 2)# 调用函数 11. 12.a = 1 13.b = 2 14.print_value(a, b)# 调用函数 15. 16.print_value(a=1, b=2)# 调用函数 a < b a < b a < b 4. 有返回值,有参数 1.def print_value(a_test, b_test): 2.if a > b: 3.return 'a > b' 4.elif a < b: 5.return 'a < b' 6.else: 7.return 'a == b' 8. 9.#3种调用方式 10.print(print_value(1, 2))# 调用函数 11. 12.a = 1 13.b = 2 14.print(print_value(a, b))# 调用函数 15. 16.print(print_value(a_test=1, b_test=2))# 调用函数 a < b a < b a < b 3.4.2面向对象编程 面向对象有两个概念: 类(Class)和实例(Instance),类是抽象的模板,例如Phone类; 而实例是根据类创建出来的一个个具体的“对象”,例如huawei和iphone等,每个实例的对象都拥有相同的方法,但各自的数据可能不同。 每一个方法的第1个参数永远是self。 类具有三大特性: 封装、继承与多态。 1. 封装 将属性和方法封装进类,每一个对象的属性和方法是一样的,类似模板,但数据不一样,类似我们将自己的内容输入模板。 1.class Phone(object): 2.# 内置的方法,用来绑定类的属性 3.def __init__(self, name, price): 4.# 属性 5.self.name = name 6.self.price = price 7. 8.# 方法 9.def print_price(self): 10.print(self.price) 11.def assistant(self): 12.print('I have an assistant!') 2. 实例化对象 类似将数据填入模板(类),以此实例化。 1.iphone = Phone('iphone', 5200) 2.huawei = Phone(name='huawei', price=8888) 3.print(iphone.price)# 查看实例属性 4.huawei.print_price()# 调用实例函数 5200 8888 3. 继承 继承就是传统意义上的意思,继承父辈已有的东西,然后在自己身上开发父辈没有的东西。 1.class Iphone(Phone): 2.def operation_system(self): 3.return 'ios' 4.iphone = Iphone('iphone', '5200') 5.print(iphone.operation_system()) ios 4. 多态 如果从父辈继承的方法不适合,子类会重写一个适合自己的同名方法,覆盖从父辈继承的已有的方法。即在运行子类的实例时,总是优先运行子类的代码。所以多态也叫多样性。 1.class Iphone(Phone): 2.def assistant(self): 3.print('I have siri assistant!') 4. 5.class Huawei(Phone): 6.def assistant(self): 7.print('I have hormony assistant!') 8.iphone = Iphone('iphone', 5200) 9.huawei = Huawei(name='huawei', price=8888) 10.iphone.assistant() 11.huawei.assistant() I have siri assistant! I have hormony assistant! 1.def get_assistant(Phone): 2.Phone.assistant() 3.get_assistant(Phone('phone', 500)) 4.get_assistant(Iphone('iphone', 5200)) 5.get_assistant(Huawei('huawei', 8888)) I have an assistant! I have siri assistant! I have hormony assistant! 3.4.3面向过程与面向对象的区别 面向过程的程序设计是以过程为中心,将问题分解成一个个小问题,然后用一个个函数将这些小问题按照步骤去解决,即把大函数切成小函数,从而降低问题的复杂度。而面向对象的程序设计是以对象为中心,将事物高度抽象化成模型,然后使用模型实例化出一个个对象,通过对象之间的通信来解决问题。 当然,不管是面向过程还是面向对象编程,本质上都是为了简化代码,提高代码复用率,只不过面向对象更加抽象罢了。越抽象的东西,通用性越高,当然也就意味着复用性越好。 视频讲解 3.5正则表达式 正则表达式是一个特殊的字符序列,帮助我们匹配想要的字符串格式。 3.5.1re.match 匹配字符串开头,开头不匹配直接返回None。 1.# !/usr/bin/python 2.# -*- coding: UTF-8 -*- 3. 4.import re 5.print(re.match('Chile', 'ChileWang').span())# 在起始位置匹配 6.print(re.match('Wang', 'ChileWang'))# 不在起始位置匹配 (0, 5) None 3.5.2re.search 返回字符串中第1个匹配的匹配。 1.import re 2.print(re.search('Chile', 'ChileWang').span())# 在起始位置匹配 3.print(re.search('Wang', 'ChileWang'))# 不在起始位置匹配 (0, 5) 3.5.3re.sub 替换字符串中的匹配项: re.sub(pattern, repl, string, count=0, flags=0) 参数: pattern: 正则中的模式字符串。 repl: 替换的字符串,也可为一个函数。 string: 要被查找替换的原始字符串。 count: 模式匹配后替换的最大次数,默认为0,表示替换所有的匹配。 1.#!/usr/bin/python 2.# -*- coding: UTF-8 -*- 3. 4.import re 5. 6.phone ="1234567@qq.com"# 这是一个QQ邮箱 7. 8.#删除字符串中的 Python注释 9.num = re.sub(r'#.*$', "", phone) 10.print ("QQ邮箱是: ", num) 11. 12.#用@163.com替换非数字(@qq.com)的字符串 13.num = re.sub(r'\\D+', "@163.com", phone) 14.print ("163邮箱是: ", num) QQ邮箱是: 1234567@qq.com 163邮箱是:1234567@163.com 3.5.4re.compile 函数与findall compile函数用于编译正则表达式,生成一个正则表达式(Pattern)对象,供match()和search()这两个函数使用。 findall(string, pos, endpos): 在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。 参数: string: 待匹配的字符串。 pos: 可选参数,指定字符串的起始位置,默认为 0。 endpos: 可选参数,指定字符串的结束位置,默认为字符串的长度。 1.# -*- coding:UTF8 -*- 2. 3.import re 4. 5.pattern = re.compile(r'\\d+')# 查找数字 6.result1 = pattern.findall('Chile 111 Wang 222') 7.result2 = pattern.findall('Chi111le444Wang333', 0, 11) 8. 9.print(result1) 10.print(result2) ['111', '222'] ['111', '444'] 3.5.5正则表达式的重点 正则表达式的核心是如何构建一个正则对象去匹配我们需要的字符,这里涉及很多的正则符号,之前的代码只是简单地介绍了匹配('\d+')数字或者('\D+')非数字,其实还有很多很多的匹配项。这是一个庞大的知识体系,我们不可能完全记住,也不可能完全精通,因此我们只需要在使用的时候翻阅一下即可。 目前,互联网上已经有很多正则表达式的匹配教程,笔者在此提及它,只是想让初学的读者知道有这么一个途径,等到需要用的时候,通过互联网去查阅即可。 视频讲解 3.6进程与线程 至此,大家写的代码都是完成单任务的,那如果想让Python同时进行多个任务呢?这就涉及了进程和线程。这里笔者先讲解什么是进程与线程。 举个例子,我们在计算机上可以同时运行QQ和微信等多个软件,这些软件就是在一个个进程中运行的。而我们在QQ上既可以聊天也可以看新闻,这就是进程里面一个个线程所做的事。因此,一个进程中至少拥有一个线程。 不过,多线程和多进程一样,都是统一由操作系统在线程中快速切换,切换速度比人类肉眼可见的速度快,造成好像多个任务同时运行的假象。但是如果我们的操作系统拥有多个CPU,就可以让多任务同时进行,让每个CPU都运行一个进程即可。 3.6.1多进程的例子 这里笔者用进程池(Pool)举例,进程池的默认参数是CPU核数目。 当然,互联网上也有很多别的多进程使用方法,思路都是一样的,只是实现方式不同,大家也可以选择自己喜欢的方式去实现。 参数设置成4,代表同时进行4个进程,第5个进程要等前面4个进程中的某个进程结束才能开始执行。 1.from multiprocessing import Pool 2.import time, random 3. 4.def random_time_task(name): 5.print('执行任务 %s ...' % (name)) 6.start_time= time.time() 7.time.sleep(random.random() * 5) 8.end_time = time.time() 9.print('任务 %s 执行时间: %0.2f s.' % (name, (end_time - start_time))) 10. 11.if __name__=='__main__': 12.p = Pool(4) 13.for i in range(5): 14.p.apply_async(random_time_task, args=(i,)) 15.p.close()# 调用close保证所有进程结束后,不再进入新的进程 16.p.join() 17.print('所有进程完成!') 执行任务 0 ... 执行任务 1 ... 执行任务 2 ... 执行任务 3 ... 任务 1 执行时间: 0.67 s. 执行任务 4 ... 任务 3 执行时间: 2.45 s. 任务 2 执行时间: 2.78 s. 任务 0 执行时间: 3.29 s. 任务 4 执行时间: 3.49 s. 所有进程完成! 3.6.2多线程例子 线程和进程之间还是存在一定区别的,每一个进程的变量都是独一无二的,类似QQ和微博,两者独立运行,互不影响。但是同一个进程内的线程是共享同一套变量的,类似我们同时取钱,第1个线程取完了所有的钱,第2个线程就不能再取钱了,因为已经没钱了。因此,为了避免我们程序出现bug,需要引入Lock(锁)机制,保证线程间在操作过程中,不能同时对同一变量进行操作。 1.import threading 2.balance = 10# 银行余额 3.lock = threading.Lock() 4. 5.def operation2balance(money): 6.global balance# 全局变量 7.balance = balance + money 8.balance = balance - money 9. 10.def new_thread(n): 11.for i in range(20): 12.# 操作前先获得锁 13.lock.acquire() 14.try: 15.operation2balance(n) 16.finally: 17.# 操作后释放锁 18.lock.release() 19. 20.# 启动两个线程 21.t1 = threading.Thread(target=new_thread, args=(29,)) 22.t2 = threading.Thread(target=new_thread, args=(18,)) 23.t1.start() 24.t2.start() 25.t1.join() 26.t2.join() 27.print(balance) 10 3.7总结 当然,Python能做的事不止这些,我们可以用Python写网页后台,也可以用它操作数据库等。所以有些读者可能会疑惑为什么笔者没有给大家把Python的更多细节说清楚。在这里笔者首先声明不是偷懒,原因有四,待我细细诉说。 第一,目前阶段的编程学习已经能完全应付这个系列的课程了,没有必要深入把目前用不着的知识给大家灌输一遍,没有实战,灌输再多边边角角的知识也只是走马观花,很难融会贯通。 第二,笔者已经帮助大家建立好了Python最基本知识体系,它犹如大树的枝干,而其他的知识犹如枝叶,枝叶会在枝干下不断衍生。那么衍生枝叶所需要的养分呢?那就是你接下来要碰到的一个个需要解决的项目,我们在掌握最基本的知识的情况下,通过实战去磨砺我们对所学知识的运用,最终量变决定质变。 第三,网上的知识已经过于冗余,笔者要给大家做减法,而建立一个知识体系就是给大家做减法。有时候我们只需要知道某个东西能解决哪些问题,例如Pandas或者Numpy这两个包可以解决很多很多的问题,但是你目前用不着,讲再多也是徒劳,不过我们知道它们的强大,那就在我们需要它们的时候,利用互联网去搜索即可,互联网上总会有人碰到和你一样的问题,并有人已经提供了答案。 第四,一切的项目都是从最基本的语法出发的,它们是万丈高楼的基石,我们想砌什么样的楼房不是看砖头长什么样,而是看设计图长什么样。同样的砖头在不同的图纸下,就会砌出不同形状的楼房。同样的语法,在不同的学习路线下,就细分出不同的专业领域。此时,我们回到最开始的问题,Python确实可以做很多的事,但是都是从最基本的知识点出发,至于接下来大家是想从事数据挖掘,还是人工智能,抑或是网页开发,甚至是爬虫工程师,那就看大家接下来的学习路线了。现在互联网上有很多学习资源,大家一定要学会使用搜索引擎,遇事不决先搜索,这也是锻炼自己的学习能力。学会规划学习路线和善用搜索引擎才是成长的关键所在。 最后,我们要始终铭记,编程只是工具,并不需要很聪明的脑瓜子,也不需要太多的奇技淫巧,无他,唯熟尔。上述所说不仅仅适用于编程的学习,也是我们在当前互联网时代下的有效学习途径。