Python5 ---- 常用模块与面向对象
常用模块与面向对象
导入第三方模块
- 导包的层级关系
- 模块(module)
以文件为载体, 包含各类对象 - 包(package)
以文件夹为载体, 包含了各类模块 - 库(lib)
包含了各类包
- 模块(module)
import 库
from 库/模块 import 模块/函数
- 导包的命名冲突
通过as
这个关键词来给当前模块/函数取个别名from datetime import datetime as p_datetime
时间模块time
调用的都是系统级的接口, 提供时间的访问和转换的功能
- 查看时间
-
获取当前时间
# 有时区的 time.localtime() 返回的是一个time.struct_time对象
-
时间戳
time.time()
-
时间的格式化输出
now = time.localtime() now = time.strftime("%Y-%m-%d %H:%M:%S", now) print(now) # 可以省略时间对象 now = time.strftime("%Y-%m-%d %H:%M:%S")
-
运算
将时间对象转换为list
, 对相应的时间重新赋值后, 通过time.struct_time
生成一个新的时间对象time_list = list(time.localtime()) time_list[2] = 4 time.struct_time(time_list)
-
时间休眠
当前程序休眠n秒time.sleep(3)
-
时间模块datetime
封装了time, 提供了更高级和更友好的接口
-
查看时间
# 获取计算机时间, 返回的是一个datetime.datime对象.在交互式优先_repr__()接口,__str__() datetime.datetime.today() # 获取指定时区的时间 datetime.datetime.now(tz=None) # 获取utc时间 datetime.datetime.utcnow()
-
时间格式的转换
-
datetime.datetime
->str
now = datetime.datetime.now(tz=None) now.strftime("%Y-%m-%d %H:%M:%S")
-
str
->datetime.datetime
>>> now '2021-01-03 23:38:26' >>> datetime.datetime.strptime(now, "%Y-%m-%d %H:%M:%S") datetime.datetime(2021, 1, 3, 23, 38, 26)
-
datetime.datetime
->timestamp
>>> now datetime.datetime(2021, 1, 3, 23, 40, 45, 749240) >>> now.timestamp() 1609688445.74924
-
timestamp
->datetime.datetime
>>> ts 1609688445.74924 >>> datetime.datetime.fromtimestamp(ts, tz=None) datetime.datetime(2021, 1, 3, 23, 40, 45, 749240)
-
-
时间运算
-
timedelta
只作用于datetime.datetime
格式# 选中目标模块 ctrl+B / command+B 跳转到模块源码 def __new__(cls, days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0):
>>> from datetime import timedelta >>> now + timedelta(hours=-1) datetime.datetime(2021, 1, 3, 22, 40, 45, 749240)
-
课后作业
- 通过
datetime
模块完成时间戳,datetime.datetime
对象, 格式化字符串三者之间的转换
import datetime
now = datetime.datetime.now()
# datetime转str
time_str = now.strftime("%Y-%m-%d %H:%M:%S")
# str转datetime
str_time = datetime.datetime.strptime(time_str, "%Y-%m-%d %H:%M:%S")
# datetime转timestamp
time_smp = now.timestamp()
# timestamp转datetime
smp_time = datetime.datetime.fromtimestamp(time_smp)
- 封装一个函数
get_date(day_delta)
, 如果传入的是-1
, 输出就是字符串日期2020-01-02
.
import datetime
# from datetime import timedelta
def get_date(day=-1):
if day == -1:
now = datetime.datetime.now(tz=None)
# td = now + timedelta(days=day)
str_time = now.strftime('%Y-%m-%d')
print(str_time)
else:
print("请输入为-1,获取当前日期")
return
get_date()
类的创建, 实例化, 初始化
-
什么是类
类就是拥有相同功能或者相同属性的对象集合 -
类的创建
object
是所有类的基类class GoGamer(object): subject = 'go' print(GoGamer)
-
类的实例化
实例就是抽象概念的具象化kejie = GoGamer() print(kejie)
-
类的初始化
类创建一个新实例的时候会默认调用__init__
这样一个特殊方法class GoGamer(object): subject = 'go' def __init__(self, obj): self.p = obj kejie = GoGamer("金勺子") # 等同于以下 # kejie.__init__('金钥匙') print(f"柯洁含着{kejie.p}出生")
- 关于
self
指代还未实例化的实例
- 关于
面向对象
-
面向过程
程序=数据结构+算法
- 强调的是一个实现的细节
-
面向对象
完成对越来越庞大项目代码以及对外公开接口的归类和重(chong)用, 是一种更高级的抽象.- 通过什么手段来完成上述目的?
-
继承
class ChineseGoGamer(GoGamer): nation = 'cn' class KoreaGoGamer(GoGamer): nation = 'kr'
-
处理多继承冲突
-
查看
MRO(mehotd resolution order)
class A: def __init__(self): print("init A") class B: def __init__(self): print("init B") class C(A, B): pass print(C.__mro__) 默认继承第一个
-
指定类方法的调用顺序
class C(A, B): def __init__(self): super(A, self).__init__()
指定当前前一个类,可用mro属性查看,简单来说就是获取当前解释顺序传入当前糨的index+1,索引加1
- `super`函数源码
def super(cls, inst): mro = inst.__class__.mro() return mro[mro.index(cls) + 1] def super(类, 实例): # 获取当前实例的方法解析顺序 mro = 实例.类.mro() return mro[mro.index(类) + 1]
-
-
-
多态
方式为覆盖和重载-
覆盖(子类和父类之间的, 是垂直的关系)
子类可以继承父类的所有属性和方法, 但是同时子类也可以重写父类的属性和方法, 达到自定义的目的.class A: def __init__(self): print("init A") class B: def __init__(self): print("init B") class C(A, B): def __init__(self): print("init C") #class D: # def a(self, a): # return a # def a(self, a, b): # return a ** b
-
重载(类中的方法和方法之间的, 是水平关系)
Python中式没有重载, 但是可以用装饰器来实现该功能,不推荐
-
-
封装
把客观事物封装成抽象的类, 隐藏实现细节, 使得代码模块化,简单来说定义公开的接口,仅关心获取接口的功能或数据,不关心如何实现
-
- 通过什么手段来完成上述目的?
课后作业
-
用类封装一个
MyMath
类, 实现加, 减, 乘, 除, 幂, 开方class MyMath: def add(self, a, b): return a + b def subtract(self, a, b): return a - b def multi(self, a, b): return a * b def divi(self, a, b): return a / b def power(self, a, b): return a ** b def Prescription(self, a, b): return a ** (1 / b) value = MyMath() print(f'加法:', value.add(2, 2)) print(f'减法:', value.subtract(2, 2)) print(f'乘法:', value.multi(2, 2)) print(f'除法:', value.divi(2, 2)) print(f'幂:', value.power(2, 2)) print(f'开方:', value.Prescription(2, 2))
-
自由课题, 大家按自己的想法, 将身边的事物抽象出一个类, 并创建多个实例
- 创建多个继承作业2父类的子类
# 定义一个类Message 消息 # 标题,内容 class Message(object): message = 'message' def __init__(self, title, context): self.t = title self.c = context def mes(self): print(f'Title: {self.t}\nContext: {self.c}') # 创建多个继承作业2父类的子类 class Terminal(Message): def __init__(self, title, context): # title=title 前面的title是Message.self.t=title,后面的是则是Terminal.self.title super(Terminal, self).__init__(title=title, context=context) def info(self): # self.t=Message.self.t print(f'{self.t}\t\t{self.c}') # 继承和多态 class Test1(Message): def func1(self): pass if __name__ == '__main__': # 小明 = 消息(内容) xiaoming = Message('hello', 'xiaohong') xiaoming.mes() # 小红 = 消息(内容) xiaohong = Message('hello', 'xiaoming') xiaohong.mes() # 终端 = tty = Terminal('tty', 'This is tty') tty.info()
类属性和实例属性
-
类属性
-
通过类对象可以直接访问的属性
-
抽象概念的固有属性, 要考虑当前抽象概念的普适性
# 贴标签不是一个特别好的抽象, 原因他没有一个普适性 class Developer: programing_language = None busy = True
- 私有属性
不希望外部更改, 只作用于类内部-
通过
__变量名
来声明私有属性class Lottery: __items = ["mac", "ipad", "iphone"]
-
通过
类._类名__变量名
来访问私有属性print(Lottery._Lottery__items)
-
- 私有属性
-
-
实例属性
-
绑定在实例上的属性, 只能通过该实例进行访问
-
实例的自有属性
class Developer: programing_language = None busy = True __case = "doing something" d_python = Developer() d_python.programing_language = "python" d_java = Developer() d_java.programing_language = "java" print(d_java.programing_language) print(d_python.programing_language)
- 私有属性
- 通过
self.__变量名
来声明私有属性 - 通过
实例._类名__变量名
来访问私有属性
- 通过
- 私有属性
-
类方法, 静态方法, 实例方法
-
类方法
- 仅供类调用的方法
- 通过
classmethod
装饰器来声明一个类方法 - 自定义类创建
class Developer: programing_language = None busy = True __case = "doing something" def __init__(self, hairs): self.__hairs = hairs @classmethod def __new__(cls, *args, **kwargs): print("init class") return super().__new__(cls) @classmethod def get_case(cls): return cls.__case
-
静态方法
- 类可以直接调用的方法
- 通过
staticmethod
装饰器装饰 - 对一类抽象行为的归类
class MyMath: @staticmethod def add(a, b): return a + b
-
实例方法
- 仅供实例调用的方法
接口, 协议和抽象基类
-
接口
对象公开方法的子集, 让对象在系统中扮演特定的角色.list实现了增删改查的接口, 只要有一个接口没有实现那就不属于list tuple只提供了查的接口
-
协议
非正式的接口, 协议与继承没有关系, 一个类可能会实现多个接口, 从而让实例扮演多个角色list扮演者列表的角色, 但同时也是一个序列, 序列并不是一个实体类.
- 协议的应用
class MyDict(dict): def __iadd__(self, other): self.update(other) return self def __str__(self): return f"My Dict {self.items()}"
- 协议的应用
-
抽象基类
把客观事物封装成抽象的元类, 区分概念和实现.- 只要有
@abc.abstractmethod
装饰器的类就是抽象基类import abc class Mixin: def sign(self): pass def rank(self): pass class Gamer: @abc.abstractmethod def sign(self): pass class GoGamer(Mixin, Gamer): pass class Swimmer(Mixin, Gamer): pass
- 只要有
课后作业
- 将之前封装的
MyMath
类中的实例方法改为静态方法, 体会两者的区别
class MyMath:
@staticmethod
def add(a, b):
return a + b
@staticmethod
def subtract(a, b):
return a - b
@staticmethod
def multi(a, b):
return a * b
@staticmethod
def divi(a, b):
return a / b
@staticmethod
def power(a, b):
return a ** b
@staticmethod
def Prescription(a, b):
return a ** (1 / b)
def add_2(self, a, b):
return a + b
print(f'加法:', MyMath.add(2, 2))
print(f'减法:', MyMath.subtract(2, 2))
print(f'乘法:', MyMath.multi(2, 2))
print(f'除法:', MyMath.divi(2, 2))
print(f'幂:', MyMath.power(2, 2))
print(f'开方:', MyMath.Prescription(2, 2))
math = MyMath()
print(math.add_2(1, 2))
- 为上节课自定义类添加以下功能:
- 添加类属性
- 添加类私有属性
- 添加类方法或者类的私有属性
- 在
__init__
方法中初始化实例属性 - 在
__init__
方法中绑定私有实例属性 - 在自定义类中实现
__str__
, 自定义输出格式
class People:
name = None #类属性、实例属性
gender = None
__age = 18 #私有属性
def __init__(self, name, gender):
self.__name = name #实例私有属性
self.gender = gender #初始化实例属性
print(f"姓名:{self.__name}")
print(f"性别:{self.gender}")
@classmethod
def get_age(cls): #类方法
return cls.__age
def __str__(self):
return f"{self.__name}是{self.gender}生"
value = People('张三', '男')
print(f"年龄:{People.get_age()}")
print(value.__str__())