版权声明:本文为博主原创文章。未经博主同意不得转载。 https://blog.csdn.net/signjing/article/details/30745465

抽象

懒惰即美德。

抽象和结构

抽象能够节省大量工作,实际上它的作用还要更大。它是使得计算机程序能够让人读懂的关键。

创建函数

函数能够调用(可能包含參数,也就是放在圆括号里的值),它运行某种行为而且返回一个值。一般来说,内建的callable函数能够用来推断函数是否可调用:

>>> import math

>>> y=1

>>> x=math.sqrt

>>> callable(x)

True

>>> callable(y)

False

 

创建函数是组织程序的关键。

那么如何定义函数呢?

使用def(或“函数定义”)语句就可以:

>>> def hello(name):

return 'Hello, ' + name + '!'

 

传入不同的參数。得到不同的结果:

>>> print hello('signjing')

Hello, signjing!

>>> print hello('jiao')

Hello, jiao!

 

斐波那契数列的获取方法(比如,前10项)为:

>>> f=[0,1]

>>> for i in range(8):

f.append(f[-1]+f[-2])

 

>>> print f

[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

 

假设用函数的方法实现。则为:

>>> def fibs(num):

result=[0,1]

for i in range(num-2):

result.append(result[-2]+result[-1])

return result

 

运行结果:

>>> fibs(10)

[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

>>> fibs(16)

[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]

 

return语句是用来从函数中返回值的。

记录函数

假设想给函数写文档,让后面使用该函数的人能理解的话。能够增加凝视(以#开头)。

另外一个方式是直接写上字符串。

这里字符串在其它地方可能会非常实用,比方在def语句后面(以及在模块或类的开头)。假设在函数的开头写下字符串,它就会成为函数的一部分进行存储。称为文档字符串。

>>> def fibs(num):

'fibs is a funtion:*************'

result=[0,1]

for i in range(num-2):

result.append(result[-2]+result[-1])

return result

 

>>> fibs.__doc__

'fibs is a funtion:*************'

 

注意:__doc__是函数属性。

内建的help函数非常实用。

在交互式解释器中使用它,就能够得到关于函数,包含它的文档字符串的信息。

>>> help(fibs)

Help on function fibs in module __main__:

 

fibs(num)

    fibs is a funtion:*************

 

并非真正函数的函数

数学意义上的函数,总在计算其參数后返回点什么。python的有些函数却并不返回不论什么东西。

没有return语句。或者虽有return语句但return后边没有跟不论什么值的函数不返回值。

 

>>> def test():

print "This is printed"

return

print 'this is not'

 

>>> x=test()

This is printed

上述函数中的return语句仅仅起到结束函数的作用。

>>> x

>>> print x

None

 

所以,全部的函数的确都返回了东西:当不须要它们返回值的时候。它们就返回None。

參数魔法

值从哪里来

写在def语句中函数名后面的变量通常叫函数的形式參数,而调用函数时提供的值是实际參数,或者成为參数。

我能改变參数吗?

在函数内为參数赋予新值不会改变外部不论什么变量的值。

>>> def try_to_change(n):

n="Hello , signjing"

 

>>> say="Hello , jiao"

>>> try_to_change(say)

>>> say

'Hello , jiao'

 

字符串(以及数字和元组)是不可变的。即无法被改动。所以它们做參数的时候也就无需多做介绍。

但假设将可变的数据结构如列表做參数的时候会发生什么:

 

>>> def change(n):

n[0]='signjing'

 

>>> names=['Li lei','Han meimei']

>>> change(names)

>>> names

['signjing', 'Han meimei']

 

以下不用函数调用再做一次:

>>> names=['Li lei','Han meimei']

>>> n=names

>>> n[0]='signjing'

>>> names

['signjing', 'Han meimei']

 

之前也出现过这样的情况:当两个变量同一时候引用一个列表的时候,它们的确是同一时候引用一个列表。

假设想避免这样的情况。能够复制一个列表的副本。当在序列中做切片的时候,返回的切片总是一个副本。因此。假设你复制了整个列表的切片,将会得到一个副本:

>>> n=names[:]

>>> n

['Li lei', 'Han meimei']

>>> names

['Li lei', 'Han meimei']

>>> n is names

False

>>> m=n

>>> m is n

True

 

 

在某些语言(如c++、Ada)中,重绑定參数而且使这些改变影响到函数外的变量是非常寻常的事情。

但在python中是不可能的。函数仅仅能改动參数对象本身。

但假设參数不可变,如数字。又该怎么办呢?答案是没有办法。

这时候应该从函数中返回全部须要的值,假设值多于一个。则以元组形式返回。

比如。将变量数值增1的函数能够这样写:

>>> def inc(x):return x+1

 

>>> foo=10

>>> foo=inc(foo)

>>> foo

11

 

假设真的想改变參数,能够使用一点小技巧。即将值放置在列表中:

>>> def inc(x):x[0]=x[0]+1

 

>>> foo=[10]

>>> inc(foo)

>>> foo

[11]

这样就仅仅会返回新值。

 

keyword參数和默认值

眼下我们所使用的參数都叫做位置參数,由于它们的位置非常重要——其实比它们的名字更重要。

>>> def hello_1(greeting,name):

print '%s,%s' %(greeting,name)

 

>>> def hello_2(name,greeting):

print '%s,%s' %(name,greeting)

 

>>> hello_1('hello','boy')

hello,boy

>>> hello_2('hello','girl')

hello,girl

 

有些时候(尤其是參数非常多的时候)。參数的顺序是非常难记住的。为了让事情简单些,能够提供參数的名字:

>>> hello_1(greeting='hello',name='boy')

hello,boy

>>> hello_1(name='boy',greeting='hello')

hello,boy

但參数名和值一定要相应:

>>> hello_2(name='boy',greeting='hello')

boy,hello

>>> hello_2(greeting='hello',name='boy')

boy,hello

 

这类使用參数名提供的參数叫做keyword參数。

主要作用是明白每一个參数的作用。

keyword參数最厉害的地方在于能够在函数中给參数提供默认值。当參数具有默认值的时候。调用的时候就不用提供參数了。能够不提供、提供一些或者提供全部的參数:

>>> def hello_3(greeting='hello',name='world'):

print '%s,%s!' %(greeting,name)

 

>>> hello_3()

hello,world!

>>> hello_3('Greeting')

Greeting,world!

>>> hello_3('Greeting','universe')

Greeting,universe!

>>> hello_3(name='boys')

hello,boys!

 

位置和keyword參数是能够联合使用的。

把位置參数放置在前面就能够了。

 

注意:除非全然清楚程序的功能和參数的意义。否则应该避免混合使用位置參数和keyword參数。

 

收集參数

有时候让用户提供随意数量的參数是非常实用的。

试着像以下这样定义函数:

>>> def print_params(*params):

print params

 

>>> print_params(1,2)

(1, 2)

>>> print_params(1,2,'ab')

(1, 2, 'ab')

 

參数前的星号将全部值放置在同一个元组中。能够说是将这些值收集起来,然后使用。

>>> def print_params_2(title,*params):

print title

print params

 

>>> print_params_2('Params: ',1,2,3)

Params: 

(1, 2, 3)

 

假设不提供不论什么供收集的元素,params就是空元组:

>>> print_params_2('Nothing: ')

Nothing: 

()

 

>>> print_params_2('Hmm...',something=42)

 

Traceback (most recent call last):

  File "<pyshell#73>", line 1, in <module>

    print_params_2('Hmm...',something=42)

TypeError: print_params_2() got an unexpected keyword argument 'something'

我们须要另外一个能处理keyword參数的“收集”操作。

>>> def print_params_3(**params):

print params

 

>>> print_params_3(x=1,y=2,z=3)

{'y': 2, 'x': 1, 'z': 3}

 

 

反转过程

>>> def add(x,y):

return x+y

 

>>> params=(1,2)

>>> add(*params)

3

在调用中使用而不是在定义中使用。

 

对于參数列表来说工作正常。仅仅要扩展到部分是最新的就能够。能够使用相同的技术来处理字典——使用双星号运算符。

 

>>> def hello_3(greeting='hello',name='world'):

print '%s, %s!' %(greeting,name)

 

>>> params={'name':'Sir Robin','greeting':'Well met'}

>>> hello_3(*params)

name, greeting!

>>> hello_3(**params)

Well met, Sir Robin!

 

星号仅仅在定义函数(同意使用不定数目的參数)或者调用(“切割”字典或者序列)时才实用。

 

作用域

变量和所相应的值用的是个“不可见”的字典。

实际上这么说已经非常接近真实情况了。内建的vars函数能够返回这个字典:

>>> x=1

>>> scope=vars()

>>> scope['x']

1

>>> scope['x']+=1

>>> x

2

 

这类“不可见字典”叫做命名空间或者作用域。究竟有多少个命名空间?除了全局作用域外,每一个函数调用都会创建一个新的作用域。

 

參数的工作原理相似于局部变量,所以用全局变量的名字作为參数名并没有问题。

 

假设须要在函数内部訪问全局变量,应该怎么办呢?而且仅仅想读取变量的值(也就是说不想重绑定变量),一般来说是没有问题的:

>>> def combine(parameter):

print parameter+external

 

>>> external='berry'

>>> combine('Shrub')

Shrubberry

 

读取全局变量一般来说并非问题,可是还是有个会出问题的事情。假设局部变量或者參数的名字和想要訪问的全局变量名相同的话,就不能直接訪问了。全局变量会被局部变量屏蔽。

假设的确须要的话,能够使用globals函数获取全局变量值。该函数的近亲是vars,它能够返回全局变量的字典(locals返回局部变量的字典)。

 

重绑定全局变量(使变量引用其它新值):假设在函数内部将值赋予一个变量。它会自己主动成为局部变量——除非告知python将其声明为全局变量。

>>> x=1

>>> def change_global():

global x

x=x+1

 

>>> change_global()

>>> x

2

递归

想到了一个笑话:

你要想理解递归,首先得理解递归。

 

好吧。有点冷,继续热乎的话题....

 

递归的定义(包含递归函数定义)包含它们自身定义内容的引用。

须要查找递归的意思。结果它告诉请參见递归,无穷尽也,一个相似的函数定义例如以下:

>>> def recursion():

return recursion()

 

显然它什么也做不了,理论上讲。它应该永远运行下去。

 

由于每次调用函数都会用掉一点内存,在足够的函数调用发生后,空间就不够了,程序以一个“超过最大递归深度”的错误信息结束:

Traceback (most recent call last):

  File "<pyshell#37>", line 1, in <module>

    recursion()

  File "<pyshell#36>", line 2, in recursion

return recursion()

......

  File "<pyshell#36>", line 2, in recursion

    return recursion()

RuntimeError: maximum recursion depth exceeded

 

这类递归叫无穷递归,相似于while True開始的无穷循环。中间没有break或return语句。

 

实用的递归函数包含以下几个部分:

当函数直接返回值时有基本实例(最小可能性问题);

递归实例,包含一个或者多个问题最小部分的递归调用;

 

两个经典:阶乘和幂

>>> def factorial(n):

result=n

for i in range(1,n):

result*=i

return result

 

>>> factorial(5)

120

 

递归的实现方式:

>>> def factorial(n):

if n==1:

return 1

else:

return n*factorial(n-1)

>>> factorial(4)

24

 

>>> def power(x,n):

result=1

for i in range(n):

result*=x

return result

 

>>> power(5,3)

125

递归实现:

>>> def power(x,n):

if n==0:

return 1

else:

return x*power(x,n-1)

 

>>> power(4,4)

256

还有一个经典:二元查找

此处略;

对象的魔力

创建自己的对象(尤其是类型或者被称为类的对象)是python的核心概念——非常核心。

 

面向对象程序设计中的术语对象基本上能够看作数据(特性)以及由一系列能够存取、操作这些数据的方法所组成的集合。

对象最重要的长处包含以下几个方面:

多态:能够对不同类的对象使用相同的操作;

封装:对外部世界隐藏对象的工作细节。

继承:以普通的类为基础建立专门的类对象。

类和类型

类究竟是什么

类就是一种对象。全部的对象都属于某一个类,成为类的实例。

 

当一个对象所属的类是另外一个对象所属类的子集时。前者就被称为后者的子类。相反,后者就称为前者的超类(基类)。

 

在面向对象程序设计中,子类的关系是隐式的,由于一个类的定义取决于它所支持的方法。定义子类仅仅是定义很多其它(也有可能是重载已经存在的)的方法的过程。

创建自己的类

>>> __metaclass__ = type

>>> class Person:

 

def setName(self,name):

self.name=name

def getName(self):

return self.name

def greet(self):

print "Hello,world!I'm %s." %self.name

 

>>> foo=Person()

>>> bar=Person()

>>> foo.setName('abc')

>>> foo.getName()

'abc'

>>> foo.greet()

Hello,world!I'm abc.

 

self是对于对象自身的引用。

没有它,成员方法就没法訪问他们要对其特性进行操作的对象本身了。

 

特效、函数和方法

默认情况下。程序能够从外部訪问一个对象的特性。

为了让方法或特性变为私有(从外部无法訪问),仅仅要在它的名字前面加上双下划线就可以:

>>> class Secretive:

def __inaccessible(self):

print "Bet you can't see me..."

def accessible(self):

print "The secret message is:"

self.__inaccessible()

 

>>> s.__inaccessible()

 

Traceback (most recent call last):

  File "<pyshell#52>", 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...

 

类的内部定义中,全部以双下划线開始的名字都被“翻译”成前面加上单下划线和类名的形式:

>>> Secretive._Secretive__inaccessible

<unbound method Secretive.__inaccessible>

 

简而言之,确保其它人不会訪问对象的方法和特性是不可能的,可是这类“名称变化术”就是他们不应该訪问这些函数或者特性的强有力信号。

类的命名空间

类的定义其实就是运行代码块,这一点非常实用。

指定超类

将其它类名写在class语句后的圆括号内能够指定超类:

>>> class Filter:

def init(self):

self.blocked=[]

def filter(self,sequence):

return [x for x in sequence if x not in self.blocked]

 

>>> class SPAMFilter(Filter):

def init(self):

self.blocked=['SPAM']

 

 

Filter是个用于过滤序列的通用类。其实它不能过滤不论什么东西:

>>> f=Filter()

>>> f.init()

>>> f.filter([1,3,4])

[1, 3, 4]

 

Filter类的用处在于它能够用作其它类的基类(超类),能够将序列中的“SPAM”过滤出去。

>>> s=SPAMFilter()

>>> s.init()

>>> s.filter(['abc','SPAM',"SPAM",'SPAM','signjing'])

['abc', 'signjing']

调查继承

想要查看一个类是否是还有一个的子类。能够使用内建的issubclass函数:

>>> issubclass(SPAMFilter,Filter)

True

>>> issubclass(Filter,SPAMFilter)

False

 

假设想要知道已知类的基类(们),能够直接使用它的特殊特性__bases__:

>>> SPAMFilter.__bases__

(<class '__main__.Filter'>,)

>>> Filter.__bases__

(<type 'object'>,)

 

相同。还能使用isinstance方法检查一个对象是否是一个类的实例:

>>> isinstance(s,SPAMFilter)

True

>>> isinstance(s,Filter)

True

>>> isinstance(s,str)

False

 

S是SPAMFilter类的(直接)成员。但也是Filter类的间接成员,由于SPAMFilter是Filter的子类。

 

假设想知道一个对象属于哪个类,能够使用__class__特性:

>>> s.__class__

<class '__main__.SPAMFilter'>

多个超类

>>> 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

 

超类能够有多个。

在这里,子类不做不论什么事,从自己的超类继承全部的行为。

这样的行为成为多重继承。是个非常实用的工具。

使用多重继承时,有个须要注意的地方。假设一个方法从多个超类继承,必须要注意一下超类的顺序:

先继承的类中的方法会重写后继承的类中的方法。

python基础教程_学习笔记9:抽象的更多相关文章

  1. python基础教程_学习笔记14:标准库:一些最爱——re

    标准库:一些最爱 re re模块包括对正則表達式的支持,由于以前系统学习过正則表達式,所以基础内容略过,直接看python对于正則表達式的支持. 正則表達式的学习,见<Mastering Reg ...

  2. python基础教程_学习笔记12:充电时刻——模块

    充电时刻--模块 python的标准安装包含一组模块,称为标准库. 模块 >>> import math >>> math.sin(0) 0.0 模块是程序 不论什 ...

  3. python基础教程_学习笔记19:标准库:一些最爱——集合、堆和双端队列

    版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/signjing/article/details/36201499 标准库:一些最爱 集合.堆和双端队 ...

  4. python基础教程_学习笔记1:序列-1

    序列 数据结构:通过某种方式组织在一起的数据元素的集合,这些数据元素能够是数字或者字符,甚至能够是其它数据结构. python中,最主要的数据结构是序列. 序列中的每一个元素被分配一个序号--即元素的 ...

  5. python基础教程_学习笔记10:异常

    异常 什么是异常 Python用异常对象来表示异常情况.遇到错误后,会引发异常.假设异常对象并未被处理或捕捉,程序就会用所谓的回溯(Traceback,一种错误信息)终止运行: >>> ...

  6. python基础教程_学习笔记11:魔法方法、属性和迭代器

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/signjing/article/details/31417309 魔法方法.属性和迭代器 在pyth ...

  7. python基础教程_学习笔记18:标准库:一些最爱——shelve

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/signjing/article/details/36029981 标准库:一些最爱 shelve S ...

  8. python基础课程_学习笔记26:编程的乐趣

    编程的乐趣 编程柔术 当你坐下来,打算如何组织计划要定时,具体程序,然而,无论什么经验.在实现时间的函数的,你会逐渐学会了原来的设计,实用的新知识.我们不应该忽视沿途汲取的教训,相反,它们用于其他设计 ...

  9. python基础课程_学习笔记15:标准库:有些收藏夹——fileinput

    标准库:有些收藏夹 fileinput 重要功能 性能 叙述性说明 input([files[,inplace[,backup]]) 便于遍历多个输入流中的行 filename() 返回当前文件的名称 ...

随机推荐

  1. 201621123001《Java程序设计》第4周学习总结

    1. 本周学习总结 1.1 写出你认为本周学习中比较重要的知识点关键词 关键字:继承,多态,覆盖(Override),重载(Overload),抽象类(abstract)等. 1.2 尝试使用思维导图 ...

  2. tf.trainable_variables() and tf.all_variables()

    tf.trainable_variables()  返回的是 所有需要训练的变量列表 tf.all_variables() 返回的是 所有变量的列表 v = tf.Variable(0, name=' ...

  3. 安装Android开发工具

    这两天开始学Android,首先要要解决的是安装编译器的问题,经过我这两天的探究,我把收获总结一下 最简单的编译器是ADT-bundle,它是一个集成的工具,里面有eclipse,也不需要下载SDK, ...

  4. L251

    Beer before wine, or wine before beer; whatever the order, you’ll feel queer. That, at least, is the ...

  5. 『翻译』Android USB Host

    USB Host When your Android-powered device is in USB host mode, it acts as the USB host, powers the b ...

  6. python 爬虫数据时间转换格式

    from datetime import datetimea = '2018/9/18 10/10'print(datetime.strptime(a,'%Y/%m/%d %H/%M'))>&g ...

  7. HDU 6077 17多校4 Time To Get Up 水题

    Problem Description Little Q's clock is alarming! It's time to get up now! However, after reading th ...

  8. Tail Recusive

    1.尾递归 double f(double guess){ if (isGoodEnough(guess)) return guess; else return f(improve(guess)); ...

  9. ORA-00600: internal error code, arguments: [kole_t2u], [34]

    数据库版本10.2.0.5,Alert 日志存在ORA-600报错 ORA-00600: internal error code, arguments: [kole_t2u], [34], [] -- ...

  10. Java中的List集合和迭代器

    一.Java中的List集合. 终于有时间来好好整理一下Java中的集合. 首先要讲的就是List集合.Java中List集合主要将两个: 第一个是底层使用数组维护的ArrayList,第二个是底层是 ...