36类和对象:介绍
一、介绍对象
0、对象中的属性和方法,在编程中实际是什么?
变量和函数。
1、类和对象是什么关系呢?
类是对象的抽象表达,对象是类的实际表现。
2、如果我们定义了一个猫类,那你能想象出由“猫”类实例化的对象有哪些?
黑猫,白猫,黑猫警长。
3、类的定义有些时候或许不那么“拟物”,有时候会抽象一些,例如我们定义一个矩阵类,那你会为此添加哪些属性和方法呢?
添加长度,宽度,坐标,颜色等属性,计算面积和周长等方法。
4、类的属性定义应该尽可能抽象还是尽可能具体?
抽象,这样才叫面向对象啊。
5、请用一句话概括面向对象的几个特征?
封装:对外部隐藏对象的工作细节
继承:子类自动共享父类之间数据和方法的机制
>>> class MyList(list):
pass 占位符 无意义
>>> list1 = MyList()
>>> list1.append(0)
>>> list1
[0]
多态:可以对不同类的对象调用相同的方法,产生不同的结果,就是不同类的同一个方法名调用和后的结果不一样。
6、函数和方法有什么区别?
方法多了一个self参数。
二、课后题
0、按照以下提示尝试定义一个Person类并生成类实例对象。
# 属性:姓名(默认姓名为“小甲鱼”)
# 方法:打印姓名
# 提示:放法中对属性的引用形式加上self,如self.name
class Person :
name = '小甲鱼'
def print_name(self) :
print('名字是%s' % self.name)
1、按照以下提示尝试定义一个矩阵类并生成类实例对象。
属性:长和宽
方法:设置长和宽->setRect(self),获得长和宽->getRect(self),获得面积->getArea(self)
提示:方法中对属性的引用形式加上self,如self.width
#属性:长和宽
#方法:设置长和宽->setRect(self),获得长和宽->getRect(self),
#获得面积->getArea(self)
#提示:方法中对属性的引用形式加上self,如self.width
class Matrix:
length = 5
width = 4
def setRect(self) :
print('请输入矩形的长和宽')
self.length = float(input('长:'))
self.width = float(input('宽:'))
def getRect(self) :
print('这个矩形的长是:%d,宽是:%d' % (self.length,self.width))
def getArea(self) :
area = self.length * self.width
print(area)
37类和对象:面向对象编程
一、self
0、self参数的作用是什么?
绑定方法。self参数类似于人的身份证,每个实例对象都有唯一的self参数。
二、类的方法
0、如果我们不希望对象的属性或方法被外部直接引用,我们可以怎么做?(私有变量)
我们可以在属性或方法名字前边加上双下划线,这样子从外部是无法直接访问到,会显示AttributeError错误。
>>> class Person:
__name = '小甲鱼'
def getName(self):
return self.__name
>>> p = Person()
>>> p.__name
Traceback (most recent call last):
File "<pyshell#7>", line 1, in <module>
p.__name
AttributeError: 'Person' object has no attribute '__name'
>>> p.getName()
'小甲鱼'
因为加了“__”就变成私有元素,类外部不能直接访问,但可以通过类的方法间接访问。但其实Python只是把元素名改变了而已,可以通过“_类名__变量名”访问,即_Person__name。
1、类在实例化后哪个方法会被自动调用?
__init__方法会在类实例化时被自动调用,称为魔法方法,又称为构造方法。
三、课后题
0、按照以下要求定义一个游乐园门票的类,并尝试计算2个成人+1个小孩平日票价。
a.平日票价100元
b.周末票价为平日的120%
c.儿童半价
#0、按照以下要求定义一个游乐园门票的类,并尝试计算2个成人+1个小孩平日票价。
#a.平日票价100元
#b.周末票价为平日的120%
#c.儿童半价
class Ticket:
def __init__(self,people = 1,date = 1) :
'成人1,平日1'
if people == 1:
if date == 1 :
self.price = 100
else :
self.price = 120
else :
if date == 1 :
self.price = 50
else :
self.price = 60
def allprice(self,number = 1) :
return self.price * number
adults = Ticket()
child = Ticket(2,1)
print(adults.allprice(2) + child.allprice(1))
1、游戏编程:按以下要求定义一个乌龟类和鱼类并尝试编写游戏。(初学者不一定可以完整实现,但请务必先自己动手,你会从中学习到很多知识的)
#1、游戏编程:按以下要求定义一个乌龟类和鱼类并尝试编写游戏。
#(初学者不一定可以完整实现,但请务必先自己动手,你会从中学习到很多知识的)
#a.假设游戏场景为范围(x,y)为0<=x<=10,0<=y<=10
#b.游戏生成1只乌龟和10条鱼
#c.它们的移动方向均随机
#d.乌龟的最大移动能力是2(Ta可以随机选择1还是2移动),鱼儿的最大移动能力是1
##e.当移动到场景边缘,自动向反方向移动
#f.乌龟初始化体力为100(上限)
#g.乌龟每移动一次,体力消耗1
#h.当乌龟和鱼坐标重叠,乌龟吃掉鱼,乌龟体力增加20
#i.鱼暂不计算体力
#j.当乌龟体力值为0(挂掉)或者鱼儿的数量为0游戏结束
''' 结构
1.设置游戏范围(x,y)为0<=x<=10,0<=y<=10
让位置为(x,y),一直在范围内
2.生成1只乌龟和10条鱼,乌龟体力值为100,且最大为100,鱼无体力
3.乌龟和鱼都移动,移动方向随机,乌龟走1或2步,体力消耗1,鱼走1步
如果移动到边界的自动反方向
4.如果乌龟和鱼坐标重叠,乌龟吃掉鱼,乌龟体力增加20
5.当乌龟体力值为0(挂掉)或者鱼儿的数量为0游戏结束
'''
import random
class Turtle :
def __init__(self) :
self.HP = 100 #乌龟体力值为100
(self.x,self.y) = (random.randint(0,10),random.randint(0,10)) #位置随机
self.GPS = (self.x,self.y)
def crawl(self) : #乌龟移动
stepcount = random.randint(1,2)
if stepcount == 1 : #一次移动一步
direction = random.randint(1,4)
if direction == 1 : #上
self.y += 1
self.GPS = (self.x,self.y)
elif direction == 2 : #下
self.y -= 1
self.GPS = (self.x,self.y)
elif direction ==3 : #左
self.x -= 1
self.GPS = (self.x,self.y)
else : #右
self.x += 1
self.GPS = (self.x,self.y)
else : #一次移动两步
direction = random.randint(1,4)
if direction == 1 : #上
self.y += 2
self.GPS = (self.x,self.y)
elif direction == 2 : #下
self.y -= 2
self.GPS = (self.x,self.y)
elif direction ==3 : #左
self.x -= 2
self.GPS = (self.x,self.y)
else : #右
self.x += 2
self.GPS = (self.x,self.y)
#超出边界,当移动到场景边缘,自动向反方向移动
if self.x < 0 :
self.x = self.x * (-1)
self.GPS = (self.x,self.y)
elif self.x > 10 :
self.x = 10 - (self.x - 10)
self.GPS = (self.x,self.y)
elif self.y < 0 :
self.y = self.y * (-1)
self.GPS = (self.x,self.y)
elif self.y > 10 :
self.y = 10 - (self.y - 10)
self.GPS = (self.x,self.y)
def reduceHP(self) : #乌龟每移动一次,体力消耗1
self.HP -= 1
def eat(self) : #如果乌龟和鱼坐标重叠,乌龟吃掉鱼,乌龟体力增加20
self.HP += 20
if self.HP > 100 :
self.HP =100
class Fish :
def __init__(self) :
(self.x,self.y) = (random.randint(0,10),random.randint(0,10)) #位置随机
self.GPS = (self.x,self.y)
def tour(self) : #鱼移动
direction = random.randint(1,4)
if direction == 1 : #上
self.y += 1
self.GPS = (self.x,self.y)
elif direction == 2 : #下
self.y -= 1
self.GPS = (self.x,self.y)
elif direction ==3 : #左
self.x -= 1
self.GPS = (self.x,self.y)
else : #右
self.x += 1
self.GPS = (self.x,self.y)
#超出边界,当移动到场景边缘,自动向反方向移动
if self.x < 0 :
self.x = self.x * (-1)
self.GPS = (self.x,self.y)
elif self.x > 10 :
self.x = 10 - (self.x - 10)
self.GPS = (self.x,self.y)
elif self.y < 0 :
self.y = self.y * (-1)
self.GPS = (self.x,self.y)
elif self.y > 10 :
self.y = 10 - (self.y - 10)
self.GPS = (self.x,self.y)
def beeated(self) : #如果乌龟和鱼坐标重叠,乌龟吃掉鱼
del self.GPS
turtle1 = Turtle()
fish1 = Fish()
fish2 = Fish()
fish3 = Fish()
fish4 = Fish()
fish5 = Fish()
fish6 = Fish()
fish7 = Fish()
fish8 = Fish()
fish9 = Fish()
fish10 =Fish()
list1 = [fish1,fish2,fish3,fish4,fish5,fish6,fish7,fish8,fish9,fish10]
count = 0
print('=========================初始的游戏状况:====================')
print('乌龟的位置为:'+ str(turtle1.GPS))
print('乌龟的体力为:%d' % turtle1.HP)
for i in list1 :
if i.GPS == turtle1.GPS :
turtle1.eat()
i.beeated()
del i
print('鱼的位置是:'+ str(i.GPS))
while turtle1.HP > 0 and len(list1) > 0 :
turtle1.crawl()
turtle1.reduceHP()
for i in list1 :
i.tour()
if i.GPS == turtle1.GPS :
turtle1.eat()
i.beeated()
list1.remove(i)
count += 1
print('=======================移动%d次之后的游戏状况:=================' % count)
print('乌龟的位置为:'+ str(turtle1.GPS))
print('乌龟的体力为:%d' % turtle1.HP)
for i in list1 :
print('鱼的位置是:'+ str(i.GPS))
38类和对象:继承
一、格式
class 类名(父类类名):
二、测试题
0. 继承机制给程序猿带来最明显的好处是?
答:
如果一个类 A 继承自另一个类 B,就把这个 A 称为 B 的子类,把 B 称为 A 的父类、基类或超类。继承可以使得子类具有父类的各种属性和方法,而不需要再次编写相同的代码(偷懒)。
在子类继承父类的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类的原有属性和方法,使其获得与父类不同的功能。另外,为子类追加新的属性和方法也是常见的做法。
但是,这里覆盖的是子类实例化对象里面的方法而已,对父类的方法没有影响。
- 如果按以下方式重写魔法方法 init,结果会怎样?
class MyClass:
def __init__(self):
return "I love FishC.com!"
答:会报错,因为 init 特殊方法不应当返回除了 None 以外的任何对象。
- 当子类定义了与相同名字的属性或方法时,Python 是否会自动删除父类的相关属性或方法?
答:不会删除!Python 的做法跟其他大部分面向对象编程语言一样,都是将父类属性或方法覆盖,子类对象调用的时候会调用到覆盖后的新属性或方法,但父类的仍然还在,只是子类对象“看不到”。
- 假设已经有鸟类的定义,现在我要定义企鹅类继承于鸟类,但我们都知道企鹅是不会飞的,我们应该如何屏蔽父类(鸟类)中飞的方法?
答:覆盖父类方法,例如将函数体内容写 pass,这样调用 fly 方法就没有任何反应了。
- super 函数有什么“超级”的地方?
答:super 函数超级之处在于你不需要明确给出任何基类的名字,它会自动帮您找出所有基类以及对应的方法。由于你不用给出基类的名字,这就意味着你如果需要改变了类继承关系,你只要改变 class 语句里的父类即可,而不必在大量代码中去修改所有被继承的方法。
- 多重继承使用不当会导致重复调用(也叫钻石继承、菱形继承)的问题,请分析以下代码在实际编程中有可能导致什么问题?
class A():
def __init__(self):
print("进入A…")
print("离开A…")
class B(A):
def __init__(self):
print("进入B…")
A.__init__(self)
print("离开B…")
class C(A):
def __init__(self):
print("进入C…")
A.__init__(self)
print("离开C…")
class D(B, C):
def __init__(self):
print("进入D…")
B.__init__(self)
C.__init__(self)
print("离开D…")
答:多重继承容易导致重复调用问题,下边实例化 D 类后我们发现 A 被前后进入了两次(有童鞋说两次就两次憋,我女朋友还不止呢……)。
这有什么危害?我举个例子,假设 A 的初始化方法里有一个计数器,那这样 D 一实例化,A 的计数器就跑两次(如果遭遇多个钻石结构重叠还要更多),很明显是不符合程序设计的初衷的(程序应该可控,而不能受到继承关系影响)。
>>> d = D()
进入D…
进入B…
进入A…
离开A…
离开B…
进入C…
进入A…
离开A…
离开C…
离开D…
- 如何解决上一题中出现的问题?
class A():
def __init__(self):
print("进入A…")
print("离开A…")
class B(A):
def __init__(self):
print("进入B…")
super().__init__()
print("离开B…")
class C(A):
def __init__(self):
print("进入C…")
super().__init__()