【python学习笔记】task07 类、对象与魔法方法
类与对象
类(Class):用来描述具有相同的属性和方法的对象的集合,在python中使用 class
关键字创建类,类名必须是大写英文字母
1.类与对象关系
(1)对象与类关系:对象是类的实例,类对对象的结构进行了定义,可以以类为模板来创建对象,类中不仅包含方法定义,还包含了实例共享的数据。
(2)面向对象特点
-
封装:信息隐蔽技术
-
继承:子类自动共享父类之间数据和方法的机制继承语法
class 派生类名(基类名)
,Python支持多继承,但是应尽量少使用避免造成混乱 -
多态:不同对象对同一方法相应不同的行动
【例1】类的封装:创建一个甲鱼类,并定义了其爬、跑、咬人、吃饭、睡觉等方法
class Turtle:#python中类名约定以大写字母开头
"""关于类的一个简单例子"""
#属性
color='green'
weight=10
legs=4
shell=True
mouth='大嘴'
#方法
def climb(self):
print('我正在很努力的向前爬...')
def run(self):
print('我正在飞快的向前跑...')
def bite(self):
print('咬死你咬死你!!')
def eat(self):
print('有得吃,真满足...')
def sleep(self):
print('困了,睡了,晚安,zzz')
#创建一个类的实例
tt=Turtle()
#查看类型
print(tt) #<__main__.Turtle object at 0x000000498AA17470>
print(type(tt)) #<class '__main__.Turtle'>
print(tt.__class__) #<class '__main__.Turtle'>
print(tt.__class__.__name__) #Turtle
tt.climb()# 我正在很努力的向前爬...
tt.run()# 我正在飞快的向前跑...
tt.bite()# 咬死你咬死你!!
# Python类也是对象。它们是type的实例
print(type(Turtle))# <class 'type'>
【例2】类的继承
import random
class Fish:
def __init__(self):
self.x = random.randint(0, 10)
self.y = random.randint(0, 10)
def move(self):
self.x -= 1
print("我的位置", self.x, self.y)
class GoldFish(Fish): # 金鱼
pass
class Carp(Fish): # 鲤鱼
pass
class Salmon(Fish): # 三文鱼
pass
class Shark(Fish): # 鲨鱼
def __init__(self):
self.hungry = True
def eat(self):
if self.hungry:
print("吃货的梦想就是天天有得吃!")
self.hungry = False
else:
print("太撑了,吃不下了!")
self.hungry = True
g = GoldFish()
g.move() # 我的位置 9 4
s = Shark()
s.eat() # 吃货的梦想就是天天有得吃!
s.move()
# AttributeError: 'Shark' object has no attribute 'x'
由于x是在父类的构造方法中定义的而子类中没有,所以出现了错误,有以下两种解决方法
- 调用未绑定的父类方法
Fish.__init__(self)
class Shark(Fish): # 鲨鱼
def __init__(self):
Fish.__init__(self)
self.hungry = True
- 使用super函数
super().__init__()
class Shark(Fish): # 鲨鱼
def __init__(self):
super().__init__()
self.hungry = True
【例3】多态:创建了父类动物及其多个子类,在run方法上子类有多个不同的实现形式
#多态
#创建父类-动物
class Animal:
def run(self):
raise AttributeError('子类必须实现这个方法')
class People(Animal):
def run(self):
print('人正在走')
class Pig(Animal):
def run(self):
print('pig is walking')
class Dog(Animal):
def run(self):
print('dog is running')
def func(animal):
animal.run()
func(Pig()) # pig is walking
单下划线、双下划线、头尾双下划线说明:
2.单下划线、双下划线、头尾双下划线说明
-
__foo__
: 定义的是特殊方法,一般是系统定义名字 ,类似 init() 之类的。 -
_foo
: 以单下划线开头的表示的是 protected 类型的变量,即保护类型只能允许其本身与子类进行访问,不能用于 from module import * -
__foo
: 双下划线的表示的是私有类型(private)的变量, 只能是允许这个类本身进行访问了。
3.self是什么?
Python 的 self
相当于 C++ 的 this
指针,在类的内部,使用 def 关键字可以为类定义一个方法,与一般函数定义不同,类方法必须包含参数 self
,且为第一个参数(对应于该实例,即该对象本身)
【例子】self的使用
class Ball:
def setName(self, name):
self.name = name
def kick(self):
print("我叫%s,该死的,谁踢我..." % self.name)
a = Ball()
a.setName("球A")
b = Ball()
b.setName("球B")
c = Ball()
c.setName("球C")
a.kick()# 我叫球A,该死的,谁踢我...
b.kick()# 我叫球B,该死的,谁踢我...
4.Python 的魔法方法
类有一个名为__init__(self[, param1, param2...])
的魔法方法,该方法在类实例化时会自动调用
【例子】使用魔法方法,完成实例的自动调用(注意与上个例子区别)
class Ball:
def __init__(self, name):
self.name = name
def kick(self):
print("我叫%s,该死的,谁踢我..." % self.name)
a = Ball("球A")
b = Ball("球B")
c = Ball("球C")
a.kick()
# 我叫球A,该死的,谁踢我...
b.kick()
# 我叫球B,该死的,谁踢我...
魔法方法详细介绍见https://www.cnblogs.com/zhouyixian/p/11129347.html
5.公有和私有
(1)类的私有属性:__private_attrs
两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问。在类内部的方法中使用时 self.__private_attrs
。
(2)类的私有方法:__private_method
两个下划线开头,声明该方法为私有方法,不能在类的外部调用。在类的内部调用 self.__private_methods
【例子】类的私有属性与私有方法
class Site:
def __init__(self, name, url):
self.name = name # public
self.__url = url # private
def who(self):
print('name : ', self.name)
print('url : ', self.__url)
def __foo(self): # 私有方法
print('这是私有方法')
def foo(self): # 公共方法
print('这是公共方法')
self.__foo()
x = Site('老马的程序人生', 'https://blog.csdn.net/LSGO_MYP')
x.who()
# name : 老马的程序人生
# url : https://blog.csdn.net/LSGO_MYP
x.foo()
# 这是公共方法
# 这是私有方法
x.__foo()
# AttributeError: 'Site' object has no attribute '__foo
6.类、类对象和实例对象
类对象 | 创建一个类,其实也是一个对象也在内存开辟了一块空间,称为类对象,类对象只有一个。 |
实例对象 | 就是通过实例化类创建的对象,称为实例对象,实例对象可以有多个。 |
类属性 | 类里面方法外面定义的变量称为类属性。类属性所属于类对象并且多个实例对象之间共享同一个类属性,说白了就是类属性所有的通过该类实例化的对象都能共享。 |
实例属性 | 实例属性和具体的某个实例对象有关系,并且一个实例对象和另外一个实例对象是不共享属性的,说白了实例属性只能在自己的对象里面使用,其他的对象不能直接使用,因为self是谁调用,它的值就属于该对象。 |
类属性和实例属性区别
- 类属性:类外面,可以通过
实例对象.类属性
和类名.类属性
进行调用。类里面,通过self.类属性
和类名.类属性
进行调用。 - 实例属性 :类外面,可以通过
实例对象.实例属性
调用。类里面,通过self.实例属性
调用。 - 实例属性就相当于
局部变量
。出了这个类或者这个类的实例对象,就没有作用了。 - 类属性就相当于类里面的
全局变量
,可以和这个类的所有实例对象共享。
【例子】区分类属性与实例属性
# 创建类对象
class Test(object):
class_attr = 100 # 类属性
def __init__(self):
self.sl_attr = 100 # 实例属性
def func(self):
print('类对象.类属性的值:', Test.class_attr) # 调用类属性
print('self.类属性的值', self.class_attr) # 相当于把类属性 变成实例属性
print('self.实例属性的值', self.sl_attr) # 调用实例属性
a = Test()
a.func()
# 类对象.类属性的值: 100
# self.类属性的值 100
# self.实例属性的值 100
b = Test()
b.func()
# 类对象.类属性的值: 100
# self.类属性的值 100
# self.实例属性的值 100
a.class_attr = 200
a.sl_attr = 200
a.func()
# 类对象.类属性的值: 100
# self.类属性的值 200
# self.实例属性的值 200
b.func()
# 类对象.类属性的值: 100
# self.类属性的值 100
# self.实例属性的值 100
Test.class_attr = 300
a.func()
# 类对象.类属性的值: 300
# self.类属性的值 200
# self.实例属性的值 200
b.func()
# 类对象.类属性的值: 300
# self.类属性的值 300
# self.实例属性的值 100
7.绑定
Python 严格要求方法需要有实例才能被调用,这种限制其实就是 Python 所谓的绑定
概念。
Python 对象的数据属性通常存储在名为.__ dict__
的字典中,我们可以直接访问__dict__
,或利用 Python 的内置函数vars()
获取.__ dict__
class CC:
def setXY(self, x, y):
self.x = x
self.y = y
def printXY(self):
print(self.x, self.y)
dd = CC()
print(dd.__dict__)
# {}
print(vars(dd))
# {}
print(CC.__dict__)
# {'__module__': '__main__', 'setXY': <function CC.setXY at 0x000000C3473DA048>, 'printXY': <function CC.printXY at 0x000000C3473C4F28>, '__dict__': <attribute '__dict__' of 'CC' objects>, '__weakref__': <attribute '__weakref__' of 'CC' objects>, '__doc__': None}
dd.setXY(4, 5)
print(dd.__dict__)
# {'x': 4, 'y': 5}
print(vars(CC))
# {'__module__': '__main__', 'setXY': <function CC.setXY at 0x000000632CA9B048>, 'printXY': <function CC.printXY at 0x000000632CA83048>, '__dict__': <attribute '__dict__' of 'CC' objects>, '__weakref__': <attribute '__weakref__' of 'CC' objects>, '__doc__': None}
print(CC.__dict__)
# {'__module__': '__main__', 'setXY': <function CC.setXY at 0x000000632CA9B048>, 'printXY': <function CC.printXY at 0x000000632CA83048>, '__dict__': <attribute '__dict__' of 'CC' objects>, '__weakref__': <attribute '__weakref__' of 'CC' objects>, '__doc__': None}
8.Python类中的一些内置函数
函数 | 作用 |
---|---|
issubclass(class, classinfo) | 用于判断参数 class 是否是类型参数 classinfo 的子类,一个类是自己的子类,classinfo可以是类对象的元组,只要class是其中任何一个候选类的子类,则返回True。 |
isinstance(object, classinfo) | 用于判断一个对象是否是一个已知的类型,类似type(),但type()不考虑继承关系,isinstance()考虑继承关系。如果第一个参数不是对象,则永远返回False。如果第二个参数不是类或者由类对象组成的元组,会抛出一个TypeError异常。 |
hasattr(object, name) | 用于判断对象是否包含对应的属性 |
getattr(object, name[, default]) | 用于返回一个对象属性值 |
setattr(object, name, value) | 对应函数 getattr(),用于设置属性值,该属性不一定是存在的 |
delattr(object, name) | 用于删除属性 |
class property([fget[, fset[, fdel[, doc]]]]) | 用于在新式类中返回属性值,其中fget – 获取属性值的函数;fset – 设置属性值的函数;fdel – 删除属性值函数;doc – 属性描述信息 |
9.Python类中的一些内置类属性
类属性 | 介绍 |
---|---|
dict | 类的属性(包含一个字典,由类的数据属性组成) |
doc | 类的文档字符串 |
name | 类名 |
module | 类定义所在的模块(类的全名是’main.className’,如果类位于一个导入模块mymod中,那么className.module 等于 mymod) |
bases | 类的所有父类构成元素(包含了一个由所有父类组成的元组) |
相关资料
- https://www.runoob.com/python3/python3-tutorial.html
- https://www.bilibili.com/video/av4050443
- https://www.cnblogs.com/loved/p/8678919.html
- https://www.runoob.com/python3/python3-class.html
- https://www.jianshu.com/p/9fb316cbf42e
练习题
1、以下类定义中哪些是类属性,哪些是实例属性?
class C:
num = 0
def __init__(self):
self.x = 4
self.y = 5
C.count = 6
num和count是类属性,x和y是实例属性
2、怎么定义私有⽅法?
类的私有方法:`__private_method`两个下划线开头,声明该方法为私有方法,不能在类的外部调用。在类的内部调用 `self.__private_methods`
3、尝试执行以下代码,并解释错误原因:
class C:
def myFun():
print('Hello!')
c = C()
c.myFun()
类、类对象、实例对象是三个不同的名词,,一个类可以实例化出无数的对象(实例对象),Python为了区分是哪个对象调用了方法,于是要求方法必须绑定(通过self参数)才能调用。实例化的类对象直接调用方法,会将c对象作为第一个参数传入,因为多了self参数,所以就会报错。
4、按照以下要求定义一个游乐园门票的类,并尝试计算2个成人+1个小孩平日票价。
要求:
平日票价100元
周末票价为平日的120%
儿童票半价
class Ticket():
# your code her
定义构造方法,对各种不同票价情况进行设置,并创建一个用于计算价格的方法
class Ticket():
def __init__(self,weekend=False,child=False):
self.exp=100
if weekend:
self.inc=1.2
else:
self.inc=1
if child:
self.discount=0.5
else:
self.discount=1
def calcPrice(self,num):
return self.exp*self.inc*self.discount*num
adult=Ticket()
child = Ticket(child=True)
print("2个成人 + 1个小孩平日票价为:%.2f" % (adult.calcPrice(2) + child.calcPrice(1)))
#2个成人 + 1个小孩平日票价为:250.00
魔法方法
- 魔法方法是面向对象的 Python 的一切,它们总能够在适当的时候被自动调用。
- 魔法方法总是被双下划线包围,例如
__init__
。魔法方法的第一个参数应为cls
(类方法) 或者self
(实例方法)。
相关资料:https://www.cnblogs.com/yoyo1216/p/10368793.html
1.基本的魔法方法
方法 | 作用 |
---|---|
_init__(self[, ...]) | 当一个实例被创建的时候调用的初始化方法 |
__new__(cls[, ...]) | 在一个对象实例化的时候所调用的第一个方法,在调用__init__ 初始化前,先调用__new__ ,`__new__至少要有一个参数cls ,代表要实例化的类,__new__方法主要是当继承一些不可变的 class 时(比如int, str, tuple), 提供一个自定义这些类的实例化过程的途径 |
__del__(self) | 析构器,当一个对象将要被系统回收之时调用的方法。 |
__str__(self) | 当打印一个对象的时候,或当使用%s格式化的时候,或使用str强转数据类型的时候,触发__str__ |
__repr__(self) | 是str的备胎,没有实现__str__ 的时候,执行此,repr(obj)内置函数对应的结果是__repr__ 的返回值,当使用%r 格式化的时候 触发__repr__ |
【例1】__new__(cls[, ...])
的使用
#不加object的叫做经典类或者旧式类,但是想在python3都是默认继承了object的
class A(object):
def __init__(self, value):
print("into A __init__")
self.value = value
def __new__(cls, *args, **kwargs):
print("into A __new__")
print(cls)
return object.__new__(cls)
#类B继承类A
class B(A):
def __init__(self, value):
print("into B __init__")
self.value = value
def __new__(cls, *args, **kwargs):
print("into B __new__")
print(cls)
return super().__new__(cls, *args, **kwargs)
b = B(10)
结果为
# into B __new__
# <class '__main__.B'>
# into A __new__
# <class '__main__.B'>
# into B __init__
【例2】利用利用__new__
实现单例模式
class Earth:
pass
a = Earth()
print(id(a)) # 260728291456
b = Earth()
print(id(b)) # 260728291624
class Earth:
__instance = None # 定义一个类属性做判断
def __new__(cls):
if cls.__instance is None:
cls.__instance = object.__new__(cls)
return cls.__instance
else:
return cls.__instance
a = Earth()
print(id(a)) # 512320401648
b = Earth()
print(id(b)) # 512320401648
2.算术运算符
方法 | 作用 |
---|---|
__add__(self, other) | 定义加法的行为:+ |
__sub__(self, other) | 定义减法的行为:- |
__mul__(self, other) | 定义乘法的行为:* |
__truediv__(self, other) | 定义真除法的行为:/ |
__floordiv__(self, other) | 定义整数除法的行为:// |
__mod__(self, other) | 定义取模算法的行为:% |
__divmod__(self, other) | 定义当被 divmod() 调用时的行为divmod(a, b)把除数和余数运算结果结合起来,返回一个包含商和余数的元组(a // b, a % b) |
__pow__(self, other[, module]) | 定义当被 power() 调用或 ** 运算时的行为 |
__lshift__(self, other) | 定义按位左移位的行为:<< |
__rshift__(self, other) | 定义按位右移位的行为:>> |
__and__(self, other) | 定义按位与操作的行为:& |
__xor__(self, other) | 定义按位异或操作的行为:^ |
__or__(self, other) | 定义按位或操作的行为:| |
3.反算术运算符
反运算魔方方法,与算术运算符保持一一对应,不同之处就是反运算的魔法方法多了一个“r”。当文件左操作不支持相应的操作时被调用。
方法 | 作用 |
---|---|
__radd__(self, other) | 定义加法的行为:+ |
__rsub__(self, other) | 定义减法的行为:- |
__rmul__(self, other) | 定义乘法的行为:* |
__rtruediv__(self, other) | 定义真除法的行为:/ |
__rfloordiv__(self, other) | 定义整数除法的行为:// |
__rmod__(self, other) | 定义取模算法的行为:% |
__rdivmod__(self, other) | 定义当被 divmod() 调用时的行为 |
__rpow__(self, other[, module]) | 定义当被 power() 调用或 ** 运算时的行为 |
__rlshift__(self, other) | 定义按位左移位的行为:<< |
__rrshift__(self, other) | 定义按位右移位的行为:>> |
__rand__(self, other) | 定义按位与操作的行为:& |
__rxor__(self, other) | 定义按位异或操作的行为:^ |
__ror__(self, other) | 定义按位或操作的行为:| |
4.增量符号运算符
方法 | 作用 |
---|---|
__iadd__(self, other) | 定义赋值加法的行为:+= |
__isub__(self, other) | 定义赋值减法的行为:-= |
__imul__(self, other) | 定义赋值乘法的行为:*= |
__itruediv__(self, other) | 定义赋值真除法的行为:/= |
__ifloordiv__(self, other) | 定义赋值整数除法的行为://= |
__imod__(self, other) | 定义赋值取模算法的行为:%= |
__ipow__(self, other[, modulo]) | 定义赋值幂运算的行为:**= |
__ilshift__(self, other) | 定义赋值按位左移位的行为:<<= |
__irshift__(self, other) | 定义赋值按位右移位的行为:>>= |
__iand__(self, other) | 定义赋值按位与操作的行为:&= |
__ixor__(self, other) | 定义赋值按位异或操作的行为:^= |
__ior__(self, other) | 定义赋值按位或操作的行为: |
5.一元运算符
方法 | 作用 |
---|---|
neg(self) | 定义正号的行为:+x |
pos(self) | 定义负号的行为:-x |
abs(self) | 定义当被abs()调用时的行为 |
invert(self) | 定义按位求反的行为:~x |
6.属性访问
方法 | 作用 |
---|---|
__getattr__(self, name) | 定义当用户试图获取一个不存在的属性时的行为。 |
__getattribute__(self, name) | 定义当该类的属性被访问时的行为(先调用该方法,查看是否存在该属性,若不存在,接着去调用__getattr__)。 |
__setattr__(self, name, value) | 定义当一个属性被设置时的行为。 |
__delattr__(self, name) | 定义当一个属性被删除时的行为。 |
【例子】
class C:
def __getattribute__(self, item):
print('__getattribute__')
return super().__getattribute__(item)
def __getattr__(self, item):
print('__getattr__')
def __setattr__(self, key, value):
print('__setattr__')
super().__setattr__(key, value)
def __delattr__(self, item):
print('__delattr__')
super().__delattr__(item)
c = C()
c.x
# __getattribute__
# __getattr__
c.x = 1
# __setattr__
del c.x
# __delattr__
7.描述符
描述符就是将某种特殊类型的类的实例指派给另一个类的属性
方法 | 作用 |
---|---|
__get__(self, instance, owner) | 用于访问属性,它返回属性的值。 |
__set__(self, instance, value) | 将在属性分配操作中调用,不返回任何内容。 |
__del__(self, instance) | 控制删除操作,不返回任何内容 |
8.定制序列
协议(Protocols)与其它编程语言中的接口很相似,它规定你哪些方法必须要定义。但在 Python 中,协议更像是一种指南。
容器类型的协议
- 如果希望定制的容器是不可变的话,只需要定义
__len__()
和__getitem__()
方法。 - 如果希望定制的容器是可变的话,除了
__len__()
和-__getitem__()
方法,还需要定义__setitem__()
和__delitem__()
两个方法。
方法 | 作用 |
---|---|
__len__(self) | 定义当被len()调用时的行为(返回容器中元素的个数)。 |
__getitem__(self, key) | 定义获取容器中元素的行为,相当于self[key]。 |
__setitem__(self, key, value) | 定义设置容器中指定元素的行为,相当于self[key] = value。 |
__delitem__(self, key) | 定义删除容器中指定元素的行为,相当于del self[key] |
【例子】
class CountList:
def __init__(self, *args):
self.values = [x for x in args]
self.count = {}.fromkeys(range(len(self.values)), 0)
def __len__(self):
return len(self.values)
def __getitem__(self, item):
self.count[item] += 1
return self.values[item]
c1 = CountList(1, 3, 5, 7, 9)
c2 = CountList(2, 4, 6, 8, 10)
print(c1[1]) # 3
print(c2[2]) # 6
print(c1[1] + c2[1]) # 7
print(c1.count)
# {0: 0, 1: 2, 2: 0, 3: 0, 4: 0}
print(c2.count)
# {0: 0, 1: 1, 2: 1, 3: 0, 4: 0}
9.迭代器
(1)迭代器特点
- 迭代是访问集合元素的一种方式。
- 迭代器是一个可以记住遍历的位置的对象,迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。
- 迭代器只能往前不会后退。
- 字符串,列表或元组对象都可用于创建迭代器
(2)迭代器基本方法iter()
和 next()
iter(object)
函数用来生成迭代器。next(iterator[, default])
返回迭代器的下一个项目。
iterator – 可迭代对象;default – 可选,用于设置在没有下一个元素时返回该默认值,如果不设置,又没有下一个元素则会触发 StopIteration 异常。
10.生成器
- 在 Python 中,使用了
yield
的函数被称为生成器(generator)。生成器是一个返回迭代器的函数,只能用于迭代操作。 - 在调用生成器运行的过程中,每次遇到
yield
时函数会暂停并保存当前所有的运行信息,返回yield
的值, 并在下一次执行 next() 方法时从当前位置继续运行。 - 调用一个生成器函数,返回的是一个迭代器对象
【例子】用生成器实现斐波那契数列。
def libs(n):
a = 0
b = 1
while True:
a, b = b, a + b
if a > n:
return
yield a
for each in libs(100):
print(each, end=' ')
# 1 1 2 3 5 8 13 21 34 55 89
相关资料
- https://www.runoob.com/python3/python3-tutorial.html
- https://www.bilibili.com/video/av4050443
- http://c.biancheng.net/view/2371.html
- https://www.cnblogs.com/seablog/p/7173107.html
- https://www.cnblogs.com/Jimmy1988/p/6804095.html
- https://blog.csdn.net/johnsonguo/article/details/585193
练习题
1、上面提到了许多魔法方法,如__new__,init, str,rstr,getitem,__setitem__等等,请总结它们各自的使用方法。
(1)
__new__(cls[, ...])
在一个对象实例化的时候所调用的第一个方法,在调用__init__初始化前,先调用__new__。
__new__
至少要有一个参数cls,代表要实例化的类,此参数在实例化时由 Python 解释器自动提供,后面的参数直接传递给__init__。__new__
对当前类进行了实例化,并将实例返回,传给__init__的self。但是,执行__new__,并不一定会进入__init__,只有__new__返回了,当前类cls的实例,当前类的__init__才会进入。(2)
__init__(self[, ...])
构造器,当一个实例被创建的时候调用的初始化方法
(3)__str__(self)
:
- 当你打印一个对象的时候,触发__str__
- 当你使用%s格式化的时候,触发__str__
- str强转数据类型的时候,触发__str__
(4)__repr__(self)
- repr是str的备胎
- 有__str__的时候执行__str__,没有实现__str__的时候,执行__repr__
- repr(obj)内置函数对应的结果是__repr__的返回值
-当你使用%r格式化的时候 触发__repr__
(5)__getitem__(self, key)
定义获取容器中元素的行为,相当于self[key]。
(6)__setitem__(self, key, value)
定义设置容器中指定元素的行为,相当于self[key] = value。
2、利用python做一个简单的定时器类
要求:
定制一个计时器的类。
start和stop方法代表启动计时和停止计时。
假设计时器对象t1,print(t1)和直接调用t1均显示结果。
当计时器未启动或已经停止计时时,调用stop方法会给予温馨的提示。
两个计时器对象可以进行相加:t1+t2。
只能使用提供的有限资源完成。
参考
(1)https://www.zybuluo.com/kingwhite/note/136684
(2)https://mp.weixin.qq.com/s?__biz=MzIyNDA1NjA1NQ==&mid=2651011380&idx=1&sn=e2fb4ad1b9734e8f104c267d4cd36b33&chksm=f3e35eacc494d7ba417701f2f9b6bd2133e921bef5ed3b798a6aa87d35919dfdd26156491e83&token=523711417&lang=zh_CN#rd
import time
class Timer:
start_time = 0
stop_time = 0
#计时器相加
def __add__(self, other):
together = int.__add__(self.secs, other.secs)
return '总共运行了%d秒' % together
def __repr__(self):
ret = getattr(self, 'secs', '未开始计时')
if isinstance(ret, int):
return '总共运行了%d秒' % ret
return ret
#启动计时器
def start(self):
self.start_time = time.time()
print('开始计时!')
#停止计时器
def stop(self):
if self.start_time == 0:
print('请先调用 start() 开始计时!')
else:
self.stop_time = time.time()
self.secs = round(self.stop_time - self.start_time)
效果
a = Timer()
a
#返回:未开始计时
a.stop()
#返回:请先调用 start() 开始计时!
a.start()
#打印:开始计时!
a.stop()
a
#返回:总共运行了4秒
print(a)
#打印:总共运行了4秒
b = TimeCount()
b.start()
#打印:开始计时!
b.stop()
b
#返回:总共运行了2秒
a + b
#返回:'总共运行了6秒'
print(a + b)
#返回:总共运行了6秒