面向对象四(封装+Property装饰器+检验实例是否是某类的实例)2020-11-26

1. 封装

1.1 封装的引入

我们先写个案例:

class Car:
	def __init__(self,name,color):
		self.name=name
		self.color=color
	def run(self):
		print('会跑')
	def loudspeaker(self):
		print('滴滴')

c=Car('大奔','白色')
print(c.color)
c.run()

在这里插入图片描述

我们可以再修改一下

class Car:
	def __init__(self,name,color):
		self.name=name
		self.color=color
	def run(self):
		print('%s会跑'%self.name)
	def loudspeaker(self):
		print('%s滴滴'%self.name)

c=Car('大奔','白色')
print(c.color)
c.run()
c.loudspeaker()

在这里插入图片描述
我们可以通过实例对象修改属性值:
在这里插入图片描述
在编程中有时候不想让人随意修改代码,所以这里需要封装一下,使属性不能随意修改。

1.2 封装的使用

封装是面向对象的三大特性之一(封装、继承、多态),指隐藏一些不希望被外界访问到的属性或方法。
案例:

class Dog:
	def __init__(self,name):
		self.name=name
	def speak(self):
		print('大家好,我是%s'%self.name)
d=Dog('二哈')
d.speak()

在这里插入图片描述
这是一个简单的程序,我们可以更改狗的名字:

class Dog:
	def __init__(self,name):
		self.name=name
	def speak(self):
		print('大家好,我是%s'%self.name)
d=Dog('二哈')
d.name='德牧'
d.speak()

在这里插入图片描述
我们看到结果被改变了,我们可以简单的标志性的封装一下,就不是那么容易改了。

class Dog:
	def __init__(self,name):
		self.hidden_name=name
	def speak(self):
		print('大家好,我是%s'%self.hidden_name)
d=Dog('二哈')
d.name='德牧'
d.speak()

在这里插入图片描述
大家看到了,我尝试用d.name='德牧’去改属性,但是属性并没有被改变。当然,你会说如果用d.hidden_name='德牧’不久能修改了吗?答案是肯定的,你是对的,可以修改的。所以任何事情都没有绝对的,不是绝对的封装,但是这里当你发现属性名为hidden_name的时候,你是不是考虑一些作者的感受,哦,这里是不建议修改的代码,如果修改了将会有某种后果。所以,你就要慎重考虑是不是要修改了。当然,你认为有必要,还是可以修改的。

1.3 getter和setter方法来访问或修改属性

仍用上面的案例:

class Dog:
	def __init__(self,name):
		self.hidden_name=name
	def speak(self):
		print('大家好,我是%s'%self.hidden_name)
	def get_name(self):
		# get_name()这个方法用来获取对象的name属性
		return self.hidden_name
d=Dog('二哈')
print(d.get_name())

在这里插入图片描述
这样外部就可以轻松访问内部属性了。入果我们想修改属性,可以添加一个setter()方法。

class Dog:
	def __init__(self,name):
		self.hidden_name=name
	def speak(self):
		print('大家好,我是%s'%self.hidden_name)
	def get_name(self):
		# get_name()这个方法用来获取对象的name属性
		return self.hidden_name
	def set_name(self,name):
		self.hidden_name=name
		return self.hidden_name
d=Dog('二哈')
d.set_name('德牧')

在这里插入图片描述
大家看到通过set_name()方法我们修改了属性,其中56-61行代码是封装代码。平时不一定要写,必要时才用。
总结:

  • 使用封装隐藏了属性名,使得调用者无法随意修改对象的属性
  • 设置getter和setter方法很好的控制了属性的读和改
  • 使用setter方法设置属灵,可以增加数据的验证,确保数据的值是正确的
  • 可以在读取和修改属性的时候,做一些其他的处理
    下面对第三和第四点做一下说明,我将上述案例添加一个年龄属性:
class Dog:
   def __init__(self,name,age):
       self.hidden_name=name
       self.hidden_age=age
   def speak(self):
       print('大家好我是%s,今年我%s岁'%(self.hidden_name,self.hidden_age))
   def get_age(self,age):
       if age>0:
           self.hidden_age=age
       return self.hidden_age
d=Dog('二哈',8)
d.speak()
d.get_age(9)
d.speak()
d.get_age(-9)
d.speak()

在这里插入图片描述
可以看到,当我调用set_age()方法修改年龄的时候,输入数据为-9的时候就没有能够改动数据。
下面对第四点进行说明,我们可以在读取和修改属性的时候,做一些其他的处理:

class Dog:
    def __init__(self,name,age):
        self.hidden_name=name
        self.hidden_age=age
    def speak(self):
        print('大家好我是%s,今年我%s岁'%(self.hidden_name,self.hidden_age))
    def set_age(self,age):
        if age>0:
            self.hidden_age=age
            print('年龄已经被修改')
        else:
            print('年龄没有被修改')
        return self.hidden_age
    def get_age(self):
        print('年龄已经被读取')
        return self.hidden_age
d=Dog('二哈',8)
d.speak()
print(d.get_age())
d.set_age(9)
d.speak()
print(d.get_age())
d.set_age(-9)
d.speak()
print(d.get_age())

输出结果:

D:\Python38\python.exe D:/work/基础/Day14/Demo02.py
大家好我是二哈,今年我8岁
年龄已经被读取
8
年龄已经被修改
大家好我是二哈,今年我9岁
年龄已经被读取
9
年龄没有被修改
大家好我是二哈,今年我9岁
年龄已经被读取
9

Process finished with exit code 0

做了这些处理以后,一旦有人修改了封装的数据,输出的时候就会有提醒,这在某些场合是很有用的。

2. Property装饰器(拓展)

2.1 引入

当我们写爬虫程序的时候,有这样的代码:

import requests
response=requests.get('https://www.baidu.com/')
print(response.text)

按照经验,我们认为.text应该是属性。但是如果我们看源码,发现它却是方法。
我们按住ctrl直接点击text就可以查看源码。
在这里插入图片描述
我们发现源码里面是方法。而且在该方法的上方有一行代码:@property,这是一个装饰器,只要被它装饰的方法,调用时如果加括号反而会报错。

2.2 @property装饰器的作用

  • 用来创建只读属性,会将方法转换称相同名称的只读属性。
  • 可以防止属性被修改
    例题
class Person:

    def __init__(self,name):
        self._name=name
    def name(self):
    	print('get方法执行了')
        return self._name

p=Person('葫芦娃')
print(p.name())

结果

get方法执行了
葫芦娃

这里我们发现,我们调用了方法,但是却打印了一个名字,一般情况下,我们应该时调用并打印属性。
那么我们可以用@property装饰器装饰一下这个方法就可以了。
如果我们再像刚才那样调用方法,就会报错。

File "D:/work/基础/Day14/Demo02.py", line 107, in <module>
    print(p.name())
TypeError: 'str' object is not callable

Process finished with exit code 1

在这里插入图片描述
那么这个属性能改吗?答案时否定的。
在这里插入图片描述
报错了。因为这是用@property装饰器修改的一个方法。如果我们要改,用@name.setter

class Person:

    def __init__(self,name):
        self._name=name
    @property
    def name(self):
        print('get方法执行了')
        return self._name
    @name.setter
    def name(self,name):
        self._name=name
p=Person('葫芦娃')
p.name='黑猫警长'
print(p.name)

可以看到结果已经可以改了。在这里插入图片描述
但是,一般我们用了@peroperty装饰器就没必要再用@name.setter装饰器了。

3. 继承

  • 继承提高了代码的复用性
  • 让类与类之间产生了关系,有了这个关系才有了后面的多态特性
    例题:
class Animal:
 	def run(self):
 		print('动物会跑')
 	def sleep(self):
 		print('动物会睡觉')
a=Animal()
a.run()
a.sleep()

结果

动物会跑
动物会睡觉

我们想再创建一个狗类,但够类具有动物的属性,所以不需要重复写代码了,直接继承就可以了。

class Animal:
 	def run(self):
 		print('动物会跑')
 	def sleep(self):
 		print('动物会睡觉')
class Dog(Animal):
	def t_home(self):
		print('狗会看家')


d=Dog()
d.run()
d.sleep()
d.t_home()

结果

动物会跑
动物会睡觉
狗会看家

3.1 检验实例是否为类的实例的方法

我们看到。够类继承了动物类的方法。我们可以用isinstance()方法检查一下够类是否是动物类的实例:

class Animal:
 	def run(self):
 		print('动物会跑')
 	def sleep(self):
 		print('动物会睡觉')
class Dog(Animal):
	def t_home(self):
		print('狗会看家')
d=Dog()
r=isinstance(d,Animal)
print(r)

结果

True

3.2 检验某类是否为另一个类的子类的方法

还有一种方法可以检验某个类是否是另一个类的子类:issubclass()

class Animal:
 	def run(self):
 		print('动物会跑')
 	def sleep(self):
 		print('动物会睡觉')
class Dog(Animal):
	def t_home(self):
		print('狗会看家')
r=issubclass(Dog,Animal)
print(r)

结果

True

3.3 方法的重写

如果子类和父类出现了相同名字的属性和方法怎么办呢?那么自然,子类的同名属性和方法会替代父类的同名属性和方法。这个叫着方法的重写(或者叫着方法的覆盖)。
例题:

class Animal:
 	def run(self):
 		print('动物会跑')
 	def sleep(self):
 		print('动物会睡觉')
class Dog(Animal):
    def run(self):
        print('狗跑')

结果

狗跑

3.4 类的属性的继承遵循就近原则

如果子类调用一个方法,子类没有这个方法,就会去父类去找,如果父类也没有,就会去父类的父类去找,以此类推,如果都没有就会报错。
例题

class A(object):
	def test(self):
		print('AAA')
class B(A):
	pass
class C(B):
	pass
c=C()
c.test()

结果

AAA

如果代码改为:

class A(object):
	def test(self):
		print('AAA')
class B(A):
		def test(self):
		print('BBB')
class C(B):
	pass
c=C()
c.test()

结果就成了

BBB

4. 作业

4.1 写博客梳理知识点

4.2 课堂代码三遍起敲

猜你喜欢

转载自blog.csdn.net/m0_46738467/article/details/110164608