目录
========第四部分 Python进阶========
第一节 函数
4.1.1 函数定义及调用
4.1.2 函数的参数
4.1.3 函数的返回值
第二节 面向对象
4.2.1 面向对象基本概念
4.2.2 类和实例
4.2.3 对象的属性与方法
4.2.4 类属性与方法
4.2.5一切皆对象
4.2.6 综合案例-电商购物车商品统计分析
4.2.7 自定义属性-property
第三节 模块和包管理
4.3.1 模块的导入
4.3.2 自定义模块
4.3.3 常用内置模块
datetime - 日期时间类型
time - 时间的访问和转换
random - 生成随机数
os - 操作系统接口
sys - 系统相关参数及函数
========第四部分 Python进阶========
第一节函数
在前面的学习过程中,我们已经接触了很多次函数,现在我们来好好的认识一下这个重要的小伙伴。函数就是一段可以重复调用的代码,在Python中函数是非常重要的概念,在编程中几乎无处不在。
4.1.1函数定义及调用
在Python在, 我们使用def关键字来定义函数
def hello(name):print("Hello", name)
上面的代码定义了一个 简单的函数,它的作用就是打印出"Hello"加一个名字。我们看看它的结构:
调用hello函数,将会打印“Hello, Python”
hello("Python")
在这个过程中发生什么什么事呢?这实际上是将name传递给hello函数,也就是将name的值设置为"Python",并执行函数体内的代码。
4.1.2函数的参数
函数的参数可以有一个,也可以有多个,也可以没有参数。这取决于在定义函数的时候如何定义参数部分。刚才我们定义的函数只有一个参数,现在我们定义两个参数的函数。
def hello(name, sex):if sex == '男':print("Hello, Mr", name)elif sex == '女':print("Hello, Miss", name)
这个函数有两个参数,name和sex,分别表示用户的名字和性别,以便显示不同的尊称。我们在调用的时候,要注意参数的顺序,不能前后颠倒。调用函数:
hello("Zhang", "男")hello("Wang", "女")
如果参数较多,记不清它们的顺序,可以写上参数名,这样就不用管顺序了。
hello(sex='男', name='Zhang')
如果说用户大多数是女的,只有少部分的男性,那这个函数还可以改造一下,我们让它的sex参数默认就是“女”:
def hello(name, sex='女'):if sex == '男':print("Hello, Mr", name)elif sex == '女':print("Hello, Miss", name)
和上面的函数相比,只是在sex参数后面加上一个默认值,这样,后面用户没有填性别信息的时候,就会默认为女性。
hello("Wang")
如果每一个参数都有默认值,在调用的时候甚至可以不传参数。
def hello(name='Anonym', sex='女'):if sex == '男':print("Hello, Mr", name)elif sex == '女':print("Hello, Miss", name)hello() # Hello, Miss Anonym
现在这个函数对于信息不完整的数据也有处理能力了。
4.1.3函数的返回值
如果将函数比做一名员工,调用函数的我们就是老板,老板给员工一些具体的指示,员工则按规定好的流程去做事。有一些事情,比如老板说去打扫一下厕所,员工就默默地去干活了,干完了就完事了。如果是一些需要回复的事情,比如老板让员工去算一下去年公司的收入,那老板的意思肯定是要知道 后算出来的那个数字。对于函数也是一样,有一些函数我们是需要知道执行的结果。
def multiply(num1, num2):return num1 * num2n = multiply(2, 4)print(n) # 8
multiply函数的功能是计算两个数相乘,我们传入两数字作为参数,希望能得到一个这两个数相乘的结果。
multiply的最后一行使用return 关键字将结果返回。通常在函数的最后一行返回结果,但有时候也有多种可能。
def permit(age):if age >= 18:print("准许进入")return Trueelse:print("禁止进入")return Falseprint("end")
multiply的 后一行使用return关键字将结果返回。通常在函数的 后一行返回结果,但有时候
上面我们定义了一个只允许成年人进入的函数,如果年龄大于等于18岁,返回True,表示允许通过;如果小于18岁则不允许。虽然有两个return语句,但只返回一个结果,要么返回True要么返回False。注意在return语句执行完后,函数就会结束执行,在它之后的任何语句都不会再执行,所以上例中的“end”无论怎么样都不会被打印。
如果一个函数内没有任何return语句,那它的返回值就是None。
def do_nothing():passprint(do_nothing()) # None
4.1.4匿名函数
有时候我们临时需要一个函数,且它的逻辑比较简单,这时候就可以定义匿名函数。
lambda n: n * n
这就定义了一个匿名函数,这个匿名函数接收一个数值参数,计算出这个数的平方值并返回,就相当于下面的函数
def square(n):return n * n
lambda是Python中的关键字,它的作用就是用来定义匿名函数,匿名函数的函数体一般只有一行代码,省略了函数名和返回值语句。
这样的函数它的作用是什么呢?什么时候需要使用匿名函数而不是函数呢?回忆一下,我们在学习列表排序的时候用过一个匿名函数,现在是时候重温一下了。
revenue = [('1月', 5610000), ('2月', 4850000), ('3月', 6220000)]revenue.sort(reverse=True, key=lambda x:x[1])
列表的sort函数key参数,它只能接收一个函数类型的值。单独看一下这段匿名函数:
key = lambda x: x[1]
现在key就是一个函数了,我们来调用一下它,x[1]这种索引操作说明x肯定是个序列,且长度至少为2。
key([1, 2]) # 2key("abcd") # 'b'
key函数的作用就是返回序列中的第二个元素,在sort排序的时候就会以每个元素的第二个元素作为比对的依据。在这个例子中,第二个元素就是月收入,所以是不是达到了以月收入排序的目的了?
这样的一个简单的功能,我们用不着单独定义一个函数,即用即抛,就像一次性手套一样,这正是匿名函数的使用场景。
值和引用*
作用域/global*
yield表达式*
可变参数*
装饰器*
第二节面向对象
4.2.1面向对象基本概念
面向过程:根据业务逻辑从上到下写代码。
面向对象:将变量与函数、属性绑定到一起,分类进行封装,每个程序只要负责分配给自己的功能,这样能够更快速的开发程序,减少了重复代码。
我们在前面写的代码都是面向过程的,这对初学者比较容易接受,而且,对于比较简单的需求,用面向过程实现起来确实更简单。
那什么是对象呢 ?我们可以理解为实际存在的实物,比如一个用户、一台ATM机、一幢建筑,亦或者是软件业务流程中产生的虚拟概念,比如订单、购物车、用户账户。我们发现,不管是实体还是虚拟产物,它们都是有一些共同点,都是名词,有自己的行为,有自己的属性。比如说用户对象,用户都有相同的几个属性,名字、年龄、性别、注册时间、上一次登录的时间等等。但不同用户这个几属性的值却都不一样。下面我们来看几个例子。如果你想向另一个人描述一只狗,那你会说出这只狗的哪几个特点?品种颜色
体型大小
狗会有哪些行为呢?
吃东西奔跑吠叫
这些都是我们基于常识总结出来的狗的特点和行为,对象的属性就是可以精确描述事物的特点,对象的函数就是事物的行为。
4.2.2 类和实例
现在我们用代码来实现一下“狗”对象,先介绍Python里的一个重要概念:类,它也是面试对象编程的基础。
class Dog:pass
这样我们就定义了一个类,使用class关键字,加上一个类名,这样我们就定义了一个空的类。
类名一般使用名词,且使用驼峰式命名法。
类是创建对象的模板,对象是类的实例。类就像生产线,有了类,就可以生产出许许多多的相同对象。
使用上面的Dog类来创建一个Dog对象:
dog = Dog()type(dog)
这里dog就是Dog的实例,通过内置的type函数,可以查看任何对象的类。
type(1)type('abc')type([])
这些都是我们学习过的数据类型,我们看到它们分别是整数、字符串和列表。那dog的类型就是Dog。
如果我们不知道一个对象是不是某种类型,就可以用type判断。
type('abc') == str # Truetype(dog) == Dog # Truetype(1) == int # True
也可以使用内置函数isinstance来判断对象与类的关系
isinstance('abd', str) # Trueisinstance(1, int) # Trueisinstance(dog, Dog) # True
4.2.3对象的属性与方法
现在我们来完整的实现一下Dog 类
class Dog:def __init__(self):self.breed = Noneself.color = Noneself.size = Nonedef 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))
调用不同的方法能打印出不同的内容,体现了不同的行为。但是最后一句话打印出来的内容却是None,因为我们还没有设置相应的属性。
dog.breed = '哈士奇'dog.color = '黑白'dog.size = '大'print('一只%s型%s色的%s' % (dog.size, dog.color, dog.breed))# 一只大型黑白色的哈士奇
如果每个创建完每个对象之后还要一个个的设置属性,会很麻烦。我们可以使用__init__ 函数来接收初始化参数,这样就可以把属性的值作为参数在初始化对象的时候就传给它。大家应该也注意到了,__init__ 函数看起来与众不同的样子,它是Python的类用来初始化对象的构造函数,它的名字是固定的,必须这样写,创建对象时会首先调用它。改完后构造函数后代码如下:
class Dog:def __init__(self, size, color, breed='土狗'):self.breed = breedself.color = colorself.size = sizedef eat(self):print("I like bones")def run(self):print("I'll catch you.")def bark(self):print('Wang! Wang!')
现在再来创建对象:
dog = Dog('中', '黄')print('一只%s型%s色的%s' % (dog.size, dog.color, dog.breed))
第三个参数breed因为给了它默认值,所以可以不用传。
我们在之前学习的字符串、列表的所有函数,实际是调用字符串对象、列表对象的方法。
对象自身的属性是直接可以方法里使用的,比如我们改造一下bark方法,让狗可以开口自我介绍
class Dog:def __init__(self, size, color, breed='土狗'):self.breed = breedself.color = colorself.size = sizedef eat(self):print("I like bones")def run(self):print("I'll catch you.")def bark(self):print('我是一只%s型%s色的%s' % (self.size, self.color, self.breed))
这里在bark方法里使用的self和构造函数里的self一样,都是指向对象自身。
dog = Dog("小", "棕", "泰迪犬")dog.bark()
4.2.4类属性与方法
对象是从类创造的,对象的属性和方法虽然是在类中定义的,但它们的值是各个对象独有的,互相不能共享。而类也有属性和方法,且它们可以和类创建的所有对象共享。我们先来定义一个类
class Goods:def __init__(self):self.name = ''self.price = 0self.discount = 1
Goods类有三个对象属性,每个商品有自己的名称、价格、折扣。我可以随意的创建商品
g1 = Goods()g2 = Goods()
但如何知道一共创建了多少个商品呢?我们可以给Goods类加一个计数器。
class Goods:count = 0def __init__(self):Goods.count += 1self.name = ''self.price = 0self.discount = 1
我们给Goods类加了一个属性count,每当调用__init__ 函数时将它加1,这样我们就可以知道一共创建了多少商品对象了。这个count就是类属性,它可以通过对象访问,也可以通过类访问。
g1 = Goods()g1.count # 1g2 = Goods()Goods.count # 2
即使没有定义对象,也可以直接访问count属性,这就是类属性,同样,类方法也不需要创建对象,通过类名就可以访问。我们改造一下Goods类,给它增加一个属性id,表示商品唯一的序列号,为了保证 id不重复,我们使用计数器,每创建一个商品给它加1。
class Goods:id_count = 0@classmethoddef generate_id(cls):cls.id_count += 1return cls.id_countdef __init__(self):# zfill函数表示用“0”将数字补足5位self.id = str(self.generate_id()).zfill(5)self.name = ''self.price = 0self.discount = 1
这里的generate_id 方法就是一个类方法,它的上面一行有一个@classmethod ,声明了它是类方法,它的参数不再是self,而是cls,指向类本身,用来在类方法内部访问类成员属性和方法。这个方法每次将id_count属性加1,并返回。
这种@ 符号的写法叫做装饰器,装饰器是用来装饰函数的,不同的装饰器赋予函数不同的特殊功能。对于classmethod装饰器,大家只要知道它是用来定义类方法的就行了。
现在我们再来试试:
g1 = Goods()g2 = Goods()g1.id # 00001g2.id # 00002Goods.id_count # 2
4.2.5一切皆对象
在Python中一切都是对象,我们使用的数字、字符串、函数甚至类本身,都是对象。所有的对象都可以用type函数来判断它的类型,同时可以用dir函数来查看它的属性和方法。
dir(dog)
会显示出dog对象的所有属性和方法,包括刚刚定义的那几个方法和属性。对于对象,也可以使用help 函数查看它的帮助文档。
help(sum)help(print)
这些帮助信息可以在定义的时候写入到代码里:
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 # Falsel2.append(3)l1 == l2 # Truel1 is l2 # False
最后一行操作,使用is 关键字来判断这两个对象是否是同一个对象,结果是False。它表明l1和l2是不同的对象,这一点可以使用id函数看出来:
id(l1)id(l2)
分别返回两串不同的数字,这个一长串的数字代表了对象所指向的内存空间地址。
4.2.6综合案例-电商购物车商品统计分析
项目需求:可以设置每个商品的名称、价格、折扣率,用户将商品加入到购物车以后,能够立即显示所有商品、总价、折扣情况和实际需要支付的金额,也就是折扣后的金额。商品的名称、价格、折扣率都可以随意修改,且修改完成后,购物车中的相关信息和金额也会发生改变。
需求分析:在这个需求里面,提到了两个虚拟产物,商品与购物车,也就是说需要定义两个类。
class Goods:"""商品类"""id_count = 0@classmethoddef generate_id(cls):cls.id_count += 1return cls.id_countdef __init__(self, name, price, discount=1):self.id = str(self.generate_id()).zfill(5)self.name = nameself.price = priceself.discount = discountdef calc_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)
这样我们就创建了三个商品对象,并设置好了它们的名称、价格、折扣。接下来我们来编写购物车类:
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] = self.cart[goods.id] + numelse:self.goods_list.append(goods)self.cart[goods.id] = numdef remove(self, goods, num):"""从购物车减少或删除商品"""if goods not in self.goods_list:returnself.cart[goods.id] -= numif self.cart[goods.id] <= 0:del self.cart[goods.id]self.goods_list.remove(goods)def get_goods_by_id(self, id):"""根据商品名称查找商品"""for g in self.goods_list:if g.id == id:return gdef get_total_amount(self):"""获取当前购物车中的总价"""amount = 0for name, num in self.cart.items():goods = self.get_goods_by_id(name)amount += goods.price * numreturn amountdef get_pay_amount(self):"""获取实际需要支付的总价"""amount = 0for name, num in self.cart.items():goods = self.get_goods_by_id(name)amount += goods.calc_price() * numreturn amountdef show(self):"""显示当前购物车中所有商品的数量、价格,以及总价"""title = ('商品', '单价', '数量', '价格(元)')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.get_goods_by_id(id)price = '%.2f' % goods.priceif goods.discount < 1:price = '%.2f (%d折)' % (goods.price, goods.discount * 10)show_row((goods.name, price, num, '%.2f' % (goods.calc_price() * num)))total_amount = self.get_total_amount()pay_amount = self.get_pay_amount()discount_amount = total_amount - pay_amountshow_row(('', '', '', '总金额: %.2f' % total_amount))if discount_amount > 0:show_row(('', '', '', '优惠: %.2f' % discount_amount))show_row(('', '', '', '实付金额: %.2f' % pay_amount))
这是购物车类,看起来它的代码很长。共有两个属性,6个方法。其实这个类主要就是提供了三个功能:
增加商品 add
减少商品 remove
显示商品 show
其他的函数都是辅助实现这三个主要功能。cart是一个字典,用来保存商品和数量的对应关系,它的键名是商品ID(字符串);goods_list是一个列表,保存了购物车所有商品的详细信息(商品类实例),注意它们的数据结构。有了Goods和Cart,我们就可以随意的增加删除商品,并可以随时查看购物车里的情况。
cart = Cart()cart.add(g1)cart.add(g2, 3)cart.show()
显示如下:
商品单价 数量 价格(元)
iPhone 11 6000.00 (9折) 1 5400.00
U盘32G 100.00 (8折) 3 240.00
总金额: 6300.00
优惠: 660.00
实付金额: 5640.00
我们可以继续增加或者删除,并随时可以查看购物车的商品、计算总金额。如果商品的数量为零,则会从购物车中被删除
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类不用修改任何代码,这样做到了不同实体之间的操作隔离,是不是有点感受到面向面向对象的便捷了呢?
4.2.7 自定义属性-property
Cart类中的这两个函数get_total_amount 和get_pay_amount ,每次调用它们的时候都是直接调用,没有传递任何参数,最后返回一个值。对于这种方法,其实可以把它们变成property(属性):
@propertydef total_amount(self):"""获取当前购物车中的总价"""amount = 0for name, num in self.cart.items():goods = self.get_goods_by_id(name)amount += goods.price * numreturn amount@propertydef pay_amount(self):"""获取实际需要支付的总价"""amount = 0for name, num in self.cart.items():goods = self.get_goods_by_id(name)amount += goods.calc_price() * numreturn amount
我们在函数名前面加了一个property装饰器,修改方法名,去掉了get_ ,其实方法名也可以不改,在这里修改是为了代码的可读性更通顺。改造后,使用这两个方法时,就可以像使用普通属性一样:
cart.total_amountcart.pay_amount
这样使用起来是不是更简洁优雅了呢?
继承*
魔术方法*
第三节模块和包管理
Python中具有丰富的标准库和第三方库,学习并掌握模块、包的概念尤为重要,决定了我们是否能够利用这些丰富的资源,以及如何妥善组织好我们自己的代码。
4.3.1模块的导入
首先,我们来导入一个内置模块
import math
math是Python标准库中的一个模块,用来进行数学运算,我们在上面使用import 关键字将它导入了,现在我们就可以使用它的功能啦。
# 求一个数的平方根math.sqrt(4)
现在我们可以使用math模块里的所有函数了,可以使用dir来看一下都有哪些函数
dir(math)
我们也可以使用from ... import ... 这种语句来具体导入某一个子模块或函数
from math import sqrtsqrt(4)
这种方式更精确的导入某个函数,使用起来更方便, 但要注意重名的问题。如果说我们的代码本来就有一个叫sqrt的函数,那我们可以使用as 关键字来给模块起一个别名
from math import sqrt as squartedef sqrt(num):passsquarte(4) # 2
或者是这样:
import math as math2math = 0math2.sqrt(4) # 2
有时候需要一次性导入多个模块,可以这样写
import sys, osfrom math import sqrt, pow
注意,在实际调用模块之前,必须先导入,否则将会产生报错。
# 将会产生NameErrormath.sqrt(4)import math
如果导入一个不存在的模块,也会产生报错
# 将会产生ModuleNotFoundError: No module named 'maht'import maht
4.3.2自定义模块
除了使用标准库的模块,我们也可以自己定义模块,实际上,这也是我们在项目中组织代码的基本方式。以上一个综合案例“电商购物车”为例,实际的文件结构应该是这样的:
└── project├── cart.py # Cart类├── goods.py # Goods类└── main.py # 入口文件
shopcart目录里面,有三个文件,不同的类写在不同的文件内,cart.py和goods.py文件和原来保持一致即可。我们来看看main.py
from cart import Cartfrom goods import Goodsg1 = 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在导入时自动生成的缓存文件,可以忽略。
from shopcart.cart import Cartfrom shopcart.goods import Goods
在mian.py同级目录下,多了一个shopcart目录,注意,shopcart目录里除了cart.py和goods.py目录,还多了一个__init__.py ,这是一个空文件,它的文件名看起来很奇怪,这是Python规定的命名规范,只要目录有一个名为__init__.ppy 的文件,则将这个目录视为包(package),现在修改main.py,作一下调整:
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 时不会执行。
4.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()
计算机中时间的起始点都是1970年1月1日00:00:00,时间戳就是从1970年1月1日00:00:00到现在总秒数。所以如果时间戳A比时间戳B的值小,说明A在B之前。
datetime也提供将日期时间对象和字符串相互转换的操作,这在处理数据时会经常使用。
# 返回指定格式的日期字符串, 下面的返回 "-08-10 20:29:41"datetime.now().strftime('%Y-%m-%d %H:%M:%S')# 将指定格式的字符串转换为日期时间对象datetime.strptime('-01-01 00:00:00', '%Y-%m-%d %H:%M:%S')
%Y这种形式是日期时间的格式代码,下面是一些常用的代码含义:
还有很多格式,可以查看Python官方文档:
/zh-cn/3/library/datetime.html#strftime-strptime-behavior
只要得到了datetime对象,我们就可以把它转换成各种格式。同样,只要有一个相对标准化的格式,我们就可以将它转换为datetime对象。
得到datetime对象后,可以对它进行修改,显示去年的今天现在这个时候的时间:
now = datetime.now()last_year = now.replace(year=)print(last_year.strftime('%Y-%m-%d %H:%M:%S'))
如果我们想知道两个datetime对象之间相差多长时间,可以将这两个对象相减
delta = now - last_yeartype(delta)
得到的对象就是一个timedelta对象,我们可以根据timedelta对象知道这两个时间相差多少天多少分多少秒。
delta.daysdelta.seconds
现在得到delta就是一个timedelta对象, 它表示366天整的时间,我们也可以将一个datetime对象和一个timedelta对象相加,将会得到一个新的datetime对象:
now + delta
将当前时间加上366天,就是明年的明天。timedelta类提供了非常便捷的方式帮我们处理日期时间,比如我们想要构造:
# 从当前开始20天后的时间datetime.now() + timedelta(days=20)# 两个半小时之前的时间datetime.now() - timedelta(hours=2, minutes=30
time - 时间的访问和转换
还有一个经常使用的时间模块time
import time# 返回当前时间戳time.time()# 返回当前时间的格式化字符串time.strftime('%Y-%m-%d %H:%M:%S')
其实time模块的另一个函数我们也经常使用,它可以使我们的程序暂时睡一会儿
print("好累呀,我要小睡3秒钟")time.sleep(3)print("好啦,我又元气满满!")
sleep函数会将当前的程序暂停若干秒数。
random - 生成随机数
准确的说是生成伪随机数,这是一个数学问题。默认random模块会根据当前的系统时间作为随机数种子,所以可以保证生成的随机数不会重复。
# 生成一个随机浮点数,范围[0.0, 1.0)random.random()# 生成1到100之间的随机整数,包括1和100random.randint(1, 100)# 从序列中随机抽出一个元素random.choice(['a', 'b', 'c', 'd', 'e', 'f', 'g'])# 从序列中随机抽出k个元素,注意抽出来的元素可能会重复random.choices(['a', 'b', 'c', 'd', 'e', 'f', 'g'], k=2)# 跟choices函数类似,但它是不重复的随机抽样random.sample(['a', 'b', 'c', 'd', 'e', 'f', 'g'])# 将一个序列随机打乱,注意这个序列不能是只读的lst = ['a', 'b', 'c', 'd', 'e', 'f', 'g']random.shuffle(lst)
os - 操作系统接口
os模块提供了一种使用与操作系统相关的功能的便捷式途径。需要大家了解一些操作系统的知识。
# 获取当前目录的路径os.getcwd()# 创建指定目录os.mkdir(path)# 与 mkdir() 类似,但会自动创建到达最后一级目录所需要的中间目录。os.makedirs(path)# 返回一个列表,该列表包含了 path 中所有文件与目录的名称。os.listdir()
另一个很常用的子模块就是os.path,它提供了常用的路径操作。
# 显示当前目录的绝对路径os.path.abspath('./')os.path.abspath("__file__")
在大部分操作系统中,一般用. 表示当前目录,用.. 表示父级目录
相对路径:相对于当前目录的路径
绝对路径:以根目录为开始的路径(windows和Mac、Linux的根目录不同)
目录分隔符:windows 是 \ , Mac 和 Linux中是 /
# 如果 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'
sys - 系统相关参数及函数
首先看的是sys.path,它返回的是一个列表,包含了若干个路径,它表示的是Python查找包的路径顺序,第一个是一个空字符串,它表示当前目录。之所以我们使用import 语句可以导入模块,靠的就是它。
sys.path['','/Users/envs/py3/bin','/Users/envs/py3/lib/python36.zip','/Users/envs/py3/lib/python3.6','/Users/envs/py3/lib/python3.6/lib-dynload','/Users/envs/py3/lib/python3.6/site-packages','/Users/envs/py3/lib/python3.6/site-packages/pyspider-0.3.10-py3.6.egg','/Users/envs/py3/lib/python3.6/site-packages/setuptools-27.2.0-py3.6.egg','/Users/envs/py3/lib/python3.6/site-packages/IPython/extensions','/Users/.ipython']
sys.argv 表示启动的时候传递给Python脚本的命令行参数。
import sysif __name__ == '__main__':print("Hello", end=' ')if len(sys.argv) > 1:print(' '.join(sys.argv[1:]))
上述是一个Python脚本hello.py 的代码,现在我们试着用不同的方式启动它
python hello.pypython hello.py Billpython hello.py Mr Gates
我们会看到每次的输出不一样,再加两行代码,看一看sys.argv是什么?
# sys.argv是个列表type(sys.argv)print(sys.argv)
可以看到sys.argv是一个列表,它的第一个元素就是脚本的文件名。所以传递它的启动参数,都会放在列表的后面。我们可以使用这种方式接收用户传递的参数。
7.1.3 Python进阶 《函数》定义 调用 参数 返回值《面向对象》概念 类 实例 对象 属性 方法《模块 包》导入 自定义 常用内置:datatime time random os sys