python中对象的特性_Python_基础_(面向对象三大特性)

一,继承

## 在Python中的继承分为单继承和多继承

classParentClass1:pass

classParentClass2:pass

class SubClass(ParentClass1): #单继承

pass

class SubClass(ParentClass1,ParentClass2) #多重继承

pass

# 在Python中可以继承多个类,在Java和C#中则只能继承一个类

# Python类如果继承了多个类,那么其寻找方式有两种,深度优先和广度优先(下方有讲)

## 继承例子

classDad:"这是父类"name= "henry_Dad"

def __init__(self,name):

self.name=nameprint("父类")classSun(Dad):pass

print(Sun.name) #henry_Dad

print(Dad.__dict__)#{'__module__': '__main__',#'__doc__': '这是父类',#'name': 'henry_Dad',#'__init__': ,#'__dict__': ,#'__weakref__': }

print(Sun.__dict__)#{'__module__': '__main__', '__doc__': None}

## 问题:

问:子类继承了父类的属性,子类自定义的属性与父类中的属性重名,那么就覆盖了父类?

答:不是覆盖,当子类调用一个数据属性或函数属性时,子类现在自己的类中找,若找不到则在父类中找,若找到则不在父类中找

什么时候用到继承:

1:当类之间有显著的不同,且较小的类为较大的类的组件时,用组合较好

2:当类之间具有很多相同的功能,提取这些功能作为基类,用继承比较好

## 父类:动物(吃,喝,玩,乐)

## 子类:小狗(汪汪叫)

## 子类:母鸡(喔喔叫)

## 继承具有的含义

1:继承基类的方法(尽量少用,会让类与类之间的耦合度增加,因遵循低耦合 高内聚),并且做出自己的改变或或扩展

在实践中,该继承的意义不大,甚至是有害的,因为它使基类和子类之间的耦合性加强了

2:声明某个子类兼容于某个基类,定义一个类的接口,子类继承接口类,并且实现接口中定义的方法

接口继承实质上要求“做出一个良好的抽象,这个抽象定义一个兼容的接口,使得外部的调用者无需知道具体的实现细节,可一视同仁的处理特定接口的所有对象”

## abc模块

在Python中本身不提供抽象类和接口机制,想要实现抽象类,可以利用abc模块,BAC为 Abstract Base Class

importabcclass Animal(metaclass=abc.ABCMeta):

@abc.abstractmethod#声明该适配器,被声明的方法在本类中不用实现

defeat(self):pass@abc.abstractmethoddefsleep(self):pass

classCat(Animal):defeat(self):pass

defsleep(self):passc=Cat()classDog(Animal):defeat(self):passd= Dog() #当类Dog中没有实现方法sleep时,执行这步会报错(必须实现父类中的抽象方法)

## 深度优先 和 广度优先

深度优先遍历:对每一个可能的分支路径深入到无法深入为止,且每个节点只访问一次

广度优先遍历:又叫层次遍历,从上往下对每一层依次访问,在每一层中,从左往右(也可以从右往左)访问结点,访问完一层就进入下一层,直到没有结点可以访问为止。

## 在Python中如何实现继承

1:在Python中对于你定义的每个类,Python会计算出一个方法解析顺序列表(MRO),这个MRO列表就是一个简答的所有基类的线性顺序表

2:为了实现继承,Python会从MRO列表中从左到右开始查找基类,知道找到第一个匹配这个属性的类为止

# 2.1:子类会先于基类被检查

# 2.2:如果一个子类有多个基类,则根据它们在MRO列表中的顺序进行检查

# 2.3:如果对一个子类存在两个合法的基类,则选择第一个基类

## 新式类/经典类中的查找顺序

# Python 3 为新式类

# Python 2 为经典类和新式类

class C1: #经典类,没有继承关系

pass

class C2(C1): #经典类,因为继承的C1为经典类

pass

class B1(object): #经典类,Python3基类默认继承了object

pass

class B2(B1): #新式类

pass

#当为经典类时,多继承情况下,会按照深度优先查找#当为新式类时,多继承情况下,会按照广度优先的方法查找

## MRO示例

# 下图为继承关系样例图

1455397-20181220152047027-1952544818.png

## 新式类中的查找顺序

classA:deftest(self):print("A")classB(A):deftest(self):print("B")classC(B):deftest(self):print("C")classD(A):deftest(self):print("D")classE(D):deftest(self):print("E")classF(C,E):deftest(self):print("F")print(F.__mro__) #经典类中无此方法#(, , , , , , )

## 经典类中的查找顺序(Python中),经典类中无__mro__方法

classA:deftest(self):print("A")classB(A):deftest(self):print("B")classC(B):deftest(self):print("C")classD(A):deftest(self):print("D")classE(D):deftest(self):print("E")classF(C,E):deftest(self):print("F")

f=F()

f.test()#F->D->B->A->E->C

## super方法的使用

# 方式一,在子类中直接写上基类的名称

classAnimal():def __init__(self,name,speed,appetite,master):

self.name=name

self.speed=speed

self.appetite=appetite

self.master=masterdefwalk(self):print("开始遛了")classDog(Animal):def __init__(self,name,speed,appetite,master,size): #自有属性为size

Animal.__init__(self,name,speed,appetite,master)

self.size=sizedefWalk_the_dog(self):

Animal.walk(self)print("开始遛狗啦")

d= Dog("small_yellow","10km/h","十碗","henry",30)

d.Walk_the_dog()#输出

开始遛了

开始遛狗啦

# 以上的方法存在缺陷,当父类名修改时,子类中涉及父类名称的也得进行修改,扩展性差

# 方式二,利用super

classAnimal:def __init__(self,name,speed,appetite,master):

self.name=name

self.speed=speed

self.appetite=appetite

self.master=masterdefwalk(self):print("开始遛了")classDog(Animal):def __init__(self,name,speed,appetite,master,size): #自有属性为size

#Animal.__init__(self,name,speed,appetite,master)

super().__init__(name, speed, appetite, master)

self.size=sizedefWalk_the_dog(self):#Animal.walk(self)

super(Dog,self).walk()print("开始遛狗啦")

d= Dog("small_yellow","10km/h","十碗","henry",30)

d.Walk_the_dog()#输出

开始遛了

开始遛狗啦

....

二,多态

多态:由不同的类实例化得到的对象,这些对象调用同一个方法,执行不同的逻辑

多态反应一种在执行时候的状态

>>> str1 = "abc"

>>> list1 = [1,1,2,3]>>> str1.__len__()3

>>> list1.__len__()4

>>>

#其中 str1和list1为不同的对象,都去调用方法__len__(),但执行不同的逻辑来得到结构

## 多态例子

classH20:def __init__(self,h2o_type,temperature):

self.h2o_type= h2o_type #H2O类型

self.temperature = temperature #温度

deftranslate(self):if self.temperature > 100:print("当前的温度为:%s 大于100,变成了%s" %(self.temperature,self.h2o_type))elif self.temperature > 0 & self.temperature < 100:print("当前的温度为:%s 位于0和100之间,变成了%s" %(self.temperature, self.h2o_type))elif self.temperature <0:print("当前的温度为:%s 小于0,变成了%s" %(self.temperature, self.h2o_type))classWater(H20):pass

classIce(H20):pass

classStream(H20):passw= Water("水",20) #由不同的类实例化出不同的对象

i = Ice("冰",-20) #由不同的类实例化出不同的对象

s = Stream("蒸汽",111) #由不同的类实例化出不同的对象

w.translate()#调用同一个方法(执行不同的逻辑)

i.translate() #调用同一个方法(执行不同的逻辑)

s.translate() #调用同一个方法(执行不同的逻辑)

#当前的温度为:20位于0和100之间,变成了水

当前的温度为:-20小于0,变成了冰

当前的温度为:111 大于100,变成了蒸汽

# 注

注:多态实际上是依附于继承的两种含义,“改变”和“扩展”本身就意味着必须有着一种机制去实现改变和扩展,如果没有多态,两种含义则就不可能实现

# 多态实际上是继承的实现细节,让多态与封装,继承这两个并列,显然不符合逻辑

...

三,封装

封装1 普通的封装形式

# 第一层封装,类就是麻袋,这本身就是一种封装

封装2

# 第二层封装,类中定义私有的,只在类的内部进行使用,而在外部无法进行使用 _ __ (使用单下划线和双下划线)

# 当属性以单下划线 _ 开头,那么它就是属于内部的属性,不能被外部调用(当你发现有用单下划线开头的属性,则不该调用该属性)

# 这只是一种约定,Python并不会真正阻止你访问私有的属性,外部还是能调用的

# 当属性一双下划线开头 __ ,Python会自动做一个重命名的操作,

# 外部不能访问 __star,内部可以进行直接访问 __star

classPeople:__star = "earth"

#__star被 Python重命名为 _People__star

例子

classDog:def __init__(self,name,speed,appetite,master):

self.name=name

self.speed=speed

self.appetite=appetite

self.master=masterdefwalk(self):print("开始遛%s" %self.name)

d= Dog("small_yellow","10km/h","十碗","henry")

#当调用其属性时

print(d.name,d.speed,d.appetite,d.master) #small_yellow 10km/h 十碗 henry

#当调用其方法时

d.walk() #开始遛small_yellow

# 当将类中的属性隐藏起来

classDog:def __init__(self,name,speed,appetite,master):

self.__name =name

self.__speed =speed

self.__appetite =appetite

self.__master =masterdefwalk(self):print("开始遛%s" %self.__name)

d= Dog("small_yellow","10km/h","十碗","henry")

#当调用其属性时 报错

print(d.name) #AttributeError: 'Dog' object has no attribute 'name'

#同样报错

print(d.__name) #AttributeError: 'Dog' object has no attribute '__name'

#当调用其方法时,方法还是可以进行调用

d.walk() #开始遛small_yellow

## 进行隐藏后如何进行访问

classDog:def __init__(self,name,speed,appetite,master):

self.__name =name

self.__speed =speed

self.__appetite =appetite

self.__master =masterdefwalk(self):print("开始遛%s" %self.__name)

d= Dog("small_yellow","10km/h","十碗","henry")

print(d.__dict__)#{'_Dog__name': 'small_yellow', '_Dog__speed': '10km/h', '_Dog__appetite': '十碗', '_Dog__master': 'henry'}#在Python中,当用"__属性名"进行命名时,Python自动将其隐藏的属性的命名格式进行了修改,修改成了“_类名__属性名”

#当然也可以利用 _类名__属性名 来访问对应的属性

print(d._Dog__name) #small_yellow

...

四,@property的使用

当在类中添加一个属性时,如果将属性直接暴露在外,让对象可以随意的调用,这就会让属性可以随意的更改

## 实例化出的对象可以随意的获取和修改 name

classDog:def __init__(self,name):

self.name=name

d=Dog("藏獒")print(d.name) #藏獒

d.name= "中华田园犬"

print(d.name) #中华田园犬

## 在类中添加方法 get_name()来获取名字,添加set_name()来写入名字(现在就不能随心所欲设置名字了)

classDog:defset_name(self,name):if len(name) > 10:print("名字的长度超过10个字符")else:

self.name=namedefget_name(self):returnself.name

d=Dog()

d.set_name("中华田园犬")print(d.get_name()) #中华田园犬

d1 =Dog()

d1.set_name("我是超级可爱的中华田园犬") #名字的长度超过10个字符

## @property的作用就是负责将一个方法变成一个属性调用

classDog:def __init__(self,val):

self.__NAME = val #将数据隐藏起来

@propertydefname(self):return self.__NAME  #obj.name访问的是self.__NAME

@name.setterdefname(self,value):if len(value) > 10:raise TypeError('名字的长度超过10个字符')

self.__NAME =value

d= Dog("中华田园犬")

d.name= "藏獒" #实际转化为 set_name("藏獒")

print(d.name) #实际转化为 get_name

## 可以自定义只读属性,只定以getter方法

#由getter方法和setter方法,为可读可写

classDog:def __init__(self,val):

self.__NAME =val

@propertydefname(self):return self.__NAME@name.setterdefname(self,value):

self.__NAME =value

#只有getter方法,为只读

classCat:def __init__(self,val):

self.__NAME =val

@propertydefname(self):return self.__NAME

...

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值