进度记录【Day 19】Python特性

Day 19

一、特性

  • Python也是一门面向对象的编程语言,包含面向对象的编程语言的特性:封装、继承、多态

1、封装

  • 属性和方法放到类内部,通过对象访问属性或者方法,隐藏功能的实现细节,当然还可以设置访问权限。
  • 类中的变量可以不预先定义;
  • 实例方法一定要带self参数
  • 类就是一个函数
class Human:
	def introduce(self):
		print('大家好,我是%s,我今年%d岁'%(self.__name,self.__age))
	def setInfo(self,nm,ag):
		self.__name=nm
		if ag>150 or ag<0:
			print('输入的年龄非法')
		else:
			self.__age=ag
	def getInfo(self):
		return self.__name,self.__age
h=Human()
#h.name,h.age,h.sex='张三',19,'男'
h.setInfo('张三',19)
h.introduce()
  • 封装的意义在于保护数据,通过将数据私有化,保证数据安全,对用户隐藏数据。
  • 提供公开方法来使用户可以读写数据(get和set方法),同时检测数据中的逻辑错误,确保用户输入的数据不是非法的。
  • 设计类时,尽可能的封装属性,不将属性暴露给用户。
  • 设计一张学生表,学生表中允许用户使用insert方法插入记录或者用delete方法删除一条数据,学生表的属性(sname,sage,ssex,sid)
class StudentRecord:
    def __init__(self,sn,sa,sx,si):
        self.__sname,self.__sage,self.__ssex,self.__sid=sn,sa,sx,si

    def setSname(self,sn):
        self.__sname=sn

    def setSage(self,sa):
        self.__sage=sa

    def setSsex(self,sx):
        self.__ssex=sx

    def setSid(self,si):
        self.__sid=si

    def getSname(self):
        return self.__sname

    def getSage(self):
        return self.__sage

    def getSsex(self):
            return self.__ssex
    
    def getSid(self):
        return self.__sid

    def intro(self):
        print('我是%s,几年%d岁'%(self.__sname,self.__sage))

class StudentTable:
    stuList=[]
    def insert(self,stu):
        if isinstance(stu,StudentRecord):
            self.stuList.append(stu)
        else:
            print('不是StudentRecord实例')

    def delete(self,stu):
        if isinstance(stu,StudentRecord):
            self.stuList.remove(stu)
        else:
            print('不是StudentRecord实例')

stuTbl=StudentTable()
s1=StudentRecord('张三',19,'男',1001)
s2=StudentRecord('李四',20,'男',1002)
stuTbl.insert(s1)
stuTbl.insert(s2)
stuTbl.delete(s1)
  • 在现有的学生表类的基础上,添加成绩表markTable,向成绩表中添加一些学生的选课记录(sid,cid,cmark),提供方法查询李四的平均分。
class markRecord:
    def __init__(self,sid,cid,cmark):
        self.__sid,self.__cid,self.__cmark=sid,cid,cmark
    def getSid(self):
        return self.__sid
    def getCmark(self):
        return self.__cmark
    def getCid(self):
        return self.__cid

class markTable:
    __markList=list()
    def insert(self,mark):
        if isinstance(mark,markRecord):
            self.__markList.append(mark)
        else:
            print('不是markRecord实例')
    def avg(self,sid):
        avg=0
        sum=0
        for mark in self.__markList:
            if mark.getSid()==sid:
                avg+=mark.getCmark()
                sum+=1
        return avg/sum

m1=markRecord(1002,2001,85)
m2=markRecord(1002,2002,90)
mTbl=markTable()
mTbl.insert(m1)
mTbl.insert(m2)
print(mTbl.avg(1002))
  • 前面两个下划线是私有属性/方法,前后两个下划线是公有方法。
  • get和set方法较为麻烦,python有更好的解决方式——装饰器@property
class Student(object):
	@property
	def score(self):
		return self.__score
	@score.setter
	def score(self,value):
		if not isinstance(value,int):
			raise ValueError('score must be an integer!')
		if value < 0 or value >100:
			raise ValueError('score must between 0~100!')
		self.__score=value
s = Student()
s.score = 60 # 实际转换为s.set_score(60)
print(s.score) # 实际转换为print(s.get_score())

2、继承

  • 如果写了__init__方法,默认的__init__方法会消失。
  • python中没有重载函数,一般通过可变长函数实现。
  • Student类继承了Human类中的属性和方法,也可以实现重写其继承的方法
class Human(object):
	@property
	def name(self):
		return self.__name
	@name.setter
	def name(self,nm):
		self.__name=nm
	@property
	def age(self):
		return self.__age
	@age.setter
	def age(self,ag):
		seelf.__age=ag

class Student(Human):
	@property
	def sid(self):
		return self.__sid
	@score.setter
	def sid(self,value):
		if not isinstance(value,int):
			raise ValueError('score must be an integer!')
		if value < 0 or value >100:
			raise ValueError('score must between 0~100!')
		self.__sid=sid
	@age.setter
	def age(self,ag):
		if ag<0 or ag>30:
			raise ValueError('不是学生的年龄')

s=Student()
s.name,s.sid,s.age='张三',1001,19
print(s.name,s.age,s.sid)

#、作业

1、实现地雷小游戏的类设计

棋子类
	属性:xy坐标、是否为地雷
棋盘类
	属性:棋子容器、棋盘的高宽、雷的个数
	方法:鼠标点击
游戏类
	属性:玩家信息、游戏难度
	方法:游戏初始化
	
1、展示游戏初始化后的地雷地图
2、根据输入返回周围的地雷数
import random
class Chess:
    @property
    def x(self):
        return self.__x
    @x.setter
    def x(self,value):
        self.__x=value

    @property
    def y(self):
        return self.__y
    @x.setter
    def y(self,value):
        self.__y=value

    @property
    def boom(self):
        return self.__boom
    @boom.setter
    def boom(self,value):
        if not isinstance(value,bool):
            raise ValueError('属性只能为布尔值')
        self.__boom=value

class ChessBoard:
    __map1=list()
    __map2=list()

    @property
    def width(self):
        return self.__width
    @width.setter
    def width(self,value):
        self.__width=value

    @property
    def height(self):
        return self.__height
    @height.setter
    def height(self,value):
        self.__height=value

    @property
    def numbers(self):
        return self.__numbers
    @numbers.setter
    def numbers(self,value):
        self.__numbers=value

    def __init__(self,width,height,numbers):
        self.__width,self.__height,self.__numbers=width,height,numbers

    def generateMap(self):
        # numbers个不重复的随机数
        n = self.width * self.height
        self.__s=set()
        while len(self.__s)!=self.numbers:
            self.__s.add(random.randint(1,n))
        # 构建地雷地图
        self.__map1=[[] for i in range(self.height)]
        for i in range(len(self.__map1)):
            for j in range(self.width):
                if int(i*self.width+j+1) in self.__s:
                    self.__map1[i].append(1)
                else:
                    self.__map1[i].append(0)
        '''
        构建提示地图
        1、初始化为0
        2、修改提示数字
        3、修改地雷数字为*
        '''
        # 1
        self.__map2=[[] for i in range(self.height)]
        for i in range(self.height):
            for j in range(self.width):
                    self.__map2[i].append(0)
        # 2
        x =self.width
        for t in self.__s:
            ps=[t-x-1,t-x,t-x+1,t-1,t+1,t+x-1,t+x,t+x+1] 
            ti=(t-1)//x
            tj=(t-1)%x
            for p in ps:
                if p<0 or p>n:
                    continue
                if tj==0 and (p==t-x-1 or p==t-1 or p==t+x-1):
                    continue
                if tj==x-1 and (p==t-x+1 or p==t+1 or p==t+x+1):
                    continue
                pi=(p-1)//x
                pj=(p-1)%x
                if pi<0 or pj<0 or pi>(x-1) or pj>(x-1):
                    continue
                else:
                    self.__map2[pi][pj]=1+self.__map2[pi][pj]
        # 3
        for t in self.__s:
            ti=(t-1)//x
            tj=(t-1)%x
            self.__map2[ti][tj]='*'


    def printMap1(self):
        # 打印地雷地图
        for i in range(len(self.__map1)):
            for j in range(len(self.__map1[i])):
                print(self.__map1[i][j],end=' ')
            print('')

    def printMap2(self):
        # 打印提示地图
        for i in range(len(self.__map2)):
            for j in range(len(self.__map2[i])):
                print(self.__map2[i][j],end=' ')
            print('')

    def getNum(self,x,y):
        if x<0 or x>self.width or y<0 or y>self.height:
            raise ValueError('输入坐标不在棋盘中')
        t=(x-1)*self.width+y
        ti=(t-1)//self.width
        tj=(t-1)%self.width
        if t in self.__s:
            print('这是一颗雷')
        else:
            print('这个位置周围有'+str(self.__map2[ti][tj])+'颗雷')

class Game:
    def __init__(self,width,height,numbers):
        self.__cb=ChessBoard(width,height,numbers)
        self.__cb.generateMap()
    
    def printMap1(self):
        self.__cb.printMap1()
    
    def printMap2(self):
        self.__cb.printMap2()
    
    def getNum(self,x,y):
        self.__cb.getNum(x,y)
    

gm=Game(10,10,30)
gm.printMap1()
print('')
gm.printMap2()
x=int(input('请输入横坐标')) 
y=int(input('请输入纵坐标'))
gm.getNum(x,y)

在这里插入图片描述


版权声明:本文为qq_41103187原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。