08.类与对象&魔法方法
一、类与对象
练习题:
1.以下类定义中哪些是类属性,哪些是实例属性?
class C:
num = 0
def __init__(self):
self.x = 4
self.y = 5
C.count = 6
- 类属性:类里面方法外面定义的变量称为类属性。类属性所属于类对象并且多个实例对象之间共享同一个类属性,说白了就是类属性所有的通过该类实例化的对象都能共享。
- 实例属性:实例属性和具体的某个实例对象有关系,并且一个实例对象和另外一个实例对象是不共享属性的,说白了实例属性只能在自己的对象里面使用,其他的对象不能直接使用,因为self是谁调用,它的值就属于该对象。
class C:
num = 0 #类属性
def __init__(self):
self.x = 4 #实例属性
self.y = 5 #实例属性
C.count = 6 #类属性
类属性和实例属性区别
- 类属性:类外面,可以通过实例对象.类属性和类名.类属性进行调用。类里面,通过self.类属性和类名.类属性进行调用。
- 实例属性 :类外面,可以通过实例对象.实例属性调用。类里面,通过self.实例属性调用。
- 实例属性就相当于局部变量。出了这个类或者这个类的实例对象,就没有作用了。
- 类属性就相当于类里面的全局变量,可以和这个类的所有实例对象共享。
2.怎么定义私有方法?
在 Python 中定义私有变量只需要在变量名或函数名前加上“__”两个下划线,那么这个函数或变量就会为私有的了。
class JustCounter:
__secretCount = 0 # 私有变量
publicCount = 0 # 公开变量
def count(self):
self.__secretCount += 1
self.publicCount += 1
print(self.__secretCount)
counter = JustCounter()
counter.count() # 1
counter.count() # 2
print(counter.publicCount) # 2
print(counter._JustCounter__secretCount) # 2 Python的私有为伪私有
print(counter.__secretCount)
# AttributeError: 'JustCounter' object has no attribute '__secretCount'
3.尝试执行以下代码,并解释错误原因:
class C:
def myFun():
print('Hello!')
c = C()
c.myFun()
#TypeError: myFun() takes 0 positional arguments but 1 was given
class C:
def myFun(self):
print('Hello!')
c = C()
c.myFun()
#Hello!
- Python 的 self 相当于 C++ 的 this 指针。
- 类的方法与普通的函数只有一个特别的区别 —— 它们必须有一个额外的第一个参数名称(对应于该实例,即该对象本身),按照惯例它的名称是 self。
4.按照以下要求定义一个游乐园门票的类,并尝试计算2个成人+1个小孩平日票价。
要求:
平日票价100元
周末票价为平日的120%
儿童票半价
class Ticket():
def __init__(self, adult_num, kid_num, day):
# day-输入1~7表示星期一~星期天
self.adult_num = adult_num
self.kid_num = kid_num
self.day = day
self.price = 100
def sum_price(self):
if self.day in range(1,6):
# 星期一到星期五
print("总票价为: %d 元" %(self.price * (self.adult_num+self.kid_num/2)))
else:
# 周末
print("总票价为: %d 元" %(self.price*1.2 * (self.adult_num+self.kid_num/2)))
p = Ticket(3, 1, 5)
p.sum_price()
# 总票价为: 350 元
二、魔方方法
练习题
魔法方法总是被双下划线包围,例如__init__。
魔法方法是面向对象的 Python 的一切。
魔法方法的“魔力”体现在它们总能够在适当的时候被自动调用。
魔法方法的第一个参数应为cls(类方法) 或者self(实例方法)。
- cls:代表一个类的名称
- self:代表一个实例对象的名称
- init(self[, …]) 构造器,当一个实例被创建的时候调用的初始化方法
class Rectangle:
def __init__(self, x, y):
self.x = x
self.y = y
def getPeri(self):
return (self.x + self.y) * 2
def getArea(self):
return self.x * self.y
rect = Rectangle(4, 5)
print(rect.getPeri()) # 18
print(rect.getArea()) # 20
- __ new__(cls[, …]) 在一个对象实例化的时候所调用的第一个方法,在调用__init__初始化前,先调用__new__。
__ new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由 Python 解释器自动提供,后面的参数直接传递给__init__。
__ new__对当前类进行了实例化,并将实例返回,传给__init__的self。但是,执行了__new__,并不一定会进入__init__,只有__new__返回了,当前类cls的实例,当前类的__init__才会进入。
练习题
利用python做一个简单的定时器类
要求:
- 定制一个计时器的类。
- start和stop方法代表启动计时和停止计时。
- 假设计时器对象t1,print(t1)和直接调用t1均显示结果。
- 当计时器未启动或已经停止计时时,调用stop方法会给予温馨的提示。
- 两个计时器对象可以进行相加:t1+t2。
- 只能使用提供的有限资源完成。
import time
class Mytime(object):
def __init__(self):
self.__info = '未开始计时!'
self.__begin = None
self.__end = None
self.__jg = 0
def __str__(self):
return self.__info
def __repr__(self):
return self.__info
def start(self):
print('计时开始...')
self.__begin = time.localtime()
def stop(self):
if not self.__begin:
print('提示:请先调用start()开始计时!')
return
self.__end = time.localtime()
self.__jg = time.mktime(self.__end) - time.mktime(self.__begin)
self.__info = '共运行了%d秒' % self.__jg
print('计时结束!')
return self.__jg
def __add__(self, other):
return '共运行了%d秒' % (other.__jg + self.__jg)
t1 = Mytime()
print(t1)
# 未开始计时!
t1.stop()
# 提示:请先调用start()开始计时!
t1.start()
# 计时开始...
time.sleep(5)
t1.stop()
# 计时结束!
print(t1)
# 共运行了5秒
t2 = Mytime()
t2.start()
# 计时开始...
time.sleep(7)
t2.stop()
# 计时结束!
print(t2)
# 共运行了7秒
print(t1 + t2)
# 共运行了12秒