python3基础知识复习 -- 面向对象编程的封装,继承

面向对象编程

面向对象概念

Object Oriented Programming(OOP)

一种程序设计思想,OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。

  • 对比

    • 面向过程的程序设计把计算机程序视为一系列的命令集合,即一组函数的顺序执行。为了简化程序设计,会把函数切分为子函数降低系统复杂度。

    • 面向对象的程序设计把计算机程序视为一组对象的集合,而每个对象都可以接收其他对象发过来的消息,并处理这些消息,计算机程序的执行就是一系列消息在各个对象之间传递。

  • 三大特点:

    • 封装: 使信息隐蔽安全,通过在实例上调用方法,我们就直接操作了对象内部的数据,但无需知道方法内部的实现细节。

    • 继承:子类自动共享父类之间的数据和方法机制

    • 多态: 不同对象对同一方法响应的不同行动

在这里插入图片描述

# eg: 继承,list本身是一个类对象,Mylist继承自list

 class Mylist(list):
 	pass #表示占位符,目前新类不做事情,只继承上面的

 list2 = Mylist()
 list2.extend('peanutfish')
 list2
['p', 'e', 'a', 'n', 'u', 't', 'f', 'i', 's', 'h']

 list2.sort()
 list2
['a', 'e', 'f', 'h', 'i', 'n', 'p', 's', 't', 'u']


# eg: 多态,调用同一个名字的方法,可以得到不同的结果
# 封装就是通过方法直接可以调用变量但是不需要知道内部实现的细节,更安全

 class A:
    name = "Mike"
 	def fun(self):
		print('%s is coming' % self.name)

 class B:
    name = "John"
	def fun(self):
		print('%s is coming' % self.name)

 a = A()
 b = B()
 a.fun()
Mike is coming

 b.fun()
John is coming

面向对象编程


  • 比喻:类是图纸,类的实例化是可以住人的房子,通过图纸可以建很多房子,每个房子有自己主人,self就是每个房子的门牌号
  • python的self相当于C++的this指针,当对象一个方法被调用时,会将自身作为第一个参数传入self参数,这样就知道是哪个对象在调用方法了
class Ball:
	def setName(self, name):
		self.name = name

	def kick(self):
		print('this is %s, who just kicked me...' % self.name)

 a.setName('A')
 b = Ball()
 b.setName('Dog')
 a.kick()
this is A, who just kicked me...

 b.kick()
this is Dog, who just kicked me...
魔法方法__init__(self)
  • 格式 __init__(self, parm1, parm2…) (注意左右两边双下划线)

  • 注意到__init__方法的第一个参数永远是self,表示创建的实例本身,因此,在__init__方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。

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

   def kick(self):
   	print("this is %s, who kicked me..." % self.name)

c = Cat("BB")*
c.kick()
this is BB, who kicked me...

公有和私有变量
  • name mangling(名字改编,名字重整)

  • 在python中定义私有变量只需要在他们前面加上"__"两个下划线(伪私有) ,只有内部可以访问外部不能访问。如果需要外部进行访问或者修改可以添加相应的get xxx 和 set xxx的方法实现。

    • 但是python中的属性没有权限控制,都可以被外部调用,通过 _object._Class__attri(前面单下划线,后面双下划线) eg: p._Person__name
class Dog:
   __name = "Cow"

e = Dog()
e.__name
Traceback (most recent call last):
File "<pyshell#47>", line 1, in <module>
e.__name
AttributeError: 'Dog' object has no attribute '__name'

>>> e._Dog__name
'Cow'

继承
  • class DerivedClassname(BaseClassname) – 被继承的类–> 父类、基类(base class),超类(super class)

  • object类时所有类最终都会继承的类

  • 如果子类中定义与父类同名的方法或属性,则会自动覆盖父类对应的方法或属性。

  • 当子类重写了父类的方法,会覆盖父类的方法,通过下面方法,可以继续继承父类的方法:

    • 调用未绑定的父类方法
def __init__(self):
	Parent.__init__(self)
  • 使用super函数
def __init__(self):
	super().__init__()
多重继承

class DerivedClassname(Base1, Base2, Base3…)

  • 通过多重继承,一个子类就可以同时获得多个父类的所有功能。
  • 如果继承两个爹类的类方法相同时,优先继承括号前面的类方法
eg:

class Fish():
	def init(self):
		self.x = r.randint(0, 10)
		self.y = r.randint(0, 10)

	 def move(self):
		 self.x -= 1
		 print("Position is", self.x, self.y)

class Goldfish(Fish):
 	 pass

class Shark(Fish):
	 def __init__(self):
	 	Fish.init(self) --- 调用未绑定的父类
	 	super().init() -- 使用super函数自动查找父类或者父类的父类定义的同名方法。
		self.hungry = True

 	def eat(self):
		if self.hungry:
			print("Eating now...")
			self.hungry = False
 		else:
			print("Full now...")

组合法
  • 把旧类的实例放到一个新类里面,这样就把旧类组合起来了,属于横向的组合,纵向组合就是继承

  • 新类使用其他类的实例进行初始化

class Turtle:
	def init(self, x):
		self.num = x

#### 

class Fish:
	def init(self, x):
		self.num = x

#### 

class Pool:
	def init(self, p1, p2):
		self.turtle = Turtle(p1) --- 将Turle的实例化直接赋给了Pool的属性
		self.fish=Fish(p2)

#### 

def print(self):
	print("We have total %d turtle, %d fish in the pool!" %(self.turtle.num, self.fish.num))

pool = Pool(2, 3)
We have total 2 turtle, 3 fish in the pool!

mix-in
  • 方法
    https://fishc.com.cn/thread-48888-1-1.html

  • 在设计类的继承关系时,通常,主线都是单一继承下来的,例如,Ostrich继承自Bird。但是,如果需要“混入”额外的功能,通过多重继承就可以实现,比如,让Ostrich除了继承自Bird外,再同时继承Runnable。这种设计通常称之为MixIn。(Note: 单一继承语言不支持MixIn, 比如Java)

  • class Dog(Mammal, RunnableMixIn, CarnivorousMixIn):
        pass
    

    MixIn的目的就是给一个类增加多个功能,这样,在设计类的时候,我们优先考虑通过多重继承来组合多个MixIn的功能,而不是设计多层次的复杂的继承关系。

    Python自带的很多库也使用了MixIn。举个例子,Python自带了TCPServerUDPServer这两类网络服务,而要同时服务多个用户就必须使用多进程或多线程模型,这两种模型由ForkingMixInThreadingMixIn提供。通过组合,我们就可以创造出合适的服务来。

    比如,编写一个多进程模式的TCP服务,定义如下:

    class MyTCPServer(TCPServer, ForkingMixIn):
        pass
    
限制实例的属性

使用__slots__

但是,如果我们想要限制实例的属性怎么办?比如,只允许对Student实例添加nameage属性。

为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性:

class Student(object):
    __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称

然后,我们试试:

>>> s = Student() # 创建新的实例
>>> s.name = 'Michael' # 绑定属性'name'
>>> s.age = 25 # 绑定属性'age'
>>> s.score = 99 # 绑定属性'score'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'score'

由于'score'没有被放到__slots__中,所以不能绑定score属性,试图绑定score将得到AttributeError的错误。

使用__slots__要注意,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的:

>>> class GraduateStudent(Student):
...     pass
...
>>> g = GraduateStudent()
>>> g.score = 9999

除非在子类中也定义__slots__,这样,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值