Python基础教程(第三版)读书笔记(7)

再谈抽象

这一章学习Python面向对象编程,学习对象、类、多态、封装、继承、接口和内省。

对象魔法

  • 多态: 可对不同类型的对象执行相同的操作。
  • 封装: 对外部隐藏有关对象工作原理的细节。
  • 继承: 可基于通用类创建出专用类

多态

Python中多态用的地方超级多,也叫鸭子模型。我们一直用的‘+’就应用了多态。它的功能是将俩个对象相加,至于对象是什么类型。它并不在意,无论是数字还是字符串类型。它都可以使用。这就是多态。

>>> 1 + 1
2
>>> 'one' + 'one'
'oneone'

封装

封装就像用电视机,你按电源,电视打开。但是你不知道具体是怎么实现的。对于外部它是保密的,是密封的。python中的封装是需要将属性变成私有的。

继承

继承就像是子承父业,孩子不需要做什么就可以拥有和父亲一样多的东西。孩子还可以在父亲的基础上做出自己的东西。也可以把父亲的企业按照自己的意愿再修改。

类是一种抽象。一种概括,人细分的话有很多很多种人,但是特别的分的话只有男人和女人两种人。类就是这样,概括最重要的部分。而具体到每个个体,这个个体就是一个对象,是男人类或者女人类的一个实例。如果稍微细分一点,分为男青年类,男青年类就是男人类的一个子类。而男人类就是男青年类的一个超类

创建自定义类

python中使用class语句定义类。

SyntaxError: invalid syntax
>>> class Person:

	def set_name(self, name):
		self.name = name
	def get_name(self):
		return self.name
	def greet(self):
		print("Hello, world! I'm {}.".format(self.name))

类中的函数叫做方法。方法和函数区别在于方法的第一个参数总是self。那么self是什么呢?self指向对象本身。

私有属性

默认情况下,可从外部访问对象的属性。所以python中没有私有属性,但是要让方法或者属性变成私有的(不能从外部访问),只需让其名称以两个下划线打头即可。

>>> class Secretive:
	def __inaccessible(self):  # 私有方法
		print('Bet you can\'t see me ')
	def accessible(self):
		print('The secret message is: ')
		self.__inaccessible()
		pass

	
>>> s = Secretive()
>>> s.__inaccessible() # 私有方法,无法在类外部访问
Traceback (most recent call last):
  File "<pyshell#63>", line 1, in <module>
    s.__inaccessible()
AttributeError: 'Secretive' object has no attribute '__inaccessible'
>>> s.accessible()
The secret message is: 
Bet you can't see me 

可以在使用私有方法时在开头加上一个下划线和类名,来在类外访问私有方法。

>>> s._Secretive__inaccessible()
Bet you can't see me 
>>> # No I can see you

类的命名空间。

定义类时,在class语句中定义的代码都是在一个特殊的命名空间(类的命名空间)里执行的。另外类定义其实就是要执行的代码段

>>> class C:
	print('Class C being defined')

	
Class C being defined

看下面代码的示范,其中定义了一个属性member。再次体会一下类的命名空间。

>>> class MemberCounter:
	members = 0
	def init(self):
		MemberCounter.members += 1
		pass

	
>>> m1 = MemberCounter()
>>> m1.init()
>>> MemberCounter.members
1
>>> m2 = MemberCounter()
>>> m2.init()
>>> MemberCounter.members
2
>>> m1.members
2
>>> m2.members
2

每个实例都可访问这个类作用域内的变量。但是,在实例中给属性赋值时会遮盖。相当于局部变量和全局变量的关系。

>>> m1.members = 'Two'
>>> m2.members
2
>>> m1.members
'Two'
>>> MemberCounter.members
2
>>> m2.members is MemberCounter.members
True
>>> m1.members is m2.members
False

指定超类

>>> class Filter:
	def init(self):
		self.blocked = []
		pass
	def filter(self, sequence):
		return [x for x in sequence if x not in self.blocked]

在class语句中的超类名,并将其用圆括号括起。

>>> class SPAMFilter(Filter):  # SPAMFilter是Filter的子类
	def init(self): 	# 重写超类Filter的方法init
		self.blocked = ['SPAM']
		pass
	pass

>>> f = Filter()
>>> f.init()
>>> f.filter([1, 2, 3])
[1, 2, 3]
>>> s = SPAMFilter()
>>> s.init()
>>> s.filter(['SPAM', 'SPAM', 'SPAM', 'SPAM', 'eggs', 'bacon', 'SPAM'])
['eggs', 'bacon']

深入探讨继承

使用内置方法issubclass判断一个类是否是另一个类的子类】

>>> issubclass(SPAMFilter, Filter)
True
>>> issubclass(Filter, SPAMFilter)
False

使用__bases__ 寻找一个类的基类

>>> SPAMFilter.__bases__
(<class '__main__.Filter'>,)
>>> Filter.__bases__
(<class 'object'>,)

使用isinstance确定对象是否是特定类的实例

>>> s = SPAMFilter()
>>> isinstance(s, SPAMFilter)
True
>>> isinstance(s, Filter)
True
>>> isinstance(s, Class)
False

如果你要获悉对象属于哪个类,可使用属性__class__

>>> s.__class__
<class '__main__.SPAMFilter'>

多个超类

Python支持多重继承

>>> class Calculator:
	def calculate(self, expression):
		self.value = eval(expression)

>>> class Talker:
	def talk(self):
		print('Hi, my value is ', self.value)
				
>>> class TalkingCalculator(Calculator, Talker):
	pass

>>> tc = TalkingCalculator()
>>> tc.calculate('1 + 2 +3')
>>> tc.talk()
Hi, my value is  6

接口

接口类似于多态,介绍几个方法。
使用hasattr(),检查方法是否存在

>>> hasattr(tc, 'talk')
True
>>> callable(getattr(tc, 'talk', None))
True

使用setattr(),设置对象的属性

>>> setattr(tc, 'name', 'Mr.Gumby')
>>> tc.name
'Mr.Gumby'

使用__dict__检查对象中存储的所有值。

>>> tc.__dict__
{'value': 6, 'name': 'Mr.Gumby'}

抽象基类

介绍一下显示接口,即抽象类。python之前的不支持的,之后通过引入模块abc提高了官方解决方案。

模块abc,显式接口

使用@abstactmethod来将方法标记为抽象的

>>> from abc import ABC, abstractmethod
>>> class Talker(ABC):
	@abstractmethod
	def talk(self):
		pass

抽象类无法实例化,抽象类需要继承

>>> Talker()
Traceback (most recent call last):
  File "<pyshell#197>", line 1, in <module>
    Talker()
TypeError: Can't instantiate abstract class Talker with abstract methods talk

继承的子类若没有重写抽象方法,还是抽象类。直到抽象方法被重写。

>>> class Knigger(Talker):
	def talk(self):
		print("NI!")
	
>>> k = Knigger()

小结

  • 对象: 对象由属性和方法组成。属性不过是属于对象的变量,而方法是存储在属性的函数。相比于其他函数,(关联的)方法有一个不同之处,那就是它总是将其所属的对象作为第一个参数,而这个参数通常被命名为self。
  • : 类表示一组(或一类)对象,而每个对象都属特定的类。类的主要任务是定义其实例将包含的方法。
  • 多态: 多态指的是能够同样地对待不同类型和类的对象,即无需知道对象属于哪个类就可以调用其方法。
  • 封装:对象可能隐藏(封装)其内部状态。在有些语言中,这意味着对象的状态(属性)只能通过其方法来访问。在Python中,所有的属性都是公有的,但直接访问对象的状态时应谨慎行事,因为这可能在不经意间导致状态不一致。
  • 继承:一个类可以是一个或多个类的子类,在这种情况下,子类将继承超类的所有方法。你可以指定多个超类,通过这样做可组合正交(独立且不相关)的功能。为此,一种常见的做法是使用一个核心超类以及一个或多个混合超类。
  • 接口和内省: 一般而言,你无须过于深入地研究对象,而只依赖于多态来调用所需的方法。然而,如果要确定对象包含哪些方法或属性,有一些函数可供你用来完成这种工作。
  • 抽象基类: 使用模块abc可创建抽象基类。抽象基类用于指定子类必须提供哪些功能,却不实现这些功能。

学习的新函数

函数 描述
callable(object) 判断对象是否是可调用的(如是否是函数或方法)
getattr(object, name[,default]) 获取属性的值,还可提供默认值
hasattr(object, name) 确定对象是否有指定的属性
isinstance(object, class) 确定对象是否是指定类的实例
issubclasss(A, B) 确定A是否是B的子类
random.choice(sequence) 从一个非空序列中随机地选择一个元素
setattr(object, name, value) 将对象的指定属性设置为指定的值
type(object) 返回对象的类型

注:小结摘抄于Python基础教程(第三版)

发布了14 篇原创文章 · 获赞 8 · 访问量 225

猜你喜欢

转载自blog.csdn.net/weixin_43582715/article/details/104028360