我个人认为可以将其与函数的定义结合起来理解,即尽可能的将实现细节隐藏,在我们实现该函数的功能时,可以通过较为直观的方式去调用它实现这个功能,但是不需要你展现其实现的每一步骤。书上的一段结合我们日常生活常场景的话我认为可能更有助于理解:
例如,如果你向人打听怎么去电影院,就不希望对方回答:“向前走10步,向左 转90度,接着走5步,再向右转45度,然后走123步。”听到这样的回答,你肯定一头雾水。
如果对方回答:“沿这条街往前走,看到过街天桥后走到马路对面,电影院就在你左边。”你 肯定能明白。这里的关键是你知道如何沿街往前走,也知道如何过天桥,因此不需要有关这些方 面的具体说明。
- 作用域
这里的“域”很好理解,也就是范围的意思,而作用域又分为全局作用域和局部作用域,而当我们定义函数的时候,每个函数都会创建一个局部变量,而局部变量的作用范围也仅限与该函数内部:
def name_test():
x = 1
而全局变量也就是作用范围在全局的变量,但是当函数内定义的变量与全局变量同名的话,在函数内直接调用的就是局部变量值,其对全局变量进行了遮盖,若是想在函数内调用全局变量的值,可使用函数globels
对全局变量进行调用。
其中还涉及到的一个概念是作用域嵌套,就是将一个函数放在另一个函数内。
- 递归
在之前系列的文章中介绍过如何调用函数,而递归则是函数调用其自身,我们通过将问题分解为较小的部分,可以避免无限递归,因为问题最终会被分解成基线条件可以解决的最小问题。而递归中包含的两个条件分别是: - 基线条件(针对最小的问题):满足这种条件时函数直接返回一个值。用人话来说就是可以让函数停止递归(调用自己)的条件。
- 递归条件:包含一个或者多个调用,这些调用旨在解决问题的一个部分。用人话来说就是指函数调用自己。
def count_down(i):
"""倒计时"""
print(i)
if i <= 1: # 基线条件(指函数不再调用自己)
return
else: # 递归条件(指函数调用自己)
count_down(i-1)
count_down(3)
ps:虽然递归可完全被循环所替代,并且在大多数的情况下循环的效率更高,但是递归的可读性相对会更高一些,并且我们即使不使用递归,也要能看懂别人写的递归,这是非常重要的,而且递归的可读性也较好一些的。
-
多态
可对不同类型的对象执行相同的操作,并且这些操作可以正常运行。 -
封装
对外部隐藏有关对象的工作原理。 -
继承
在我之前的文章中已经对继承有过基本的介绍,在这里就根据现在看的这本书在内容上做一些小小的补充。
issubclass
:确定一个类是否为另一个类的子类,可使用该内置方法,返回一个布尔值。
>>> issubclass(SPAMFilter, Filter)
True
isinstence
:可使用该函数进行类型检查以及确定对象是否为特定类的实例。
__base__
:如果你有一个类,并想知道一个类的基类,可访问其特殊属性“base”。
>>> Filter.__bases__
(<class 'object'>,)
-
多重继承:即继承多个父类,但是尽可能的不要出现这种情况,比如在继承的多个父类中都具有相同名称的方法,那位于前面的类中的方法会将后面的同名方法覆盖掉。(可使用方法解析顺序)
-
接口&内省:
- 内省:有时也叫类型内省,是在运行时进行的一种对象检测机制。我们可以通过内省来获取一个对象的所有信息,比如这个对象的类型,其中包含哪些属性等等。
>>> hasattr(tc, 'talk')
True
>>> hasattr(tc, 'fnord')
False
-
接口:以我现在的水平(当然可能也还不能称之为水平)我将接口暂时理解为是抽象类中定义的方法。在可以实例化的类中称之为方法,在不能实例化的抽象类中就称之为接口。
-
抽象类:关于抽象类这里我理解的并不清晰,更多的还是从定义中去理解它,比如是类的模版,是不能被实例化的类等等。但实际上我对其中的原理尚不明了,这也暂时作为我挖的一个坑,希望日后的我可以用代码量将其填上吧。