Days
- 00. 简介
- 01. 初识 Python
- 02. 语言元素
- 03. 分支结构
- 04. 循环结构
- 05. 构造程序逻辑
- 06. 函数和模块的使用
- 07. 字符串和常用数据结构
- 08. 面向对象编程基础
- 09. 面向对象进阶
- 10. 图形用户界面和游戏开发
- 11. 文件和异常
- 12. 字符串和正则表达式
- 13. 进程和线程
- 14. 网络编程入门和网络应用开发
- 15. 图像和办公文档处理
- 16 20. Python 语言进阶
- 21 30. Web 前端概述
- 31 35. 玩转 Linux 操作系统
- 36. 关系型数据库和 MySQL 概述
- 37. SQL 详解之 DDL
- 38. SQL 详解之 DML
- 39. SQL 详解之 DQL
- 40. SQL 详解之 DCL
- 41. MySQL 新特性
- 42. 视图、函数和过程
- 43. 索引
- 44. Python接入MySQL数据库
- 45. 大数据平台和HiveSQL
- 46. Django快速上手
- 47. 深入模型
- 48. 静态资源和 Ajax 请求
- 49. Cookie 和 Session
- 50. 制作报表
- 51. 日志和调试工具栏
- 52. 中间件的应用
- 53. 前后端分离开发入门
- 54. RESTful 架构和 DRF 入门
- 55. RESTful 架构和 DRF 进阶
- 56. 使用缓存
- 57. 接入三方平台
- 58. 异步任务和定时任务
- 59. 单元测试
- 60. 项目上线
- 61. 网络数据采集概述
- 62. 用 Python 获取网络资源 1
- 62. 用 Python 解析 HTML 页面 2
- 63. Python 中的并发编程 1
- 63. Python 中的并发编程 2
- 63. Python 中的并发编程 3
- 63. 并发编程在爬虫中的应用
- 64. 使用 Selenium 抓取网页动态内容
- 65. 爬虫框架 Scrapy 简介
- 66. 数据分析概述
- 67. 环境准备
- 68. NumPy 的应用 1
- 69. NumPy 的应用 2
- 70. NumPy 的应用 3
- 71. NumPy 的应用 4
- 72. 深入浅出 pandas 1
- 73. 深入浅出 pandas 2
- 74. 深入浅出 pandas 3
- 75. 深入浅出 pandas 4
- 76. 深入浅出 pandas 5
- 77. 深入浅出 pandas 6
- 78. 数据可视化 1
- 79. 数据可视化 2
- 80. 数据可视化 3
- 81. 人工智能和机器学习概述
- 82. k 最近邻分类
- 83. 决策树
- 83. 推荐系统实战 1
- 84. 贝叶斯分类
- 85. 支持向量机
- 86. K 均值聚类
- 87. 回归分析
- 88. 深度学习入门
- 89. PyTorch 概述
- 90. PyTorch 实战
- 91. 团队项目开发的问题和解决方案
- 92. Docker 容器技术详解
- 93. MySQL 性能优化
- 94. 网络 API 接口设计
- 95. 使用 Django 开发商业项目
- 96. 软件测试和自动化测试
- 97. 电商网站技术要点剖析
- 98. 项目部署上线和性能调优
- 99. 面试中的公共问题
- 100. Python 面试题实录
公开课
番外篇
年薪 50W+ 的 Python 程序员如何写代码
为什么要用Python写代码
没有对比就没有伤害
很多互联网和移动互联网企业对开发效率的要求高于对执行效率的要求。
例子1:hello, world
C的版本:
#include <stdio.h>
int main() {
printf("hello, world\n");
return 0;
}
Java的版本:
class Example01 {
public static void main(String[] args) {
System.out.println("hello, world");
}
}
Python的版本:
print('hello, world')
例子2:1-100求和
C的版本:
#include <stdio.h>
int main() {
int total = 0;
for (int i = 1; i <= 100; ++i) {
total += i;
}
printf("%d\n", total);
return 0;
}
Python的版本:
print(sum(range(1, 101)))
例子3:创建和初始化数组(列表)
Java的版本:
import java.util.Arrays;
public class Example03 {
public static void main(String[] args) {
boolean[] values = new boolean[10];
Arrays.fill(values, true);
System.out.println(Arrays.toString(values));
int[] numbers = new int[10];
for (int i = 0; i < numbers.length; ++i) {
numbers[i] = i + 1;
}
System.out.println(Arrays.toString(numbers));
}
}
Python的版本:
values = [True] * 10
print(values)
numbers = [x for x in range(1, 11)]
print(numbers)
例子4:双色球随机选号
Java的版本:
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
class Example03 {
/**
* 产生[min, max)范围的随机整数
*/
public static int randomInt(int min, int max) {
return (int) (Math.random() * (max - min) + min);
}
/**
* 输出一组双色球号码
*/
public static void display(List<Integer> balls) {
for (int i = 0; i < balls.size(); ++i) {
System.out.printf("%02d ", balls.get(i));
if (i == balls.size() - 2) {
System.out.print("| ");
}
}
System.out.println();
}
/**
* 生成一组随机号码
*/
public static List<Integer> generate() {
List<Integer> redBalls = new ArrayList<>();
for (int i = 1; i <= 33; ++i) {
redBalls.add(i);
}
List<Integer> selectedBalls = new ArrayList<>();
for (int i = 0; i < 6; ++i) {
selectedBalls.add(redBalls.remove(randomInt(0, redBalls.size())));
}
Collections.sort(selectedBalls);
selectedBalls.add(randomInt(1, 17));
return selectedBalls;
}
public static void main(String[] args) {
try (Scanner sc = new Scanner(System.in)) {
System.out.print("机选几注: ");
int num = sc.nextInt();
for (int i = 0; i < num; ++i) {
display(generate());
}
}
}
}
Python的版本:
from random import randint, sample
def generate():
"""生成一组随机号码"""
red_balls = [x for x in range(1, 34)]
selected_balls = sample(red_balls, 6)
selected_balls.sort()
selected_balls.append(randint(1, 16))
return selected_balls
def display(balls):
"""输出一组双色球号码"""
for index, ball in enumerate(balls):
print(f'{ball:0>2d}', end=' ')
if index == len(balls) - 2:
print('|', end=' ')
print()
num = int(input('机选几注: '))
for _ in range(num):
display(generate())
温馨提示:珍爱生命,远离任何形式的赌博。
例子5:实现一个简单的HTTP服务器。
Java的版本:
说明:JDK 1.6以前,需要通过套接字编程来实现,具体又可以分为多线程和NIO两种做法。JDK 1.6以后,可以使用
com.sun.net.httpserver
包提供的HttpServer
类来实现。
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
class Example05 {
public static void main(String[] arg) throws Exception {
HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0);
server.createContext("/", new RequestHandler());
server.start();
}
static class RequestHandler implements HttpHandler {
@Override
public void handle(HttpExchange exchange) throws IOException {
String response = "<h1>hello, world</h1>";
exchange.sendResponseHeaders(200, 0);
try (OutputStream os = exchange.getResponseBody()) {
os.write(response.getBytes());
}
}
}
}
Python的版本:
from http.server import HTTPServer, SimpleHTTPRequestHandler
class RequestHandler(SimpleHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.end_headers()
self.wfile.write('<h1>hello, world</h1>'.encode())
server = HTTPServer(('', 8000), RequestHandler)
server.serve_forever()
或
python3 -m http.server 8000
一行Python代码可以做什么
很多时候,你的问题只需一行Python代码就能解决。
# 一行代码实现求阶乘函数
fac = lambda x: __import__('functools').reduce(int.__mul__, range(1, x + 1), 1)
# 一行代码实现求最大公约数函数
gcd = lambda x, y: y % x and gcd(y % x, x) or x
# 一行代码实现判断素数的函数
is_prime = lambda x: x > 1 and not [f for f in range(2, int(x ** 0.5) + 1) if x % f == 0]
# 一行代码实现快速排序
quick_sort = lambda items: len(items) and quick_sort([x for x in items[1:] if x < items[0]]) + [items[0]] + quick_sort([x for x in items[1:] if x > items[0]]) or items
# 生成FizzBuzz列表
['Fizz'[x % 3 * 4:] + 'Buzz'[x % 5 * 4:] or x for x in range(1, 101)]
设计模式从未如此简单
Python是动态类型语言,大量的设计模式在Python中被简化或弱化。
思考:如何优化下面的代码。
def fib(num):
if num in (1, 2):
return 1
return fib(num - 1) + fib(num - 2)
代理模式在Python中可以通过内置的或自定义的装饰器来实现。
from functools import lru_cache
@lru_cache()
def fib(num):
if num in (1, 2):
return 1
return fib(num - 1) + fib(num - 2)
for n in range(1, 121):
print(f'{n}: {fib(n)}')
说明:通过Python标准库
functools
模块的lru_cache
装饰器为fib
函数加上缓存代理,缓存函数执行的中间结果,优化代码的性能。
单例模式在Python中可以通过自定义的装饰器或元类来实现。
from functools import wraps
from threading import RLock
def singleton(cls):
instances = {}
lock = RLock()
@wraps(cls)
def wrapper(*args, **kwargs):
if cls not in instances:
with lock:
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
说明:需要实现单例模式的类只需要添加上面的装饰器即可。
原型模式在Python中可以通过元类来实现。
import copy
class PrototypeMeta(type):
def __init__(cls, *args, **kwargs):
super().__init__(*args, **kwargs)
cls.clone = lambda self, is_deep=True: \
copy.deepcopy(self) if is_deep else copy.copy(self)
说明:通过元类给指定了
metaclass=PrototypeMeta
的类添加一个clone
方法实现对象克隆,利用Python标准库copy
模块的copy
和deepcopy
分别实现浅拷贝和深拷贝。
数据采集和数据分析从未如此简单
网络数据采集是Python最擅长的领域之一。
例子:获取豆瓣电影“Top250”。
import random
import time
import requests
from bs4 import BeautifulSoup
for page in range(10):
resp = requests.get(
url=f'https://movie.douban.com/top250?start={25 * page}',
headers={'User-Agent': 'BaiduSpider'}
)
soup = BeautifulSoup(resp.text, "lxml")
for elem in soup.select('a > span.title:nth-child(1)'):
print(elem.text)
time.sleep(random.random() * 5)
利用NumPy、Pandas、Matplotlib可以轻松实现数据分析和可视化。
写出Python代码的正确姿势
用Python写代码就要写出Pythonic的代码。
姿势1:选择结构的正确姿势
跨界开发者的代码:
name = 'jackfrued'
fruits = ['apple', 'orange', 'grape']
owners = {'name': '骆昊', 'age': 40, 'gender': True}
if name != '' and len(fruits) > 0 and len(owners.keys()) > 0:
print('Jackfrued love fruits.')
Pythonic的代码:
name = 'jackfrued'
fruits = ['apple', 'orange', 'grape']
owners = {'name': '骆昊', 'age': 40, 'gender': True}
if name and fruits and owners:
print('Jackfrued love fruits.')
姿势2:交换两个变量的正确姿势
跨界开发者的代码:
temp = a
a = b
b = temp
或
a = a ^ b
b = a ^ b
a = a ^ b
Pythonic的代码:
a, b = b, a
姿势3:用序列组装字符串的正确姿势
跨界开发者的代码:
chars = ['j', 'a', 'c', 'k', 'f', 'r', 'u', 'e', 'd']
name = ''
for char in chars:
name += char
Pythonic的代码:
chars = ['j', 'a', 'c', 'k', 'f', 'r', 'u', 'e', 'd']
name = ''.join(chars)
姿势4:遍历列表的正确姿势
跨界开发者的代码:
fruits = ['orange', 'grape', 'pitaya', 'blueberry']
index = 0
for fruit in fruits:
print(index, ':', fruit)
index += 1
Pythonic的代码:
fruits = ['orange', 'grape', 'pitaya', 'blueberry']
for index, fruit in enumerate(fruits):
print(index, ':', fruit)
姿势5:创建列表的正确姿势
跨界开发者的代码:
data = [7, 20, 3, 15, 11]
result = []
for i in data:
if i > 10:
result.append(i * 3)
Pythonic的代码:
data = [7, 20, 3, 15, 11]
result = [num * 3 for num in data if num > 10]
姿势6:确保代码健壮性的正确姿势
跨界开发者的代码:
data = {'x': '5'}
if 'x' in data and isinstance(data['x'], (str, int, float)) \
and data['x'].isdigit():
value = int(data['x'])
print(value)
else:
value = None
Pythonic的代码:
data = {'x': '5'}
try:
value = int(data['x'])
print(value)
except (KeyError, TypeError, ValueError):
value = None
使用Lint工具检查你的代码规范
阅读下面的代码,看看你能看出哪些地方是有毛病的或者说不符合Python的编程规范的。
from enum import *
@unique
class Suite (Enum):
SPADE, HEART, CLUB, DIAMOND = range(4)
class Card(object):
def __init__(self,suite,face ):
self.suite = suite
self.face = face
def __repr__(self):
suites='♠♥♣♦'
faces=['','A','2','3','4','5','6','7','8','9','10','J','Q','K']
return f'{suites[self.suite.value]}{faces[self.face]}'
import random
class Poker(object):
def __init__(self):
self.cards =[Card(suite, face) for suite in Suite
for face in range(1, 14)]
self.current=0
def shuffle (self):
self.current=0
random.shuffle(self.cards)
def deal (self):
card = self.cards[self.current]
self.current+=1
return card
def has_next (self):
if self.current<len(self.cards): return True
return False
p = Poker()
p.shuffle()
print(p.cards)
PyLint的安装和使用
Pylint是Python代码分析工具,它分析Python代码中的错误,查找不符合代码风格标准(默认使用的代码风格是 PEP 8)和有潜在问题的代码。
pip install pylint
pylint [options] module_or_package
Pylint输出格式如下所示。
模块名:行号:列号: 消息类型 消息
消息类型有以下几种:
- C - 惯例:违反了Python编程惯例(PEP 8)的代码。
- R - 重构:写得比较糟糕需要重构的代码。
- W - 警告:代码中存在的不影响代码运行的问题。
- E - 错误:代码中存在的影响代码运行的错误。
- F - 致命错误:导致Pylint无法继续运行的错误。
Pylint命令的常用参数:
--disable=<msg ids>
或-d <msg ids>
:禁用指定类型的消息。--errors-only
或-E
:只显示错误。--rcfile=<file>
:指定配置文件。--list-msgs
:列出Pylint的消息清单。--generate-rcfile
:生成配置文件的样例。--reports=<y_or_n>
或-r <y_or_n>
:是否生成检查报告。
使用Profile工具剖析你的代码性能
cProfile模块
example01.py
import cProfile
def is_prime(num):
for factor in range(2, int(num ** 0.5) + 1):
if num % factor == 0:
return False
return True
class PrimeIter:
def __init__(self, total):
self.counter = 0
self.current = 1
self.total = total
def __iter__(self):
return self
def __next__(self):
if self.counter < self.total:
self.current += 1
while not is_prime(self.current):
self.current += 1
self.counter += 1
return self.current
raise StopIteration()
cProfile.run('list(PrimeIter(10000))')
执行结果:
114734 function calls in 0.573 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.006 0.006 0.573 0.573 <string>:1(<module>)
1 0.000 0.000 0.000 0.000 example.py:14(__init__)
1 0.000 0.000 0.000 0.000 example.py:19(__iter__)
10001 0.086 0.000 0.567 0.000 example.py:22(__next__)
104728 0.481 0.000 0.481 0.000 example.py:5(is_prime)
1 0.000 0.000 0.573 0.573 {built-in method builtins.exec}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
line_profiler
给需要剖析时间性能的函数加上一个profile
装饰器,这个函数每行代码的执行次数和时间都会被剖析。
example02.py
@profile
def is_prime(num):
for factor in range(2, int(num ** 0.5) + 1):
if num % factor == 0:
return False
return True
class PrimeIter:
def __init__(self, total):
self.counter = 0
self.current = 1
self.total = total
def __iter__(self):
return self
def __next__(self):
if self.counter < self.total:
self.current += 1
while not is_prime(self.current):
self.current += 1
self.counter += 1
return self.current
raise StopIteration()
list(PrimeIter(1000))
安装和使用line_profiler
三方库。
pip install line_profiler
kernprof -lv example.py
Wrote profile results to example02.py.lprof
Timer unit: 1e-06 s
Total time: 0.089513 s
File: example02.py
Function: is_prime at line 1
# Hits Time Per Hit % Time Line Contents
==============================================================
1 @profile
2 def is_prime(num):
3 86624 43305.0 0.5 48.4 for factor in range(2, int(num ** 0.5) + 1):
4 85624 42814.0 0.5 47.8 if num % factor == 0:
5 6918 3008.0 0.4 3.4 return False
6 1000 386.0 0.4 0.4 return True
memory_profiler
给需要剖析内存性能的函数加上一个profile
装饰器,这个函数每行代码的内存使用情况都会被剖析。
example03.py
@profile
def eat_memory():
items = []
for _ in range(1000000):
items.append(object())
return items
eat_memory()
安装和使用memory_profiler
三方库。
pip install memory_profiler
python3 -m memory_profiler example.py
Filename: example03.py
Line # Mem usage Increment Line Contents
================================================
1 38.672 MiB 38.672 MiB @profile
2 def eat_memory():
3 38.672 MiB 0.000 MiB items = []
4 68.727 MiB 0.000 MiB for _ in range(1000000):
5 68.727 MiB 1.797 MiB items.append(object())
6 68.727 MiB 0.000 MiB return items
如何构建综合职业素养
学习总结
- 了解全局
- 确定范围
- 定义目标
- 寻找资源
- 创建学习计划
- 筛选资源
- 开始学习,浅尝辄止(YAGNI)
- 动手操作,边学边玩
- 全面掌握,学以致用
- 乐为人师,融会贯通
时间管理
提升专注力
充分利用碎片时间
使用番茄工作法
时间是怎么浪费掉的
任何行动都比不采取行动好
好书推荐
- 职业规划:《软技能 - 代码之外的生存指南》
- 吴军系列:《浪潮之巅》、《硅谷之谜》、《数学之美》、……
- 时间管理:《成为一个更高效的人》、《番茄工作法图解》
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论