私有属性---封装
在实际开发中,对象的某些属性或方法 可能只希望在对象的内部被使用,而不希望在外部被访问到时就需要封装。
定义属性或方法时,在属性名或者方法名前增加两个下划线__ 代表私有属性,
访问私有属性的方法如下:
1.通过自定义get,set方法提供私有属性的访问
class Person:
def __init__(self, name, age):
self.name = name
self.__age = age
#定义对私有属性的get方法,获取私有属性
def getAge(self):
return self.__age
#定义对私有属性的重新赋值的set方法,重置私有属性
def setAge(self,age):
self.__age = age
person1 = Person("tom",19)
person1.setAge(20)
print(person1.name,person1.getAge()) #tom 20
2.使用property标注提供私有属性的访问
class Teacher:
def __init__(self, name, age,speak):
self.name = name
self.__age = age
self.__speak = speak
@property # ‘装饰器’ 注意1.@proterty下面默认跟的是get方法,如果设置成set会报错。
def age(self):
return self.__age
@age.setter #注意2.这里是使用的上面函数名.setter,不是property.setter.
def age(self,age):
if age > 150 and age <=0: #还可以在setter方法里增加判断条件
print("年龄输入有误")
else:
self.__age = age
@property
def for_speak(self): #注意2.这个同名函数名可以自定义名称,一般都是默认使用属性名。
return self.__speak
@for_speak.setter
def for_speak(self, speak):
self.__speak = speak
t1 = Teacher("herry",45,"Chinese")
t1.age = 38 #注意4.有了property后,直接使用t1.age,而不是t1.age()方法了。
t1.for_speak = "English"
print(t1.name,t1.age,t1.for_speak) #herry 38 English
将实例用作属性---对象组合
使用代码模拟实物时,你可能会发现自己给类添加的细节越来越多:属性和方法清单以及文件都越来越长。在这种情况下,可能需要将类的一部分属性和方法作为一个独立的类提取出来。你可以将大型类拆分成多个协同工作的小类
例子1:
需求
房子(House) 有户型、总面积和家具名称列表
新房子没有任何的家具
家具(HouseItem) 有 名字 和 占地面积,其中
席梦思(bed) 占地 4 平米
衣柜(chest) 占地 2 平米
餐桌(table) 占地 1.5 平米
将以上三件 家具 添加 到 房子 中
打印房子时,要求输出:户型、总面积、剩余面积、家具名称列表
剩余面积
在创建房子对象时,定义一个 剩余面积的属性,初始值和总面积相等
当调用 add_item 方法,向房间 添加家具 时,让 剩余面积 -= 家具面积
先定义一个家具类
class HoureItem:
def __init__(self,name,area):
self.name = name
self.area = area
# def __str__(self):
# return f'{self.name}占地面积{self.area}平方米'
def __repr__(self):
return f'{self.name}占地面积{self.area}平方米'
if __name__ == '__main__':
bed = HoureItem('席梦思',4)
chest = HoureItem('衣柜',2)
table = HoureItem('餐桌',1.5)
再定义一个猫类
class Cat:
def __init__(self,color,name):
self.color = color
self.name = name
# print('__init__')
def __str__(self):
return self.color + '的' + self.name
def eat(self):
print(f'{id(self)}号小猫在吃鱼,我的名字是{self.name}')
def drink(self):
print(f'{id(self)}号小猫在喝水')
if __name__ == '__main__':
cat1 = Cat('褐色','英短')
cat2 = Cat('蓝色','大懒猫')
print(cat1)
print(cat2)
最后定义一个house类,并调用之前定义的家具和猫类
from Cat import Cat
from HoureItem import HoureItem
class House:
def __init__(self,type,area):
self.type = type
self.area = area
self.remain_area = area
#self.house_items保存的是HouseItem类型的对象
self.house_items = []
self.pet = None
def __str__(self):
return f"户型:{self.type} 总面积:{self.area}[剩余:{ self.remain_area}]\n家具:{self.house_items}"
def take_pet(self,pet):
self.pet = pet
def add_item(self,house_item):
self.house_items.append(house_item)
self.remain_area -= house_item.area
bed = HoureItem('席梦思',4)
chest = HoureItem('衣柜',2)
table = HoureItem('餐桌',1.5)
house = House('三室一厅',123)
print(house)
print('-'*70)
house.add_item(bed)
house.add_item(chest)
house.add_item(table)
print(house)
cat2 = Cat('蓝色','大懒猫')
house.take_pet(cat2)
'''
户型:三室一厅 总面积:123[剩余:123]
家具:[]
----------------------------------------------------------------------
户型:三室一厅 总面积:123[剩余:115.5]
家具:[席梦思占地面积4平方米, 衣柜占地面积2平方米, 餐桌占地面积1.5平方米]
'''
例子2:英雄pk怪物
from random import randint
class Hero:
def __init__(self, name, blood, strength):
"""
:param name:
:param blood:
:param strength:
"""
self.name = name
self.blood = blood
self.strength = strength
def calc_health(self):
return self.blood
def take_damage(self, monster):
damage_point = randint(monster.strength - 10, monster.strength + 10)
self.blood -= damage_point
if self.blood < 0:
self.blood = 0
print(f"{self.name}你被{monster.name}攻击,受到了{damage_point}点伤害!还剩{self.blood}滴血")
if self.blood > 0:
return False
else:
print(f"{self.name}你被杀死了!胜败乃兵家常事 请重新来过。")
return True
from random import randint
class Monster:
def __init__(self, name,blood,strength):
self.name = name
self.blood = blood
self.strength = strength
def calc_health(self):
return self.blood
def take_damage(self, hero):
damage_point = randint(hero.strength - 5, hero.strength + 5)
self.blood -= damage_point
if self.blood < 0:
self.blood = 0
print(f"{self.name}你被{hero.name}攻击,受到了{damage_point}点伤害!还剩{self.blood}滴血")
if self.calc_health() <= 0:
print(f"{self.name}你被杀死了!胜败乃兵家常事 请重新来过。")
return True
else:
return False
from Hero import Hero
from Monster import Monster
hero = Hero('周瑜',100, 10)
monster = Monster('黄盖',60,20)
while True:
is_monster_died = monster.take_damage(hero)
if is_monster_died:
break
is_hero_died = hero.take_damage(monster)
if is_hero_died:
break
类属性 类方法 静态方法
类属性
类属性就是类对象所拥有的属性,它被所有类对象的实例对象所共有,在内存中只存在一个副本,这个和C++、Java中类的静态成员变量有点类似。对于公有的类属性,在类外可以通过类对象和实例对象访问
# 类属性
class people:
name="Tom" #公有的类属性
__age=18 #私有的类属性
p=people()
print(p.name) #实例对象
print(people.name) #类对象
# print(p.__age) #错误 不能在类外通过实例对象访问私有的类属性
print(people.__age) #错误 不能在类外同过类对象访问私有的类属性
类属性应用
class NeuEduClass:
class_num = 0
def __init__(self):
self.class_name = f'东软睿道Python{NeuEduClass.class_num+1}班'
NeuEduClass.class_num += 1
classList = [NeuEduClass() for i in range(10)]
for c in classList:
print(c.class_name)
类方法
类对象所拥有的方法,需要用修饰器@classmethod来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls作为第一个参数(当然可以用其他名称的变量作为其第一个参数,但是大部分人都习惯以'cls'作为第一个参数的名字),能够通过实例对象和类对象去访问。
class people:
country="china"
@classmethod
def getCountry(cls):
return cls.country
p=people()
print(p.getCountry()) #实例对象调用类方法
print(people.getCountry()) #类对象调用类方法
静态方法
class people3:
country="china"
@staticmethod
def getCountry():
return people3.country
p=people3()
print(p.getCountry()) #实例对象调用类方法
print(people3.getCountry()) #类对象调用类方法
继承
继承的概念:子类自动拥有(继承)父类的所有方法和属性
class Cat:
def __init__(self,color,name):
self.color = color
self.name = name
# print('__init__')
def __str__(self):
return self.color + '的' + self.name
def eat(self):
print(f'{id(self)}号小猫在吃鱼,我的名字是{self.name}')
def drink(self):
print(f'{id(self)}号小猫在喝水')
class BosiCat(Cat):
def eat(self,fish):
print('波斯猫爱吃螃蟹')
def catch_mouse(self):
print(f'{self.name}抓到了一只老鼠')
if __name__ == '__main__':
cat1 = BosiCat('褐色','xiaohua')
cat1.eat('ddd')
import math
class Shape:
def __init__(self,color):
self.color = color
def area(self):
return None
def show_color(self):
print(self.color)
class Circle(Shape):
def __init__(self, color, r):
super().__init__(color)
self.r = r
def area(self):
return math.pi * self.r * self.r
class Rectangle(Shape):
def __init__(self,height,width,color):
self.width = width
self.height = height
super().__init__(color)
# Shape.__init__(self,color)
def area(self):
return self.width*self.height
class Square(Rectangle):
def __init__(self,edge_len,color):
super().__init__(edge_len,edge_len,color)
self.edge_len = edge_len
def area(self):
return self.edge_len * self.edge_len
circle = Circle('white',10)
print(circle.area())
circle.show_color()
rect = Rectangle(10,12,'black')
print(rect.area())
rect.show_color()
square = Square(10,'red')
print(square.area())
square.show_color()
lst = []
lst.append(circle)
lst.append(rect)
lst.append(square)
for shape in lst:
print(shape.area())
修改PK游戏
我们发现Hero类和Monster类中有很多代码是重复的,我们把这些重复的代码提取到一个父类Sprite(精灵)中。 sprite.py
from random import randint
class Sprite:
def __init__(self, flood,strength):
self.flood = flood
self.strength = strength
def calc_health(self):
return self.flood
def take_damage(self, attack_sprite):
damage = randint(attack_sprite.strength - 5, attack_sprite.strength + 5)
self.flood -= damage
print(f"{self.name}你被{attack_sprite.name}攻击,受到了{str(damage)}点伤害!还剩{str(self.flood)}滴血")
if self.calc_health() <= 0:
print(f"{self.name}你被杀死了!胜败乃兵家常事 请重新来过。")
return True
else:
return False
from sprite import Sprite
class Hero(Sprite):
def __init__(self, name,flood,strength):
self.name = name
super().__init__(flood,strength)
from sprite import Sprite
class Monster(Sprite):
def __init__(self, name,flood,strength):
self.name = name
super().__init__(flood, strength)
from hero import Hero
from monsters import Monster
hero = Hero('张三',100, 10)
monster = Monster('小强',60,20)
while True:
is_monster_died = monster.take_damage(hero)
if is_monster_died:
break
is_hero_died = hero.take_damage(monster)
if is_hero_died:
break
new方法
python中定义的类在创建实例对象的时候,会自动执行init()方法,但是在执行init()方法之前,会执行new()方法。
new()的作用主要有两个
1.在内存中为对象分配空间
2.返回对象的引用。
作业:扑克牌模拟
任务目的
0.培养编程思维,提高分析问题能力
1.掌握类的抽象与设计
2.掌握循环,分支条件的用法
3.掌握各种集合类的使用
任务描述
1.定义一个单张扑克类(考虑需要哪些属性),定义一个一副扑克牌类,该类包含一个单张扑克对象的数组(不考虑大小王)。实现一个模拟扑克发牌洗牌的算法; 2.电脑随机发出5张牌,判断是以下哪种牌型?(提示,利用各种集合的特性可以简化判断)
Card.py
class Card:
def __init__(self,color,value):
self.value = value
self.color = color
def __repr__(self):
strvalue = str(self.value)
if self.value == 11:
strvalue = 'J'
if self.value == 12:
strvalue = 'Q'
if self.value == 13:
strvalue = 'K'
if self.value == 1:
strvalue = 'A'
return self.color + strvalue
if __name__ == '__main__':
cardA = Card('红桃',1)
print(cardA)
Poke.py
from Card import Card
import random
color_tuple = ('红桃','方片','草花','黑桃')
class Poke:
def __init__(self):
self.cards = []
for color in color_tuple:
for value in range(1,14):
card = Card(color,value)
self.cards.append(card)
def output(self):
index = 1
for card in self.cards:
print(card,end='\t')
if index % 13 == 0:
print()
index+=1
if __name__ == '__main__':
poke = Poke()
poke.output()
random.shuffle(poke.cards)
print('-'*70)
poke.output()
hands = poke.cards[:5]
# hands[0] = poke.cards[13]
print(hands)
colorsLst = [card.color for card in hands]
print(colorsLst)
colorset = set(colorsLst)
print(colorset)
valueLst = [card.value for card in hands]
print(valueLst)
valueset = set(valueLst)
print(valueset)
valueLstSorted = sorted(valueLst)
print(valueLstSorted)
bIsSameColor = False
bIsShunzi = False
if len(valueset) == 5 and valueLstSorted[-1] - valueLstSorted[0] == 4:
bIsShunzi = True
if len(colorset) == 1:
bIsSameColor = True
if bIsSameColor == True and bIsShunzi == True:
print('同花顺')
elif bIsShunzi:
print('顺子')
elif bIsSameColor:
print('同花')
elif len(valueset) == 4:
print('一对')
elif len(valueset) == 5:
print('杂牌')
#4带1或者3带2
elif len(valueset) == 2:
if valueLst.count(valueLst[0]) == 1 or valueLst.count(valueLst[0]) == 4:
print('4带1')
else:
print('3带2')
#311或221
else:
isThreeOneOne = False
for value in valueLst:
if valueLst.count(value) == 3:
isThreeOneOne = True
break
if isThreeOneOne == True:
print('311')
else:
print('221')
网友评论