笔记内容来源:拉勾教育数据分析实战训练营
本篇是Part 2,python的进阶部分开始啦~~~~~~~
说明:理论部分是提炼的老师所讲,加上我自己看书添加的一些解释,代码部分有些会融合老师和我自己练习的写法,一起分享给大家
再啰嗦两句,关于拉勾教育数据分析实战训练营:
目前为止已经学习了近4个月的课程,已经学完Excel、数据分析思维、MySQL、Tableau、quickBI、神策、hive、统计学,每一阶段每一模块的知识都是在线自主学习,完成作业后解锁新课程,直播课会根据全体学员进度,收集疑问然后进行在线直播内容回顾和答疑以及作业讲解。每位讲师都很优秀,都有自己的授课特色所在,内容都是很干货的录好的内容,有些内容导师还会重新录制,不断迭代让学员达到更好的学习体验。作业批改、答疑导师西蒙(我接触最多的,经常麻烦他帮我解决问题)和班主任团子比较nice,认真负责,他们分别负责技术答疑和服务类的问题,平时有问题可以在微信群里问,可以单独聊也可以群里问,他们全天非工作日也会答疑。
在这里真心推荐下拉勾教育数据分析实战训练营:
1、课程体系最全面:课程内容有分析方法论、分析方法、Excel、Mysql、Tableau、Quick BI、神策平台、Hive、统计学、Python、挖掘算法、Spss等,是目前我看到的最全面的。
2、课程体系把握行业人才需求痛点:拉勾主营业务是招聘,最明白企业的人才需求,基于此设计的课程体系是比较贴近实际需求的。通过5个月10个阶段,从现状统计到预测分析、从业务数据到编程工具处理复杂业务逻辑数据,实现用数据驱动业务辅助决策,提升公司业绩。
3、课程学习模式灵活:大部分授课采用录播方式,学习完成后还有直播答疑。比直播打卡更容易安排自己的时间。
4、课程学习过程和结果有保障:学习成果作业检测+实时答疑+班主任督导,每个阶段每个模块的知识学完的作业可以锻炼实操。
5、项目实战内容丰富:也是我最看好的一点,涵盖了在线教育、电商等多个领域项目实战。
6、就业辅导+优秀内推:拉勾平台是互联网行业招聘大本营,这是天然优势。
~~~~~~~~~~~~~~~~~以下是笔记~~~~~~~~~~~~~~~~
四、Python进阶
1 函数
1.1 函数定义及调用
在Python在, 使用def关键字来定义函数
def hello(name):
print('hello',name)
hello('python')
# hello python
上面的代码定义了一个最简单的函数,它的作用就是打印出"Hello"加一个名字。看看它的结构:
1.2 函数的参数
函数的参数可以有一个,也可以有多个,也可以没有参数。这取决于在定义函数的时候如何定义参数部分。刚才我们定义的函数只有一个参数,现在我们定义两个参数的函数。
def hello2(name, sex):
if sex == '男':
print("Hello, Mr", name)
elif sex == '女':
print("Hello, Mrs", name)
这个函数有两个参数,name和sex(变量是形参),分别表示用户的名字和性别,传递的值是实参。
在调用的时候,要注意参数的顺序,不能前后颠倒。可以调用函数多次
hello("Zhang", "男")
hello("Wang", "女")
如果参数较多,记不清它们的顺序,可以写上参数名--关键字实参
hello(sex='男', name='Zhang')
默认值
使用默认值时,在形参列表中必须先列出没有默认值的形参,再列出有默认值的形参。
def hello2(name, sex='女'):
if sex == '男':
print("Hello, Mr", name)
elif sex == '女':
print("Hello, Mrs", name)
hello2(name='Zhong')
hello2('zhong')
如果每一个参数都有默认值,在调用的时候甚至可以不传参数。
def hello2(name='Anonym', sex='女'):
if sex == '男':
print("Hello, Mr", name)
elif sex == '女':
print("Hello, Mrs", name)
hello2()
现在这个函数对于信息不完整的数据也有处理能力了。
如果在调用函数时,给形参提供了实参,将使用制定的实参值,否则将使用形参的默认值。
def hello2(name='Anonym', sex='女'):
if sex == '男':
print("Hello, Mr", name)
elif sex == '女':
print("Hello, Mrs", name)
hello2('li','男') #Hello, Mr li
1.3 函数的返回值
函数并非总是直接显示输出,相反,它可以处理一些数据,并返回一个或一组值,函数返回的值被称为返回值。在函数中,可使用return语句将值返回到调用函数的代码行。
def multiply(num1, num2):
return num1 * num2
print(multiply(2, 4))
multiply函数的功能是计算两个数相乘,我们传入两数字作为参数,希望能得到一个这两个数相乘的结果。multiply的最后一行使return 关键字将结果返回。通常在函数的最后一行返回结果,但有时候也有多种可能。
def permit(age):
if age >= 18:
print("准许进入")
return True
else:
print("禁止进入")
return False
print("end")
permit(18)
上面定义了一个只允许成年人进入的函数,如果年龄大于等于18岁,返回True,表示允许通过;如果小于18岁则不允许。虽然有两个return语句,但只返回一个结果,要么返回True要么返回False。注意在return语句执行完后,函数就会结束执行,在它之后的任何语句都不会再执行,所以上例中的“end”无论怎么样都不会被打印。
如果一个函数内没有任何return语句,那它的返回值就是None。
def do_nothing():
pass
print(do_nothing())
返回列表中的最大最小值
def find_min_max(nums):
nums.sort()
return nums[0], nums[-1]
min_max = find_min_max([2, 3, 5, 6, 1, 4])
print(min_max) #(1,6)
min, max = find_min_max([2, 3, 5, 6, 1, 4])
print(min, max) #1,6
1.4 匿名函数
定义了一个匿名函数
square1 = lambda n: n * n
相当于
def square2(n):
return n * n
print(square1(2))
print(square2(2))
lambda是Python中的关键字,它的作用就是用来定义匿名函数,匿名函数的函数体一般只有一行代码,省略了函数名和返回值语句。
key = lambda x: x[1]
key([1, 2]) # 2
key("abcd") # 'b'
key函数的作用就是返回序列中的第二个元素,在sort排序的时候就会以每个元素的第二个元素作为比对的依据。
再看两个例子:
plus = lambda x, y, z: x + y + z
print(plus(1, 2, 3))
#6
key参数使用每个原始的第二个索引的和作为排序依据
revenue = [('1季度', (5610000, 5710000, 5810000)),
('2季度', (4850000, 4850000, 4850000)),
('3季度', (6220000, 6320000, 6420000))]
revenue.sort(reverse=True, key=lambda x: sum(x[1]))
print(revenue)
#[('3季度', (6220000, 6320000, 6420000)), ('1季度', (5610000, 5710000, 5810000)), ('2季度', (4850000, 4850000, 4850000))]
2 面向对象
2.1 类和实例
面向过程:根据业务逻辑从上到下写代码。
面向对象:将变量与函数、属性绑定到一起,分类进行封装,每个程序只要负责分配给自己的功能,这样能够更快速的开发程序,减少了重复代码。
对象的属性就是可以精确描述事物的特点,对象的函数就是事物的行为。
类,它也是面试对象编程的基础。
class Dog:
pass
这样我们就定义了一个类,使用class关键字,加上一个类名,这样我们就定义了一个空的类。
类名一般使用名词,且使用驼峰式命名法。
类是创建对象的模板,对象是类的实例。类就像生产线,有了类,就可以生产出许许多多的相同对象。
使用上面的Dog类来创建一个Dog对象:
dog = Dog()
type(dog)
这里dog就是Dog的实例,通过内置的type函数,可以查看任何对象的类。
print(type(1)) #
print(type((1, 2))) #
print(type([1, 2])) #
它们分别是整数、元组和列表。
那dog的类型就是Dog。
class Dog:
pass
dog = Dog()
print(type(dog))
#
如果我们不知道一个对象是不是某种类型,就可以用type判断。
type('abc') == str # True
type(dog) == Dog # True
type(1) == int # True
也可以使用内置函数isinstance来判断对象与类的关系
isinstance('abd', str) # True
isinstance(1, int) # True
isinstance(dog, Dog) # True
2.2 对象的属性与方法
创建Dog类
class Dog:
def __init__(self):
self.breed = None
self.color = None
self.size = None
def eat(self):
print("I like bones")
def run(self):
print("I'll catch you.")
def bark(self):
print('Wang! Wang!')
类的每一个方法的第一个参数是 self ,必不可少,还必须位于其他形参的前面。但在调用的时候却不需要传参数给它。它是类方法和普通函数的区别,这个self代表的是实例自身,意思是“我的”,
创建Dog的实例
dog = Dog()
dog.eat()
dog.run()
dog.bark()
print('一只%s型%s色的%s' % (dog.size, dog.color, dog.breed))
调用方法
要调用方法,可指定实例的名称(这里是dog)和要调用的方法,并用句点分割。
调用不同的方法能打印出不同的内容,体现了不同的行为。但是最后一句话打印出来的内容却是None,因为我们还没有设置相应的属性。
设置属性
dog.breed = '哈士奇'
dog.color = '黑白'
dog.size = '大'
print('一只%s型%s色的%s' % (dog.size, dog.color, dog.breed))
# 一只大型黑白色的哈士奇
访问属性
要访问实例的属性,可使用句点表示法
print(dog.breed)
如果每个创建完每个对象之后还要一个个的设置属性,会很麻烦。我们可以使用__init__ 函数来接收始化参数,这样就可以把属性的值作为参数在初始化对象的时候就传给它。
__init__ 函数看起来与众不同的样子,它是Python的类用来初始化对象的构造函数,它的名字是固定的,必须这样写,创建对象时会首先调用它。改完后构造函数后代码如下:
class Dog:
# 构造函数,初始化函数
def __init__(self, breed, color, size):
self.breed = breed
self.color = color
self.size = size
def eat(self):
print("I like bones")
def run(self):
print("I'll catch your.")
def bark(self):
print('Wang! Wang!')
dog = Dog("哈士奇", '黑白', '中')
dog.eat()
dog.run()
dog.bark()
可以给参数默认值,就不用传递值给参数了
class Dog:
# 构造函数,初始化函数
def __init__(self, breed, color, size='大'):
self.breed = breed
self.color = color
self.size = size
def eat(self):
print("I like bones")
def run(self):
print("I'll catch your.")
def bark(self):
print('Wang! Wang!')
dog = Dog("哈士奇", '黑白')
对象自身的属性是直接可以方法里使用的,比如改造一下bark方法,让狗可以开口自我介绍
class Dog:
# 构造函数,初始化函数
def __init__(self, breed, color, size='大'):
self.breed = breed
self.color = color
self.size = size
def eat(self):
print("I like bones")
def run(self):
print("I'll catch your.")
def bark(self):
"""一只狗的自我介绍"""
print('Wang! Wang!')
print("一只%s型%s色的%s" % (self.size, self.color, self.breed))
dog2 = Dog('金毛犬', '金')
dog.bark()
# Wang! Wang!
一只大型金色的金毛犬
2.3 类属性与方法
2.3 类属性与方法
对象是从类创造的,对象的属性和方法虽然是在类中定义的,但它们的值是各个对象独有的,互相不能共享。而类也有属性和方法,且它们可以和类创建的所有对象共享。
先来定义一个类
class Goods:
def __init__(self):
self.name = ''
self.price = 0
self.discount = 1
Goods类有三个对象属性,每个商品有自己的名称、价格、折扣。
可以随意的创建商品
g1=Goods()
g2=Goods()
如何知道一共创建了多少个商品呢?可以给Goods类加一个计数器。
class Goods:
count = 0
def __init__(self):
Goods.count += 1
self.name = ''
self.price = 0
self.discount = 1
给Goods类加了一个属性count,每当调用 __init__ 函数时将它加1,就可以知道一共创建了多少商品对象了。这个count就是类属性,它可以通过对象访问,也可以通过类访问。
g1 = Goods()
g1.count # 1
g2 = Goods()
Goods.count # 2
即使没有定义对象,也可以直接访问count属性,这就是类属性,同样,类方法也不需要创建对象,通过类名就可以访问。
我们改造一下Goods类,给它增加一个属性id,表示商品唯一的序列号,为了保证id不重复,我们使用计数器,每创建一个商品给它加1。
class Goods:
id_count = 0
# 类方法
# 装饰器写法,classmethod用来定义类方法
@classmethod
def generate_id(cls):
cls.id_count += 1
return cls.id_count
def __init__(self):
# 商品唯一序号, 00001, 02738
# zfill函数表示用“0”将数字补足5位
self.id = str(self.generate_id()).zfill(5)
self.name = ''
self.price = 0
self.discount = 1
这里的 generate_id 方法就是一个类方法,它的上面一行有一个 @classmethod ,声明了它是类方法,它的参数不再是self,而是cls,指向类本身,用来在类方法内部访问类成员属性和方法。这个方法每次将id_count属性加1,并返回。
这种 @ 符号的写法叫做装饰器,装饰器是用来装饰函数的,不同的装饰器赋予函数不同的特殊功能。对于classmethod装饰器,大家只要知道它是用来定义类方法的就行了。
g1 = Goods()
g2 = Goods()
g1.id # 00001
g2.id # 00002
Goods.id_count # 2
2.4 一切皆对象
在Python中一切都是对象,我们使用的数字、字符串、函数甚至类本身,都是对象。
所有的对象都可以用type函数来判断它的类型,同时可以用dir函数来查看它的属性和方法。
dir(Dog)
会显示出dog对象的所有属性和方法,包括刚刚定义的那几个方法和属性。
对于对象,也可以使用help函数查看它的帮助文档。
帮助信息可以在定义的时候写入到代码里:
def bark(self):
"""一只狗的自我介绍"""
print('我是一只%s型%s色的%s' % (self.size, self.color, self.breed))
加上这句文档后,就可以使用help函数查看bark方法的帮助信息了,这有助于其他人使用我们的方法。
help(dog.bark)
help(Dog.bark)
一切皆对象是一句简单的话,但它的精神却很深邃,试试下面的代码
lst = []
lst.append(Dog)
dog = lst[0]('中', '黄')
lst.append(dog)
lst[1].bark()
lst[1].sleep = lambda: print('Good night.')
lst.pop().sleep()
有时候两个对象的值完全相同,我们可以说这两个对象是相等的,但不能说它们是同一个对象。
l1 = [1, 2, 3]
l2 = [1, 2,]
l1 == l2 # False
l2.append(3)
l1 == l2 # True
l1 is l2 # False
最后一行操作,使用 is 关键字来判断这两个对象是否是同一个对象,结果是False。它表明l1和l2是不同的对象,这一点可以使用id函数看出来:
id(l1)
id(l2)
分别返回两串不同的数字,这个一长串的数字代表了对象所指向的内存空间地址。
但赋值l3 =l1, l3会随l1变化,且指向同一内存空间地址,相当于同一个对象有两个名字
>>> l1 = [1,2,3]
>>> l3 = l1
>>> l3
[1, 2, 3]
>>> l1.append(4)
>>> l1
[1, 2, 3, 4]
>>> l3
[1, 2, 3, 4]
>>>
2.5 综合案例电商购物车商品统计分析
项目需求:可以设置每个商品的名称、价格、折扣率,用户将商品加入到购物车以后,能够立即显示所有商品、总价、折扣情况和实际需要支付的金额,也就是折扣后的金额。商品的名称、价格、折扣率都可以随意修改,且修改完成后,购物车中的相关信息和金额也会发生改变。
需求分析:在这个需求里面,提到了两个虚拟产物,商品与购物车,也就是说需要定义两个类。
class Goods:
"""商品类"""
id_count = 0
# 类方法
# 装饰器写法,classmethod用来定义类方法
@classmethod
def generate_id(cls):
cls.id_count += 1
return cls.id_count
def __init__(self, name, price, discount=1):
self.id = str(self.generate_id()).zfill(5)
self.name = name
self.price = price
self.discount = discount
def cal_price(self):
"""计算商品打折后的实际价格"""
return self.price * self.discount
#这是商品类,它有四个属性:ID、商品名称、价格、折扣,另外它还有一个函数,计算出商品打完折后的价格。接下来创建几个商品对象:
g1 = Goods('iPhone 11', 6000, 0.9)
g2 = Goods('U盘32G', 100, 0.8)
g3 = Goods('华为P40', 5000)
print(g1.name)
# 这样就创建了三个商品对象,并设置好了它们的名称、价格、折扣。接下来来编写购物车类:
class Cart:
"""购物车"""
def __init__(self):
self.cart = {}
self.goods_list = []
def add(self, goods, num=1):
"""向购物车中添加商品"""
if goods in self.goods_list:
self.cart[goods.id] += num
else:
self.goods_list.append(goods)
self.cart[goods.id] = num
def remove(self, goods, num):
"""从购物车减少或删除商品"""
if goods not in self.goods_list:
return
self.cart[goods.id] -= num
if self.cart[goods.id] <= 0:
del self.cart[goods.id]
self.goods_list.remove(goods)
cart是一个字典,用来保存商品和数量的对应关系,它的键名是商品ID(字符串);goods_list是一个列表,保存了购物车所有商品的详细信息(商品类实例),注意它们的数据结构。
有了Goods和Cart,我们就可以随意的增加删除商品,并可以随时查看购物车里的情况。
cart = Cart()
cart.add(g1)
cart.add(g2,3)
cart.add(g3,2)
print(cart.cart)
for goods in cart.goods_list:
print(goods.id,goods.name,cart.cart[goods.id],goods.price*cart.cart[goods.id]*goods.discount)
def get_total_amount(self):
"""获取当前购物车中的总价"""
amount = 0
for id,num in self.cart.items():
for goods in cart.goods_list:
if id == goods.id:
amount += goods.price * num
return amount
def get_pay_amount(self):
"""获取实际需要支付的总价"""
payamount = 0
for id, num in self.cart.items():
for goods in cart.goods_list:
if id == goods.id:
payamount += goods.cal_price() * num
return payamount
上面有重复代码,注意多次使用的代码定义成函数,函数的作用就是消除重复代码。上面代码可修改为:
def goods_by_id(self, id):
'''根据商品ID找到商品'''
for goods in cart.goods_list:
if id == goods.id:
return goods
def get_total_amount(self):
"""获取当前购物车中的总价"""
amount = 0
for id,num in self.cart.items():
goods = self.goods_by_id(id)
amount += goods.price * num
return amount
def get_pay_amount(self):
"""获取实际需要支付的总价"""
payamount = 0
for id, num in self.cart.items():
goods = self.goods_by_id(id)
payamount += goods.cal_price() * num
return payamount
展示商品信息:
def show(self):
"""显示当前购物车中所有商品的数量、价格,以及总价"""
print('商品id','\t','商品名称','\t','商品数量','\t','商品总价')
for id,num in self.cart.items():
goods = self.goods_by_id(id)
print(id,'\t',goods.name,'\t',num,'\t',goods.price*num)
total_amount = self.get_total_amount()
pay_amount = self.get_pay_amount()
print('总金额:',total_amount,'\n支付总金额:',pay_amount)
cart.show()
显示为:
为了格式对齐,改进代码如下:
def show(self):
"""显示当前购物车中所有商品的数量、价格,以及总价"""
title = ('商品id','商品名称','商品单价','商品数量','商品总价')
def show_row(row):
"""内部定义函数,显示购物车中的一行"""
for col in row:
print(str(col).ljust(12),end='\t')
print()
print("-" * 70)
show_row(title)
for id,num in self.cart.items():
goods = self.goods_by_id(id)
price = '%.2f' % goods.price
if goods.discount < 1:
price = '%.2f(%.d折)' % (goods.price,goods.discount*10)
show_row((id, goods.name, price, num, '%.2f' %(goods.cal_price()*num)))
total_amount = self.get_total_amount()
pay_amount = self.get_pay_amount()
discount_amount = total_amount - pay_amount
show_row(('', '', '', '', '商品总金额:%.2f' % total_amount))
if discount_amount > 0:
show_row(('', '', '','','优惠总金额:%.2f' % discount_amount))
show_row(('', '', '', '','支付总金额:%.2f' % pay_amount))
cart.show()
显示如下:
可以继续增加或者删除,并随时可以查看购物车的商品、计算总金额。如果商品的数量为零,则会从购物车中被删除
cart.remove(g2, 2)
cart.show()
cart.remove(g2, 1)
cart.show()
如果商品的名称、价格或者折扣发生了变化,我们只需要修改商品对象就可以了,其他的代码都不用修改,购物车中的信息会实时的跟随调整。
cart.add(g3)
cart.show()
g3.name = '华为P40 pro'
cart.show()
可以看到,在修改了g3对象的商品名称之后,再次显示购物车时发生了变化 ,而我们的Cart类不用修改任何代码,这样做到了不同实体之间的操作隔离
3 模块和包管理
Python中具有丰富的标准库和第三方库,学习并掌握模块、包的概念尤为重要,决定了是否能够利用这些丰富的资源,以及如何妥善组织好自己的代码。
3.1 模块的导入
首先,来导入一个内置模块
import math
math是Python标准库中的一个模块,用来进行数学运算,在上面使用 import 关键字将它导入了,就可以使用它的功能啦。
# 求一个数的平方根
math.sqrt(4)
现在我们可以使用math模块里的所有函数了,可以使用dir来看一下都有哪些函数
dir(math)
也可以使用from ... import ... 这种语句来具体导入某一个子模块或函数
from math import sqrt
sqrt(4)
这种方式更精确的导入某个函数,使用起来更方便, 但要注意重名的问题。如果说我们的代码本来就有一个叫sqrt的函数,那我们可以使用 as 关键字来给模块起一个别名
from math import sqrt as squarte
def sqrt(num):
pass
squarte(4) # 2
或者是这样:
import math as math2
math = 0
math2.sqrt(4) # 2
有时候需要一次性导入多个模块,可以这样写
import sys, os
from math import sqrt, pow
注意,在实际调用模块之前,必须先导入,否则将会产生报错。
# 将会产生NameError
math.sqrt(4)
import math
如果导入一个不存在的模块,也会产生报错
# 将会产生ModuleNotFoundError: No module named 'maht'
import maht
3.2 自定义模块
除了使用标准库的模块,我们也可以自己定义模块,实际上,这也是我们在项目中组织代码的基本方式。以上一个综合案例“电商购物车”为例,实际的文件结构应该是这样的:
└── project
├── cart.py # Cart类
├── goods.py # Goods类
└── main.py # 入口文件
shopcart目录里面,有三个文件,不同的类写在不同的文件内,cart.py和goods.py文件和原来保持一致即可。我们来看看main.py
from cart import Cart
from cart import * 全部导入
from goods import Goods
g1 = Goods('iPhone 11', 6000, 0.9)
g2 = Goods('U盘32G', 100, 0.8)
g3 = Goods('华为P40', 5000)
cart = Cart()
cart.add(g1)
cart.add(g2, 3)
cart.show()
main.py作为项目的入口文件,我们实际运行的时候就是从它启动
python main.py
那Python解释器是怎么找到cart和goods模块的呢?因为它们和main.py在同一个目录下,所以可以自动的发现它们。那如果有很多这样的模块,我们想把它们放到同一个目录下,以便统一管理,该怎么做呢? 比如,需要将cart.py 和 goods.py放到shopcart包内,调整目录结构如下:
├── project
│ ├── main.py
│ └── shopcart
│ ├── __init__.py
│ ├── cart.py
│ └── goods.py
如果发现目录内有名为 pycache 的文件夹,那是Python在导入时自动生成的缓存文件,可以忽略。
在mian.py同级目录下,多了一个shopcart目录,注意,shopcart目录里除了cart.py和goods.py目录,还多了一个 __init_.py ,这是一个空文件,它的文件名看起来很奇怪,这是Python规定的命名规范,只要目录有一个名为 __init_.py的文件,则将这个目录视为(package),现在修改main.py,作一下调整:
from shopcart.cart import Cart
from shopcart.goods import Goods
同时将下面的部分也做一下调整
if __name__ == '__main__':
g1 = Goods('iPhone 11', 6000, 0.9)
g2 = Goods('U盘32G', 100, 0.8)
g3 = Goods('华为P40', 5000)
cart = Cart()
cart.add(g1)
cart.add(g2, 3)
cart.show()
__name__ 表示当前文件所在模块的名称,模块可以通过检查自己的__name__来得知是否运行在main 作用域中,这使得模块可以在作为脚本运行时条件性地执行一些代码,而在被 import 时不会执行。
3.3 常用内置模块
除了上面使用过的math模块以外,Python还有大概100多个内置模块,下面来介绍一下常用的几个模块。
datetime - 日期时间类型
datetime模块中包含了几个常用的日期时间类,其中最常用的是datetime和timedelta。
注意,我们在下面使用的datetime是指datetime类而不是datetime模块。
from datetime import datetime, timedelta
# 返回当前时间的datetime对象
now = datetime.now()
type(now)
# 查看当前时间的年、月、日
print(now.year, now.month, now.day)
# 查看当前时间的时间戳,精确到微秒
now.timestamp()
print(datetime.now().timestamp())
计算机中时间的起始点都是1970年1月1日00:00:00,时间戳就是从1970年1月1日00:00:00到现在总秒数。所以如果时间戳A比时间戳B的值小,说明A在B之前。
datetime也提供将日期时间对象和字符串相互转换的操作,这在处理数据时会经常使用。
# 返回指定格式的日期字符串
datetime.now().strftime('%Y-%m-%d %H:%M:%S') # 2020-08-10 20:29:41
datetime.now().strftime('%H:%M:%S %Y/%m/%d')) # 20:30:50 2020/11/29
# 将指定格式的字符串转换为日期时间对象
datetime.strptime('2020-01-01 00:00:00', '%Y-%m-%d %H:%M:%S')
%Y这种形式是日期时间的格式代码,下面是一些常用的代码含义:
还有很多格式,可以查看Python官方文档:
只要得到了datetime对象,我们就可以把它转换成各种格式。同样,只要有一个相对标准化的格式,我们就可以将它转换为datetime对象。
得到datetime对象后,可以对它进行修改,显示去年的今天现在这个时候的时间
now = datetime.now()
last_year = now.replace(year=2019)
print(last_year.strftime('%Y-%m-%d %H:%M:%S'))
如果想知道两个datetime对象之间相差多长时间,可以将这两个对象相减,得到的对象就是一个timedelta对象,我们可以根据timedelta对象知道这两个时间相差多少天多少分多少秒。
delta = now - last_year
print(delta) #366 days, 0:00:00
print(type(delta)) #
print(delta.days, delta.seconds) #366 0
现在得到delta就是一个timedelta对象, 它表示366天整的时间,我们也可以将一个datetime对象和一个timedelta对象相加,将会得到一个新的datetime对象. 将当前时间加上366天,就是明年的明天。
timedalte 是datetime中的一个对象,该对象表示两个时间的差值
构造函数:datetime.timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0) 其中参数都是可选,默认值为0
timedelta类提供了非常便捷的方式帮我们处理日期时间:
from datetime import timedelta
# 明年的今天
print(now + delta) #2021-11-30 20:56:14.603773
# 20天以后的时间
print(now + timedelta(days=20)) #2020-12-19 20:56:14.603773
# 两个半小时之前的时间
print(now - timedelta(hours=2, minutes=30)) #2020-11-29 18:26:14.603773
3.3.2 time - 时间的访问和转换
还有一个经常使用的时间模块time
import time
# 返回当前时间戳
time.time() #1606654855.7623074
# 返回当前时间的格式化字符串
time.strftime('%Y-%m-%d %H:%M:%S') #2020-11-29 21:00:55
其实time模块的另一个函数我们也经常使用,它可以使我们的程序暂时睡一会儿
print("好累呀,我要小睡3秒钟")
time.sleep(3)
print("好啦,我又元气满满!")
sleep函数会将当前的程序暂停若干秒数。
3.3.3 random - 生成随机数
准确的说是生成伪随机数,这是一个数学问题。默认random模块会根据当前的系统时间作为随机数种子,所以可以保证生成的随机数不会重复。
import random
# 生成一个随机浮点数,范围[0.0, 1.0)
random.random()
# 生成1到100之间的随机整数,包括1和100
random.randint(1, 100)
# 从序列中随机抽出一个元素
az=[chr(i) for i in range(65, 65 + 26)]
random.chioce(az)
random.choice(['a', 'b', 'c', 'd', 'e', 'f', 'g'])
# 从序列中随机抽出k个元素,注意抽出来的元素可能会重复
random.choices(['a', 'b', 'c', 'd', 'e', 'f', 'g'], k=2)
>>> random.choice(az)
'N'
>>> ''.join(random.choices(az,k=3))
'QON'
>>> '-'.join(random.choices(az,k=3))
'J-S-K'
# 跟choices函数类似,但它是不重复的随机抽样
random.sample(['a', 'b', 'c', 'd', 'e', 'f', 'g'])
# 将一个序列随机打乱,注意这个序列不能是只读的
lst = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
random.shuffle(lst)
3.3.4 os - 操作系统接口
os模块提供了一种使用与操作系统相关的功能的便捷式途径。需要大家了解一些操作系统的知识。
# 获取当前的工作目录
print(os.getcwd())
# 创建目录,只能创建一层目录
os.mkdir(os.getcwd() + '/test')
os.mkdir(os.getcwd() + '/abc')
# 创建多层目录
os.makedirs(os.getcwd() + '/def/123')
# 返回一个列表,该列表包含了 path 中所有文件与目录的名称
os.listdir(os.getcwd())
# 返回一个列表,该列表包含了根目录中所有文件与目录的名称
os.listdir('/')
另一个很常用的子模块就是os.path,它提供了常用的路径操作。
# 显示当前目录的绝对路径
os.path.abspath('./')
os.path.abspath("__file__")在大部分操作系统中,一般用 . 表示当前目录,用 .. 表示父级目录
相对路径:相对于当前目录的路径
绝对路径:以根目录为开始的路径(windows和Mac、Linux的根目录不同)
目录分隔符:windows 是 \ , Mac 和 Linux中是 /
# .表示当前目录,..表示父级目录
print(os.path.abspath('..'))
# 相对路径 ./text.txt ../test/abc.py
# 绝对路径 /Users/xxx/projects c:\documents\readme.txt
# 目录分隔符: Windows: \ Mac和Linux /
cur_file = os.path.abspath(__file__)
# 判断“文件“是否存在
print(os.path.isfile(cur_file)) #True
print(os.path.isfile('/Users/xxx/projects')) #False
# 输出当前系统下的目录分隔符
print(os.sep) #\
# 多个路径拼到一起
print(os.path.join(os.getcwd(), 'def', '123'))
print(os.path.dirname(cur_file))
print(os.path.basename(cur_file))
print(os.path.basename('/tmp/test'))
# 如果 path 是 现有的 目录,则返回 True。
os.path.isdir(path)
# 如果 path 是 现有的 常规文件,则返回 True。
os.path.isfile()
# 目录分隔符
os.sep
# 合理地拼接一个或多个路径部分。
os.path.join(path, *paths)
# 返回路径 path 的目录名称
os.path.dirname("/tmp/test.txt") # '/tmp'
# 返回路径 path 的基本名称,文件名或是最后一级的目录名
os.path.basename("/tmp/test.txt") # 'test.txt'
os.path.basename("/tmp/test") # 'test'
(未完待续)