为什么要用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] * 10print(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, sampledef 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_ballsdef 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以后,可以使用
.httpserver
包提供的HttpServer
类来实现。
import .httpserver.HttpExchange;import .httpserver.HttpHandler;import .httpserver.HttpServer;import java.io.IOException;import java.io.OutputStream;import .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 {@Overridepublic 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, SimpleHTTPRequestHandlerclass 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 1return fib(num - 1) + fib(num - 2)
代理模式在Python中可以通过内置的或自定义的装饰器来实现。
from functools import lru_cache@lru_cache()def fib(num):if num in (1, 2):return 1return 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 wrapsfrom threading import RLockdef 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 copyclass 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 randomimport timeimport requestsfrom bs4 import BeautifulSoupfor page in range(10):resp = requests.get(url=f'/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 = aa = bb = temp
或
a = a ^ bb = a ^ ba = 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 = 0for 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 *@uniqueclass Suite (Enum):SPADE, HEART, CLUB, DIAMOND = range(4)class Card(object):def __init__(self,suite,face ):self.suite = suiteself.face = facedef __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 randomclass Poker(object):def __init__(self):self.cards =[Card(suite, face) for suite in Suitefor face in range(1, 14)]self.current=0def shuffle (self):self.current=0random.shuffle(self.cards)def deal (self):card = self.cards[self.current]self.current+=1return carddef has_next (self):if self.current<len(self.cards): return Truereturn Falsep = Poker()p.shuffle()print(p.cards)
PyLint的安装和使用
Pylint是Python代码分析工具,它分析Python代码中的错误,查找不符合代码风格标准(默认使用的代码风格是 PEP 8)和有潜在问题的代码。
pip install pylintpylint [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 cProfiledef is_prime(num):for factor in range(2, int(num ** 0.5) + 1):if num % factor == 0:return Falsereturn Trueclass PrimeIter:def __init__(self, total):self.counter = 0self.current = 1self.total = totaldef __iter__(self):return selfdef __next__(self):if self.counter < self.total:self.current += 1while not is_prime(self.current):self.current += 1self.counter += 1return self.currentraise StopIteration()cProfile.run('list(PrimeIter(10000))')
执行结果:
114734 function calls in 0.573 secondsOrdered by: standard namencalls 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
@profiledef is_prime(num):for factor in range(2, int(num ** 0.5) + 1):if num % factor == 0:return Falsereturn Trueclass PrimeIter:def __init__(self, total):self.counter = 0self.current = 1self.total = totaldef __iter__(self):return selfdef __next__(self):if self.counter < self.total:self.current += 1while not is_prime(self.current):self.current += 1self.counter += 1return self.currentraise StopIteration()list(PrimeIter(1000))
安装和使用line_profiler
三方库。
pip install line_profilerkernprof -lv example.pyWrote profile results to example02.py.lprofTimer unit: 1e-06 sTotal time: 0.089513 sFile: example02.pyFunction: is_prime at line 1#Hits Time Per Hit % Time Line Contents==============================================================1 @profile2 def is_prime(num):38662443305.00.548.4for factor in range(2, int(num ** 0.5) + 1):48562442814.00.547.8if num % factor == 0:56918 3008.00.43.4 return False61000 386.00.40.4return True
####memory_profiler
给需要剖析内存性能的函数加上一个profile
装饰器,这个函数每行代码的内存使用情况都会被剖析。
example03.py
@profiledef eat_memory():items = []for _ in range(1000000):items.append(object())return itemseat_memory()
安装和使用memory_profiler
三方库。
pip install memory_profilerpython3 -m memory_profiler example.pyFilename: example03.pyLine # Mem usage Increment Line Contents================================================1 38.672 MiB 38.672 MiB @profile2 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)动手操作,边学边玩全面掌握,学以致用乐为人师,融会贯通
时间管理
提升专注力
充分利用碎片时间
使用番茄工作法
时间是怎么浪费掉的
任何行动都比不采取行动好