Python中 类、对象和魔法方法
类(class):简单来说就是某一类事物,它们具有相同的属性,例如猫有各种颜色,各种颜色就属于属性(也被叫做变量)。
对象(object):黑猫,白猫这些都是对象,这个对象就是类的实例(instance)。对象/实例只有一种作用,即属性引用。
方法(method):对象可以通过类的函数来实现相关功能,这个函数叫做类的方法。方法分为普通方法,类方法和静态方法。三种方法在内存中都属于类,区别在于调用方式不同。
__init__方法:它会在类的对象被实例化时立即运。
实例化的过程:
1.创建一个实例/对象,将会作为一个实际参数(ACE)
2.自动触发一个__init__的方法,通过它给对象添加一些属性,对象默认名字是self
3.执行完__init__方法之后,会将self所指向的内存空间返回给实例化它的地方
我们将方法__init__()定义成了包含三个形参:self、name和age。在这个方法的定义中,形参self必不可少,还必须位于其他形参的前面。为何必须在方法定义中包含形参self呢?因为Python调用这个__init__()方法来创建Dog实例时,将自动传入实参self。每个与类相关联的方法调用都自动传递实参self,它是一个指向实例本身的引用,让实例能够访问类中的属性和方法。我们创建Dog实例时,Python将调用Dog类的方法__init__()。我们将通过实参向Dog()传递名字和年龄;self会自动传递,因此我们不需要传递它。每当我们根据Dog类创建实例时,都只需给最后两个形参(name和age)提供值。
继承
单继承中
在单继承中就是单纯的寻找父类
在多继承中就是根据子节点 所在图 的 mro顺序找寻下一个类
遇到多继承和super
对象.方法
# 找到这个对象对应的类
# 将这个类的所有父类都找到画成一个图
# 根据图写出广度优先的顺序
# 再看代码,看代码的时候要根据广度优先顺序图来找对应的super
# 报错内容
TypeError: myFun() takes 0 positional arguments but 1 was given
修改
class C:
def myFun(self):
print('Hello!')
c = C()
c.myFun()
练习
按照以下要求定义一个游乐园门票的类,并尝试计算2个成人+1个小孩平日票价。
要求:平日票价100元;周末票价为平日的120%;儿童票半价。
class Ticket():
week_a = 100
weekend_a = 120
week_c = 50
weekend_c = 60
def __init__(self, adult, child, d):
self.adult = adult
self.child = child
self.d = d
def cost(self):
if (self.d == 'week'):
self.c = self.adult * self.week_a + self.child * self.week_c
if (self.d == 'weekend'):
self.c = self.adult * self.weekend_a + self.child * self.weekend_c
print(self.c)
A = Ticket(2, 1, 'week')
A.cost()
1、init(self[, …]) 构造器,当一个实例被创建的时候调用的初始化方法。
2、new(cls[, …]) 在一个对象实例化的时候所调用的第一个方法,在调用__init__初始化前,先调用__new__。至少要有一个参数 cls,代表要实例化的类,此参数在实例化时由 Python 解释器自动提供,后面的参数直接传递给__init____new__对当前类进行了实例化,并将实例返回,传给__init__的self。但是,执行了__new__,并不一定会进入__init__,只有__new__返回了当前类 cls 的实例,当前类的__init__才会进入。
若__new__没有正确返回当前类 cls 的实例,那__init__是不会被调用的,即使是父类的实例也不行,将没有__init__被调用。
可利用__new__实现单例模式__new__方法主要是当你继承一些不可变的 class 时(比如int, str, tuple), 提供给你一个自定义这些类的实例化过程的途径。
3、del(self) 析构器,当一个对象将要被系统回收之时自动调用的方法。
4、str 和 repr:
当你打印一个对象的时候,当你使用 %s 格式化的时候,str 强转数据类型的时候 都可以 触发__str__。
repr 是 str 的备胎,有__str__的时候执行__str__,没有实现__str__的时候,执行__repr__。repr(obj) 内置函数对应的结果是__repr__的返回值。当使用%r格式化的时候 触发__repr__。
5、str(self) 的返回结果可读性强。也就是说,str 的意义是得到便于人们阅读的信息;repr(self) 的返回结果应更准确,其存在的目的在于调试,便于开发者使用。
练习
利用python做一个简单的定时器类
要求:
- 定制一个计时器的类。
- start 和 stop 方法代表启动计时和停止计时。
- 假设计时器对象 t1 , print(t1) 和直接调用 t1 均显示结果。
- 当计时器未启动或已经停止计时时,调用 stop 方法会给予温馨的提示。
- 两个计时器对象可以进行相加: t1+t2 。
- 只能使用提供的有限资源完成。
import time as t
from time import sleep
class MyTimer():
def __init__(self):
self.unit = ['年','月','日','时','分','秒']
self.prompt = "未开始计时!"
self.lasted = []
self.begin = 0
self.end = 0
def __str__(self):
return self.prompt
__repr__ = __str__
def __add__(self, other):
prompt = "总共运行了:"
result = []
for index in range(6):
result.append(self.lasted[index] + other.lasted[index])
if result[index]:
prompt += (str(result[index] + self.unit[index]))
return prompt
#开始计时
def start(self):
self.begin = t.localtime()
self.prompt = "提示:请先调用stop(()停止计时"
print "计时开始"
#停止计时
def stop(self):
if not self.begin:
print "提示:请先调用start()进行计时!"
else:
self.end = t.localtime()
self._calc()
print "计时结束"
#内部方法,计算运行时间
def _calc(self):
self.lasted = []
self.prompt = "总共运行了:"
for index in range(6):
self.lasted.append(self.end[index] - self.begin[index])
if self.lasted[index]:
self.prompt += (str(self.lasted[index]) + self.unit[index])
print self.prompt
#创建对象
t1 = MyTimer()
t1.start()
sleep(3) #中间等待的时间来验证计时
t1.stop()