day19(2020.2.28):面向对象之继承 成员属性方法私有化、魔术方法 new init del


面向对象的三大特征:封装、继承、多态

封装

封装隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读取和修改的访问级别。它不仅是面向对象的,面向过程也有大量的封装。
类就是一种封装,通过类将数据和行为相结合,形成一个有机的整体,即将数据和对数据的操作有机的结合。封装的目的是为了增强安全性和简化编程,使用者不必了解实现细节,只需通过外部接口,以特定的访问权限使用类的成员。
成员私有化是封装的主要手段,所有的成员默认是公有的。在类里所有的属性都是公有的,没有私有的,私有是对类外而言

1.1 属性私有化

如果想实现属性私有化,可以将属性的前面增加两个下划线__,表示该属性只能在当前类的方法中被直接访问,不能通过对象访问,这个变量就是私有变量。

class Dog:
	#1.  __init__构造方法里的代码在实例化时会自动调用,只能有一个__init__构造方法,如果没有定义的话,系统会自动生成一个无参无代码的构造方法。
	#不要在__init__构造方法加print()语句,一实例化就会打印出来
	def __init__(self,name,age,gender): 
		self.name=name
		self.__age=age    
		self._gender=gender
	def get_age(self)# 2. 其他非构造方法不要同名,否则后者会覆盖前者
		return self.__age
	def set_Age(self,age):
		self.__age = age
		
		
dogA = Dog("haski",13,"male") #实例化会执行__init__方法里的代码
dogA.name # "haski"
dogA.age # 报错
dogA._Dog__age # 结果是13 ,此法能访问私有属性,但不建议。 
dogA._gender # "male" 是保护变量,但可以正常读写
dogA.__dict__  # {'name': 'haski', '_Dog__age': 18, '_gender': 'male'} __dict__是系统内置变量,所有属性包括受保护的、私有的、公有的全显示了
dogA.get_age() # 13
dogA.set_age(18) # dogA的_Dog__age变成18 

上例__age是私有变量,因此可以访问dogA.name,但不能访问dogA.age,可以通过dogA._Dog__age访问和修改,但不建议。
私有变量、保护变量只是一种语法约定,防的是无意中的无必要的访问和修改,不能防恶意的修改。

面试题:
常⻅的在变量的前后加下划线的问题:
单下划线:_age ----->受保护的但可以访问,当约定俗成,当你看到⼀个下划线开头的成员时不应该使⽤它
双下划线:__age ------>私有的
两边都双下划线:age ------->系统内置变量

通常是定义一个公开的方法get_Age访问私有变量,定义一个公开的方法set_Age修改私有变量(如上面代码),

这种方法比较麻烦,可以使用装饰器中的属性装饰器(此前用过函数装饰器),这是一种便捷语法,方便对私有属性访问与修改,这是方法属性化。

class Dog:
    def __init__(self, name, age,gender):
        self.name = name
        self.__age = age
        self._gender = gender
    @property   #代替原有get_age()
    def age(self):
        return self.__age
 
    @age.setter  #代替原有set_age()
    def age(self,age):
        self.__age = age

访问和修改时就把age方法当成对象的属性进行操作:

dogA = Dog("haski",3,"male")
print(dogA.age)
doaA.age = 10

@property先定义读age,随后@age.setter写

魔术方法

class Dog:
    def __init__(self,name,age):  # 魔术方法之构造方法
        self.name = name
        self.__age = age
        self.text()
    # 魔术方法之析构方法,销毁对象时,进行一些收尾的工作(释放资源)  对象被销毁之前自动调用
    # 没有参数 无返回值
    def __del__(self): 
        print("hi,del")
        self.fp.close()

    def text(self):
        self.fp = open("log1.txt", "w")
        print("hellowwwewerrqwwer")
        
    # 魔术方法之str方法 当print或str对象时就会调用,获取返回值并输出,代替打印对象的地址
    # 没有参数,必须返回字符串
    def __str__(self):
        return "它没有什么属性"

dogA = Dog("haski",18)
dogA.fp.write("asfsdfsf")
print(dogA) #没有str魔术方法时会出现对象的地址如:<__main__.Retangle object at 0x000001F1B43E7668>
#使用该魔术方法后则出现"它没有什么属性”

成员方法私有化

在方法名前加__,这个方法只能在类内被调用,不能通过对象调用,这就是成员方法私有化。

class Dog:
	def __init__(self,name,age):
		self.name = name
		self.__age = age
		__getAge()
	def __getAge(self):
		print(self.__age)
dogA = Dog('haski',18)# 18
dogA.__getAge() # 报错	

作业(修订版)

# 初级
# 1.刘凯买了了一台玫瑰红phone10,价值8000元,可以打电话、玩游戏

class Person:
    def __init__(self, name):
        self.name = name

    def buy(self, phone):
        print("{}买了{}{}手机,价格{}元".format(self.name,phone.color,phone.brand,phone.price))

    def call(self, phone):
        phone.call()

    def game(self, phone):
        phone.game()

class Phone:
    def __init__(self,color,brand,price):
        self.color = color
        self.brand = brand
        self.price = price

    def call(self):
        print("Make a call")

    def game(self):
        print("Play a game")


liukai = Person("刘凯")
iPhone = Phone("玫红色","Iphone10",8000)

liukai.buy(iPhone)
liukai.call(iPhone)
liukai.game(iPhone)

class Calc:
    # def __init__(self,x,y):   # 也可以将构造方法省略,直接在方法里传参,好处是省略构造方法,不好的地方是使用时
    #     self.x = x            # 要每个方法都传参
    #     self.y = y
    def add(self,x,y):
        return x + y
    def minus(self,x,y):
        return x - y
    def multiple(self,x,y):
        return x*y
    def division(self,x,y):
        return round(x/y,2)
calc = Calc()
print(calc.add(5,6),calc.minus(5,6),calc.multiple(5,6),calc.division(5,6))

'''
3.设计两个类:
一个点类,属性包括xy坐标。
一个Rectangle类(矩形),属性有左上角和右下角的坐标,可以计算矩形的面积;可以判断点是否在正方形内
实例化一个点,一个正方形,输出正方形的面积,输出点是否在正方形内
'''
设计一个类使用的参数尽量是定义好的另一个类
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return str(self.x) +","+ str(self.y)

class Retangle:
    def __init__(self, left, right):
        self.left = left
        self.right = right

    def area(self):
        return (self.right.x - self.left.x) * (self.left.y - self.right.y)

    def isIn(self, point):
        if (self.right.x >= point.x >= self.left.x) and (self.left.y >= point.y >= self.right.y):
            # 下面的打印语句中point对象会显示成内存地址,可以在Point类里增加str魔术方法
            print("点({})在正方形里{}、{}里。".format(point,self.left,self.right))
        else:
            print("点({})不在正方形里{}、{}里。".format(point,self.left,self.right))

point1 = Point(5,6)
point2 = Point(10,3)
point3 = Point(8,8)
r1 = Retangle(point1,point2)
print(r1.area())
r1.isIn(point3)
from random import randint

'''
4.定义一个Time类,成员属性包括:时、分、秒;成员⽅方法:​
add_hour(self,num) 把小时加num
add_minute(self,num) 把分钟加num
add_second(self,num) 把秒数加num
重写__str__(self)方法,返回格式化的时间字符串:"04:16:09"
'''

# 审题不对,要考虑进位的因素,而且每个方法都应该是能独立计算时间的

class Time:
    def __init__(self, hour, minute, second):
        self.hour = hour
        self.minute = minute
        self.second = second

    def add_second(self, num):
        res = self.second + num
        self.second = res % 60
        self.add_minute(res//60)    # 这个是重点,传值给类内方法,由该方法完成后一步工作(分钟处理)
        # self.minute = res // 60 % 60
        # self.hour = res // 3600 % 24

    def add_minute(self, num):
        res = self.minute + num
        self.minute = res % 60
        self.add_hour(res//60)

    def add_hour(self, num):
        res = self.hour + num
        self.hour = res % 24

    def __str__(self):
        return "{:>02}:{:>02}:{:>02}".format(self.hour, self.minute, self.second)


now = Time(23, 59, 59)
# now.add_second(1)
# now.add_minute(2)
now.add_hour(192)
print(now)

'''
中级
1.请写一个小游戏,⼈狗⼤战,2个角色,⼈和狗,游戏开始后,生成2个人,3条狗,互相混战,⼈被狗咬了会掉血,
狗被⼈打了也掉血,狗和⼈的攻击力,具备的功能都不一样。
类:⼈
属性:⼈:攻击⼒(打)、生命值(血)
方法:打
类:狗;
属性:攻击⼒(咬)、⽣命值(血)
⽅:咬
'''
class Man:
    def __init__(self, name, attack, blood):
        self.name = name
        self.attack = attack
        self.blood = blood
    def hit(self, dog):
        dog.blood -= self.attack
        if dog.blood <= 0:
            print("{}被{}打死".format(dog, self.name))
        else:
            print("{}打{}".format(self.name, dog))
    def __str__(self):
        return self.name

class Dog:
    def __init__(self, name, attack, blood):
        self.name = name
        self.attack = attack
        self.blood = blood
    def bite(self, man):
        man.blood -= self.attack
        if man.blood <= 0:
            print("{}被{}咬死b".format(man, self.name ))
        else:
            print("{}咬{}".format(self.name,man))
    def __str__(self):
        return self.name

dogList = [Dog("德牧", 20, 100), Dog("藏獒", 30, 200), Dog("吉娃娃", 5, 200)]
personList = [Man("柯南", 10, 180), Man("徐天", 40, 250)]
while len(dogList) > 0 and len(personList) > 0:
    if randint(0,1) == 0: # 狗先发动
        dogList[randint(0,len(dogList)-1)].bite(personList[randint(0,len(personList)-1)])
        for each in personList:
            if each.blood <= 0:
                personList.remove(each)
    if randint(0,1) == 1: # 人先发动:
        if len(personList) == 0:
            break
        personList[randint(0,len(personList)-1)].hit(dogList[randint(0,len(dogList)-1)])
        for each in dogList:
            if each.blood <= 0:
                dogList.remove(each)

print("*"*50)
for each in dogList:
    print(each,each.blood)
print("*"*50)
for each in personList:
    print(each,each.blood)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值