三大特征:封装、继承、多态
面向对象的三大特征之一:封装性
封装指的是隐藏对象中一些不希望被外部所访问到的属性或方法
如何隐藏一个对象中的属性?
- 将对象的属性名,修改为一个外部不知道的名字
如何获取(修改)对象中的属性? - 需要提供一个getter和setter方法使外部可以访问到属性
- getter 获取对象中的指定属性(get_属性名)
- setter 用来设置对象的指定属性(set_属性名)
使用封装,确实增加了类的定义的复杂程度,但是它也确保了数据的安全性
1.隐藏了属性名,使调用者无法随意的修改对象中的属性
2.增加了getter和setter方法,很好的控制的属性是否是只读的
如果希望属性是只读的,则可以直接去掉setter方法
如果希望属性不能被外部访问,则可以直接去掉getter方法
3.使用setter方法设置属性,可以增加数据的验证,确保数据的值是正确的
4.使用getter方法获取属性,使用setter方法设置属性
可以在读取属性和修改属性的同时做一些其他的处理
5.使用getter方法可以表示一些计算的属性
class Dog:
'''
表示狗的类
'''
def __init__(self , name , age):
self.hidden_name = name
self.hidden_age = age
def say_hello(self):
print('大家好,我是 %s'%self.hidden_name)
def get_name(self):
'''
get_name()用来获取对象的name属性
'''
# print('用户读取了属性')
return self.hidden_name
def set_name(self , name):
# print('用户修改了属性')
self.hidden_name = name
def get_age(self):
return self.hidden_age
def set_age(self , age):
if age > 0 :
self.hidden_age = age
d = Dog('旺财',8)
# d.say_hello()
# 调用setter来修改name属性
d.set_name('小黑')
d.set_age(-10)
# d.say_hello()
print(d.get_age())
可以为对象的属性使用双下划线开头,__xxx
双下划线开头的属性,是对象的隐藏属性,隐藏属性只能在类的内部访问,无法通过对象访问
其实隐藏属性只不过是Python自动为属性改了一个名字
实际上是将名字修改为了,_类名__属性名 比如 __name -> _Person__name
使用__开头的属性,实际上依然可以在外部访问,所以这种方式我们一般不用
一般我们会将一些私有属性(不希望被外部访问的属性)以_开头
一般情况下,使用_开头的属性都是私有属性,没有特殊需要不要修改私有属性
class Person:
def __init__(self,name):
self._name = name
def get_name(self):
return self._name
def set_name(self , name):
self._name = name
p = Person('孙悟空')
print(p._name)
class Person:
def __init__(self,name,age):
self._name = name
self._age = age
# property装饰器,用来将一个get方法,转换为对象的属性
# 添加为property装饰器以后,我们就可以像调用属性一样使用get方法
# 使用property装饰的方法,必须和属性名是一样的
@property
def name(self):
print('get方法执行了~~~')
return self._name
# setter方法的装饰器:@属性名.setter
@name.setter
def name(self , name):
print('setter方法调用了')
self._name = name
@property
def age(self):
return self._age
@age.setter
def age(self , age):
self._age = age
p = Person('猪八戒',18)
p.name = '孙悟空'
p.age = 28
print(p.name,p.age)
面向对象的三大特征之一:继承性
单继承
class Animal:
def __init__(self,name):
self._name = name
def run(self):
print('动物会跑~~~')
def sleep(self):
print('动物睡觉~~~')
@property
def name(self):
return self._name
@name.setter
def name(self,name):
self._name = name
# 父类中的所有方法都会被子类继承,包括特殊方法,也可以重写特殊方法
class Dog(Animal):
def __init__(self,name,age):
# 希望可以直接调用父类的__init__来初始化父类中定义的属性
# super() 可以用来获取当前类的父类,
# 并且通过super()返回对象调用父类方法时,不需要传递self
super().__init__(name)
self._age = age
def bark(self):
print('汪汪汪~~~')
def run(self):
print('狗跑~~~~')
@property
def age(self):
return self._age
@age.setter
def age(self,age):
self._age = name
d = Dog('旺财',18)
print(d.name)
print(d.age)
多继承
- 在Python中是支持多重继承的,也就是我们可以为一个类同时指定多个父类
- 可以在类名的()后边添加多个类,来实现多重继承
- 多重继承,会使子类同时拥有多个父类,并且会获取到所有父类中的方法
- 在开发中没有特殊的情况,应该尽量避免使用多重继承,因为多重继承会让我们的代码过于复杂
- 如果多个父类中有同名的方法,则会现在第一个父类中寻找,然后找第二个,然后找第三个。。。
前边父类的方法会覆盖后边父类的方法
class A(object):
def test(self):
print('AAA')
class B(object):
def test(self):
print('B中的test()方法~~')
def test2(self):
print('BBB')
class C(A,B):
pass
# 类名.__bases__ 这个属性可以用来获取当前类的所有父类
# print(C.__bases__) (<class '__main__.B'>,)
# print(B.__bases__) (<class 'object'>,)
# print(C.__bases__) # (<class '__main__.A'>, <class '__main__.B'>)
c = C()
c.test()
面向对象的三大特征之一:多态性
多态从字面上理解是多种形态
狗(狼狗、藏獒、哈士奇、古牧 。。。)
一个对象可以以不同的形态去呈现
class A:
def __init__(self,name):
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self,name):
self._name = name
class B:
def __init__(self,name):
self._name = name
def __len__(self):
return 10
@property
def name(self):
return self._name
@name.setter
def name(self,name):
self._name = name
class C:
pass
a = A('孙悟空')
b = B('猪八戒')
c = C()
# 定义一个函数
# 对于say_hello()这个函数来说,只要对象中含有name属性,它就可以作为参数传递
# 这个函数并不会考虑对象的类型,只要有name属性即可
def say_hello(obj):
print('你好 %s'%obj.name)
# 在say_hello_2中我们做了一个类型检查,也就是只有obj是A类型的对象时,才可以正常使用,
# 其他类型的对象都无法使用该函数,这个函数就违反了多态
# 违反了多态的函数,只适用于一种类型的对象,无法处理其他类型对象,这样导致函数的适应性非常的差
# 注意,向isinstance()这种函数,在开发中一般是不会使用的!
def say_hello_2(obj):
# 做类型检查
if isinstance(obj , A):
print('你好 %s'%obj.name)
# say_hello(b)
# say_hello_2(b)
# 鸭子类型
# 如果一个东西,走路像鸭子,叫声像鸭子,那么它就是鸭子
# len()
# 之所以一个对象能通过len()来获取长度,是因为对象中具有一个特殊方法__len__
# 换句话说,只要对象中具有__len__特殊方法,就可以通过len()来获取它的长度
l = [1,2,3]
s = 'hello'
# print(len(l))
# print(len(s))
print(len(b))
print(len(c))
小结:
面向对象的三大特征:
封装
- 确保对象中的数据安全
继承
- 保证了对象的可扩展性
多态
- 保证了程序的灵活性