• Python面向对象基本特征


    面向对象基本特征

    封装

    封装是指对外界隐藏信息,不能随意访问、修改对象的数据和方法

    封装是通过限制类的属性和方法的访问方式来实现的封装效果

    封装的三个层次:

    1. 类的封装:外部可以任意访问、修改类中的属性和方法
    2. 私有属性:外部不可以访问、修改勒种的属性和方法
    3. 公有方法+私有属性:外部有条件限制的访问、修改属性,调用方法

    封装表现1:

    类的定义:将某些特定属性和方法进行“隔离”

    每个学生有自己的年龄,外部可以任意读取或者修改

    class Student:
    
    	def __init__(self,name,age):
    		self.name = name
    		self.age = age
    
    s1 = Student("李白",18)
    s2 = Student("杜甫",20)
    s2.age = 200
    print(s1.name)
    print(s2.age)
    

    封装表现2:

    属性私有:只能在类的内部使用,外部不能使用

    不让外部读取、修改学生的年龄

    class Student:
    
    	def __init__(self,name,age):
    		self.name = name
    		self.__age = age	#使用两个下划线开头的属性,定义为私有属性
    		print(self.__age)
    
    	__secret = True  
    
    s1 = Student("李白",18)
    # print(s1.__age)		#外界无法直接通过属性名称来访问
    #虽然语法可以在外部通过_Student__age访问到私有属性,但是不推荐使用
    print(s1._Student__age)
    
    #__dict__查看当前对象或者类有哪些属性
    print(s1.__dict__)
    print(Student.__dict__)
    

    封装表现3:

    私有属性+ 公有方法:有限制条件的开放给外部

    可以读取年龄,但不能随意修改年龄

    设定年龄必须在(1,125)之间

    class Student:
    
    	def __init__(self,name,age):
    		self.name = name
    		self.__age = age
    
    	def getAge(self):
    		return self.__age
    
    	def setAge(self,age):
    		if 0 < age < 125:
    			self.__age = age
    		else:
    			print("年龄不符合人类")
    s1 = Student("李白",18)
    print(s1.getAge())
    s1.setAge(200)
    print(s1.getAge())
    

    私有方法

    可以在类的内部使用,有条件的开放给外部

    class Person:
    	def __tellSercert__(self):
    		print("夏天夏天悄悄过去,留下小秘密~~~~")
    
    	def talk(self,object):
    		if object == "好基友":
    			self.__tellSercert__()
    		else:
    			print("我是一个木得感情木得秘密的人")
    
    ming = Person()
    ming.talk("好基友")
    ming.talk("隔壁小黑")
    

    封装的简化写法

    装饰器

    property装饰器:把一个方法伪装成一个属性,在调用这个方法的时候不需要加()就可以直接得到返回值

    class Dog:
    
    	@property			#装饰器
    	def bark(self):
    		print("旺旺旺~~~")
    		return 89757
    
    d = Dog()
    
    num = d.bark  #注意这里没有括号呦
    print(num)
    

    总结

    使用@property装饰器时,方法名不必与属性名相同

    可以更好的防止外部通过猜测私有属性名称来访问

    凡是赋值语句就会触发set方法,获取属性值会触发get方法

    继承

    面临的问题:

    • 相似类型的定义会产生大量重复的代码
    • 类的定义没有很好的扩展性‘

    解决的方法:

    定义类和类之间的关系,子类拥有父类的全部属性和方法,并可以为之扩充

    示例

    class Pet:
    
    	def __init__(self,name,age):
    		self.name = name
    		self.age = age
    		print(f"一只名字叫{self.name}的宠物出生了")
    
    	def eat(self):
    		print(f"{self.name}在吃东西~~~")
    
    	def run(self):
    		print(f"{self.name}在溜达~~~")
    
    
    class Dog(Pet):
    	pass
    
    
    class Cat(Pet):
    	pass
    
    d = Dog("咯咯",3)
    d.run()
    
    c = Cat("布丁",1)
    c.eat()
    

    1.继承的概念:

    • Dog和Cat继承了Pet类
    • Dog和Cat称为Pet的子类、派生类
    • Pet称为Dog和Cat的父类、超类、基类
    • 子类默认拥有父类公有的属性和方法的定义

    2.子类调用方法的顺序

    • 调用方法时,子类中有的,调用子类中的
    • 子类中没有的,调用父类的
    • 一旦在子类中找到,就不在去父类中查找了
    子类不能继承父类的私有属性或者方法
    class Father:
    	__secret = "小秘密"
    	story = "从前有座山,山上有座庙"
    
    	def tellStory(self):
    		print(self.story)
    
    	def __tellSecret(self):
    		print(self.__secret)
    
    class Son(Father):
    	def tell(self):
    		# self.tellStory()
    		self.__tellSecret()
    s = Son()
    s.tell()
    

    3.重写/覆盖

    • 子类和父类拥有相同名称的方法
    • 可以理解为子类对于父类行为的扩展和补充
    class Pet:
    	master = True
    
    	def __init__(self,name,age):
    		self.name = name
    		self.age = age
    		print(f"一只名字叫{self.name}的宠物出生了")
    
    	def eat(self):
    		print(f"{self.name}在吃东西~~~")
    
    	def run(self):
    		print(f"{self.name}在溜达~~~")
    
    
    class Dog(Pet):
    	#重写父类方法
    	def eat(self):
    		print(f"{self.name}在啃骨头")
    	#扩充,定义子类特有功能
    	def lookAfter(self):
    		print(f"{self.name}在看门,汪汪汪!")
    
    d = Dog("旺财",2)
    d.eat()
    d.lookAfter()
    

    4.子类可以在类定义时,可以使用super()调用父类的方法

    应用1:和重写不同,重写是对父类方法的完全覆盖,这是对父类方法的补充
    class Pet:
    	def __init__(self,name,age):
    		self.name = name
    		self.age = age
    		print(f"一只名字叫{self.name}的宠物出生了")
    
    	def eat(self):
    		print(f"{self.name}在吃东西~~~")
    
    	def run(self):
    		print(f"{self.name}在溜达~~~")
    
    
    class Cat(Pet):
    
    	def eat(self):
    		print(f"{self.name}伸了个懒腰")
    		super().eat()
    		print(f"{self.name}吃完东西后,舔了舔爪子")
    
    c = Cat("布丁",2)
    c.eat()
    
    应用2:对象初始化时,简化重复属性的赋值
    class Cat(Pet):
    
    	def __init__(self,name,age,sex):
    		# self.name = name
    		# print(f"一只名叫{self.name}的宠物出生了")
    		super().__init__(name)		#代替了上两句代码,简化了重复属性的赋值
    		self.age = age
    		self.sex = sex
    

    5.多继承

    • 子类可以有多个父类
    • 例如:狗是脊椎动物,哺乳动物,宠物。。。
    class Father:
    	caihua = "有才"
    
    
    class Mother:
    	yanzhi = "有貌"
    
    
    class Child(Father,Mother):
    	pass
    
    c = Child()
    print(c.caihua,c.yanzhi)
    
    print(Child.__bases__)		#可以通过类名.__bases__查看其父类
    

    6.访问子类的属性或者方法时,解析的路径(顺序)

    class Father:
    	def getMoney(self):
    		print("爸爸给了零花钱")
    
    class Mother:
    	def getMoney(self):
    		print("妈妈给了零花钱")
    
    class Child(Father,Mother):
    	def getMoney(self):
    		super().getMoney()	
    		#按照继承的顺序查找父类中的方法,所以先找Father类
    		print("孩子获得了零花钱")
    
    c = Child()
    c.getMoney()
    

    从第一个父类开始向上查找,直到查找结束都没有,再对第二个父类进行查找

    深度优先:Child -> Father -> GrandFather -> Mother

    class GrandFather:
    	pass
    	# def getMoney(self):
    	# 	print("爷爷给了零花钱")
    
    class Father(GrandFather):
    	pass
    	# def getMoney(self):
    	# 	print("爸爸给了零花钱")
    
    class Mother:
    	def getMoney(self):
    		print("妈妈给了零花钱")
    
    class Child(Father,Mother):
    	def getMoney(self):
    		super().getMoney()
    		#按照继承的顺序查找父类中的方法,所以先找Father类
    		print("孩子获得了零花钱")
    
    c = Child()
    c.getMoney()
    print(Child.mro())		#可以通过类名.mro()的方式来查看类的解析顺序
    
    • object是所有类的父类
    • “万事万物”皆为对象,因为所有的类都默认继承object

    7.菱形继承

    image-20201118083544047

    广度优先:Child -> Father -> Mother -> Human

    image-20201118084332241

    多态

    想要解决的问题

    • 让程序能够有更强的灵活性
    • 让程序能够有更好的适应性
    • 概念:一个类的多种形态

    情况1:通过继承和重写来实现

    class Animal:
    	def eating(self):
    		print("动物在吃东西")
    
    
    class Pet(Animal):
    	def eating(self):
    		print("宠物在吃东西")
    
    class Dog(Pet):
    	def eating(self):
    		print("狗在啃骨头~")
    
    class Cat(Pet):
    	def eating(self):
    		print("小猫在吃鱼")
    
    class Zoo:
    	def animalEating(self,animal):
    		animal.eating()
    
    z = Zoo()
    a = Animal()
    p = Pet()
    d = Dog()
    c = Cat()
    #Dog和Cat都作为Animal的不同形态
    #都可以直接调用animal所具有的属性和方法
    z.animalEating(a)
    z.animalEating(p)
    z.animalEating(d)
    z.animalEating(c)
    

    情况2:Python持有

    没有继承关系,但是也具备相同的特征、方法,也可以直接使用

    class venusFlytrap:		#捕蝇草
    	def eating(self):
    		print("捕蝇草在吃小虫子")
    
    
    v = venusFlytrap()
    z.animalEating(v)
    

    捕蝇草不继承于Animal类,但是具有和它相同的特征,在python只要具有相同的特征和方法,没有继承关系也可以直接使用

    type和isinstance

    #type判断类型时,只看直接类型
    print(type(c) is Cat)		#True
    print(type(c) is Animal)	#False
    print(type(c) is Pet)	#False
    #isinstance 判断对象是否为一个类型的实例
    #判断实例类型时,涵盖父类的类型
    print(isinstance(c,Cat))	#True
    print(isinstance(c,Pet))	#True
    print(isinstance(c,Animal))	#True
    print(isinstance(venusFlytrap,Animal))	#False
    
  • 相关阅读:
    数组的复制
    ==与equals()区别
    构造器与方法
    数据类型及类型转换
    java标识符与命名规则
    多线程 总结
    局部变量与成员变量
    Java反射机制
    java的动态代理机制详解
    USB设备描述符
  • 原文地址:https://www.cnblogs.com/icyhblog/p/14068282.html
Copyright © 2020-2023  润新知