Python入门手记(2017新春贺岁版)

##免责声明:本文的目的是进行计算机编程和一些注意事项的纯技术探讨,对于读者应用本文所述事项进行非法行为探索造成的后果一概不负责任。

本文代码引用和免责声明:

/**************************************************************************              *
 *                                                                        *
 * DISCLAIMER: The author of this blog have used their     *
 * best efforts in preparing the work. These efforts include the          *
 * development, research, and testing of the theories and programs        *
 * to determine their effectiveness. The author makes       *
 * no warranty of any kind, expressed or implied, with regard to these    *
 * programs or to the documentation contained in this work. The author *
 * shall not be liable in any event for incidental or       *
 * consequential damages in connection with, or arising out of, the       *
 * furnishing, performance, or use of these programs.                     *
 **************************************************************************/

一、Python基本运算

Python的基本运算基本可以参考其他高级语言的基本运算,本节仅交代其中的一些特例。

  • 一般来说,编程语言中两个整数相除会得到向下取整的整数。但是Python中可以通过如下功能实现两个整数相除获得小数的计算。
from __future__ import division
1 / 2

运行结果为0.5

  • Python // (求整除)运算,若相除两数为浮点数,则结果为浮点型整数。若求余数符号(%)的运算对象为浮点数,则结果为(小余被除数)的浮点数。

  • Python的乘方运算可与模运算在同一个函数中进行,比如 pow(2, 4, 3)即2的4次方模3的值,结果为16%3,等于1。运用此操作效率比%符号更高。

  • Python大整数结尾可加上字母(推荐大写,因为小写l容易与数字1混淆)L表示长整数

  • Python支持复数运算,复数结尾需要加上英文字母j(或其大写J)

  • 此外,Python的运算符是有优先级的。如

 force = g * m1 * m2 / r * r 

这个万有引力公式问题就是没有遵循运算的优先级(参考自普林斯顿大学程序设计导论练习题)。正确的写法应该是

 force = g * m1 * m2 / (r * r)

二、Python语句:分支、循环以及若干表达式:

A、表达式:

**1. print:**在显示屏(或接入计算机的可显示设备)输出指定变量,多个变量之间用逗号隔开。输出时,变量之间会自动被添加一个空格。在python3中,print被作为一个函数了。在print中使用加号就不会导致输出中含有空格,在print语句该行结尾使用逗号就不会导致输出被换行。注意:print不会自动将隔开的数字转化为元组。print的对象均为字符串,还可以用“+”号相连。作用有二:一、忽略逗号产生的空格影响。二、作为一个整体的字符串输出(参考资料1第172页)

**2. import:**Python中的import语句形式多样,可能会出现如下几种形式:

import somemodule
from somemodule import somefunction
from somemodule import *

其中,当导入模块中含有需要调用的重名函数时,有以下几种可能的解决方案:

#假设模块1和模块2都含有open方法:
module1.open(...)
module2.open(...)

#赋予被导入模块新名称:
import math as foobar 
from math import sqrt as foobar

3.赋值语句: Python赋值语句的本质事实上是创造了一个数据字典。这个数据字典可以通过vars()方法获得。举例如下:

>>> x = 1
>>> scope = vars()
>>> scope['x']
1
>>> scope['x'] += 2
>>> x
3

3.1 序列打包:通过序列打包,可以实现在一个语句中同时对多个数据对象进行操作。详见示例。 3.2 连续赋值:将同一个值连续赋给不同的变量。注意:分别赋值和连续赋值可能会导致一些区别,在本文后面讲述is和双等号区别的时候会进一步提到。例如:

#假设somefunction已预先定义:
>>> x = y = somefunction()
#与
>>> y = somefunction()
>>> x = y
# 相同,但是可能与以下语句不同
>>>x = somefunction()
>>>y = somefunction()

也就是说,Python中的等号只是拷贝了存储地址,没有复制内容。需要复制内容的情况在此处需要用两个语句分别执行,在python列表中需要使用a = b[ : ]的操作方式

3.3 增强型赋值(augmented assignments):像其他高级语言一样,可使用+=,-=,*=,/=以及%=等进行赋值。对于能操作字符串的符号来说也适用。但是python不含++和--,需要写成+=1和-=1。

4. Python语句块:

Blocks are used as a means of grouping statements through indentation. (Ref 1, p.g.111)

语句块是指符合特定条件时(例如判断为True或循环)被一起执行的语句的集合。一般的高级语言对于语句块的书写格式没有讲究,只要以分号隔开不同语句即可,空格和换行忽略不计。

然而在Python中,空格符号不一定是忽略不计的。同一个级别的语句块必须被缩排(indent),在本级以及下一集语句块之间要换行并且打一个tab符号(一般Python IDE会自动在敲入换行时为程序员设置好一个tab)。

5. 逻辑谓词:

Python中,以下所有的逻辑谓词意思同False: False None 0 "" () [] {} 其余的谓词,在用户不特殊说明的情形下都是True。Python中的逻辑谓词可以参与基本运算,例如:

>>> True + False + 42
43

Python中,可以用类型转化bool()将其他形式的表达式转化为逻辑变量True或者False。

此外,python中逻辑代数与、或非分别为关键字and, or和!。

**6.变量比较:**Python支持与其他高级语言类似的变量比较,如==,>=, <=等,此处列举几个特殊的比较符。 x is y:区别于x == y,作用是比较x和y是否是同一个对象(种类)。x is not y为类似比较,同理可得。需要注意的是,对于对象的比较推荐使用cmp函数,这个在后文列表与元组中会提到。

7. pass语句:pass语句表示什么都不做。Python中,由于不接受空的控制语句(如空elif),因此如果希望elif的部分什么都不做,就可以插入pass语句(例子见参考资料1 107页)。与pass语句相同的做法是在该处插入一个多行注释

表达式应用举例:
  • 序列打包示例:
>>> x, y, z = 1, 2, 3
>>> print x, y, z
1 2 3

"""Python标准的交换变量写法,
如果还在使用中间变量,
那么你就OUT了。"""

>>> x, y = y, x      
>>> print x, y, z
2 1 3
>>> values = 1, 2, 3
>>> values
(1, 2, 3)
>>> x, y, z = values
>>> x
1

""" 从数据字典随机输出一个元素,并赋值给一个简直对
之后解包键值对,取得相应变量。
"""
>>> scoundrel = {'name': 'Robin', 'girlfriend': 'Marion'}
>>> key, value = scoundrel.popitem()
>>> key
'girlfriend'
>>> value
'Marion'

Python3还支持不对等数量打包和解包,需要打包的元素个数必须多于变量数目,变量序列结尾多于的变量全部会被打包给最后一个变量。

>>> a, b, rest* = [1, 2, 3, 4]
>>> rest
[3, 4]
  • 变量比较示例:
>>> x = [1, 2, 3]
>>> y = [1, 2, 3]
>>> x == y
True  #因为x和y值相同
>>> x is y
False #因为x和y是不同的两个列表

此外,python还提供比较数据结构的功能,例如:

>>> [1, 2] < [2, 1]
True
>>> [2, [1, 4]] < [2, [1, 5]]
True
  • 逻辑谓词使用示例:
"""提示并获得用户输入,
若用户没有输入,则name变量
被赋值给'<unknown>' """
name = raw_input('Please enter your name: ') or '<unknown>'
B、分支语句:

Python如其他高级语言一样支持if型分支语句,格式为if-elif(else if)-else,举例如下:

num = input('Enter a number: ')
if num > 0:
    print 'The number is positive'
elif num < 0:
    print 'The number is negative'
else:
    print 'The number is zero'

通过不同级别的缩进,Python可支持嵌套分支。 此外,python还提供一种轻量级的分支语句:a if b else c。当b为True时,返回a,否则返回c。作用有点像其他高级语言的一个三元操作符?: 。

python用assert关键字提供断言机制,除了不用导入模块之外,使用方式类似C++的断言机制。详细请见博客:《浅谈C++编程中可能会用到的预处理指令》https://my.oschina.net/SamYjy/blog/827660 的调试类预处理指令部分。

C、循环语句:

Python的循环语句大体包括while型、for型以及列表推导式,其中,python的for语句还有一些特殊用法。与其他高级语言类似。由于列表推导式的重要性,因此专门单独列出一个小节整理归纳。

Python支持while语句,举例如下:

name = ""
#当用户输入为空时一直提示输入:
while not name.strip():  
    name = raw_input('Please enter your name: ')    
print 'Hello, %s!' % name

Python的for语句支持对于所有迭代型变量的遍历,举例如下:

words = ['this', 'is', 'an', 'ex', 'parrot']
for word in words:
    print word

xrange([start], stop):返回一个包含从start到但不包括stop的迭代。start参数不选时,默认从0开始。xrange的效率一般来说好于range。 range([start], stop):返回一个包含从start到但不包括stop的数值列表。start参数不选时,默认从0开始,这是py2函数。

Python的range函数和分片操作的数值范围都包含起始值,但是不包括终止值。

循环语句可以对字典元素进行迭代。对字典元素进行迭代时,既可通过d[k]获得对应真值,也可将键值对打包,其中,打包处理的值必须是转化为序列后的字典元素(使用d.items()函数)。示例如下:

>>> d = {'x': 1, 'y': 2, 'z': 3}
>>> for key in d:
	print key, ' corresponds to ', d[key]

y  corresponds to  2
x  corresponds to  1
z  corresponds to  3

>>> for k, v in d.items():
	print k, ' corresponds to ', v

y  corresponds to  2
x  corresponds to  1
z  corresponds to  3

python迭代完成后,迭代变量储存最后一步的值并可以被继续使用:

>>> print k
z

Python中的for语句可以与打包函数zip(iterA, iterB)一起使用,支持对于打包序列按长度较短的迭代进行解包,并且返回值为元组序列。举例如下:

>>> names = ['anne', 'beth', 'george', 'damon']
>>> ages = [12, 45, 32, 102]
>>> for (name, age) in zip(names, ages):
	print(name + " is " + str(age) + " years old.")

anne is 12 years old.
beth is 45 years old.
george is 32 years old.
damon is 102 years old.

>>> zip(xrange(5), xrange(100000000))
[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]

Python中,有时需要在遍历对象的同时记录特定对象的下标,此时,enumerate(seqs) 就是一个可使用的函数:

>>> strings = ["Hello", "John", "xxx"]
>>> for index, string in enumerate(strings):
	if 'xxx' in string:
		strings[index] = '[censored]'
>>> strings
['Hello', 'John', '[censored]']
>>> index
2     

python也支持在循环语句中使用break和continue关键字(详见参考资料1 102-105页)。其中,可以通过在循环体后的同一个级别加一个else从句,设置若循环体中的break关键字未被调用的情形下(也即循环体被完整执行的情况下)需要执行的代码,示例如下:

import math
broke_out = False

#此处81是不会被打印的:
for x in xrange(99, 81, -1):
    root = math.sqrt(x)
    if root == int(root):
        print x
        break
else:
    print "Did not call break!"
    x += 5

print "x is:", x

执行效果:
Did not call break!
x is: 87
D、列表推导式:(参考资料1 105-106页)

Python列表推导式的作用是从一个列表生成另一个列表,其本质类似数据库或集合论中的集合连接运算(set comprehension)。几个使用示例如下:

>>> [x * x for x in xrange(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> [x*x for x in range(10) if x % 3 == 0]
[0, 9, 36, 81]

列表推导式还可以对元组列表进行操作,示例如下:

>>> a = [(x, y) for x in xrange(3) for y in xrange(3)]
>>> print a
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
>>> (b, c) = a[6]
>>> b
2
>>> c
0
>>> 

列表推导式能够操作两个相关集合,举例如下:

>>> girls = ['Alice', 'Bernice', 'Clarice']
>>> boys = ['Chris', 'Arnold', 'Bob']
>>> [b + ' loves ' + g for b in boys for g in girls if b[0] == g[0]]
['Chris loves Clarice', 'Arnold loves Alice', 'Bob loves Bernice']

然而在此例中,由于要检查girls和boys中的每个可能的元素,因此此算法的时间复杂度并不好,为O(n ^ 2)。此例的线性解可以通过将列表推导式与数据字典的使用相结合。以下作用完全相同的两个版本代码通过额外开销数据字典的方式,使得该算法时间复杂度降为O(N): 版本一:

girls = ['Alice', 'Bernice', 'Clarice']
boys = ['Chris', 'Arnold', 'Bob']
letterGirls = {}
for girl in girls:
    letterGirls.setdefault(girl[0], girl)

print [b + ' loves '+ letterGirls[b[0]] for b in boys]

这个版本的代码通过直接向字典中添加girls中的开头字母以及对应的名字,然而在列表推导式中就略显复杂了。(注意此处列表推导式中的g是女生名字开头第一个字母,b是男孩名字)

版本二:

girls = ['Alice', 'Bernice', 'Clarice']
boys = ['Chris', 'Arnold', 'Bob']
letterGirls = {}
for girl in girls:
    tempL = [girl]
    letterGirls.setdefault(girl[0], tempL)
    """This is identical to:
    letterGirls.setdefault(girl[0], []).append(girl),
    however, might be confusing."""

print [b + ' loves '+ g for b in boys for g in letterGirls[b[0]]]

这个版本的代码列表推导式简单了,然而中间需要将girl字符转化为列表以便于获取。

F、对于字符串进行估值或执行的函数exec和eval:

_代码潜在安全漏洞声明: Caution In this section, you learn to execute Python code stored in a string. This is a potential security hole of great dimensions. If you execute a string where parts of the contents have been supplied by a user, you have little or no control over what code you are executing. This is especially dangerous in network applications, such as Common Gateway Interface (CGI) scripts. _

exec语句通常同来执行相应本质为python代码的表达式,在python 2中为表达式,python 3中则变为一个函数(方法)。

>>> exec "print 'Hello, world!' "
Hello, world!
>>> from math import sqrt
>>> exec "a = sqrt(4)"
>>> a
2.0

因为exec语句中可能存在潜在干扰正常程序的代码(参考资料1 109页),因此将exec语句放在数据字典中执行是一种可能的规避风险的方式。

>>> from math import sqrt
>>> scope = {}
>>> exec 'sqrt = 1' in scope
>>> sqrt(4)
2.0
>>> scope['sqrt']
1

此处,由于将sqrt表示的语句放在了数据字典scope中执行,因此sqrt对于库函数math.sqrt的正常使用没有造成干扰。

eval表达式则用于对字符串进行估值,与exec不同,eval会返回经过计算的python表达式。

>>> eval(raw_input("Enter an arithmetic expression: "))
Enter an arithmetic expression: 6 + 18 * 2
42

此外,eval和exec可相互交叉作用,用于对命名空间(namespace)中的语句进行估值。

>>> scope = {}
>>> exec 'x = 2' in scope
>>> exec 'y = 3' in scope
>>> eval('x * y', scope)
6
G、将数值转化为单个字符的chr函数和将数字转化为字符的ord函数:
>>> a = 15
>>> chr(a)
'\x0f'
>>> ord('A')
65

三、Python字符串:

Python中的单行字符串可用''符号或""符号。此外,由于python是讲究格式对齐的编程语言,多行字符串需要被包括在""" """符号之间,此符号亦可用来注释多行代码。(python中注释单行代码的是#符号。)

str()和repr()都是将Python表达式转为Python字符的方式。由于在Python 3中,使用双斜点的方式已经被废除,因此repr是推荐的方式。

Python使用 \ 既可用作显示字符串中的标点符号,也可以表示代码换行。string模块有一些常量,可以通过import string进行使用。详情见参考资料1第60页。

Python生字符串前必须有小写字母r。代码举例:

print r'Let\'s go!'
print r'C:\Program Files\foo\bar' '\\'

Python中,格式化字符串(format string)的方式与其他编程语言大致相同,使用百分符号,例如:

>>> format = "Hello, %s. %s enough for ya?"
>>> values = ('world', 'Hot')
>>> print format % values
Hello, world. Hot enough for ya?
>>> format = "Pi with three decimals: %.3f"
>>> from math import pi
>>> print format % pi
Pi with three decimals: 3.142

>>> '%+10.2f' % pi    # "-"号有特殊意义,表示左对齐,此处效果就不是这样了。  
'     +3.14'
>>> '%010.2f' % pi 
'0000003.14'

>>> '%s plus %s equals %s' % (1, 1, 2)
'1 plus 1 equals 2'

其中,%符号(conversion specifiers,中文译名转换说明符)后面的值如果有多个,这多个值需要放入元组或数据字典中。如果需要在格式化的字符串中输出百分符号,需要连打%%。如果元组出现在转换说明符之后,则该元素需要加上括号,否则容易导致编译错误。

除此之外,Python提供模版型字符串用来格式化字符串,使用方式举例如下。在模版型字符串格式化中,对于输出美元符号$来说,情形类似%符号,需要连打。除非使用safe_substitute函数。

>>> from string import Template
>>> s = Template('$x, glorious $x!')
>>> s.substitute(x='slurm')
'slurm, glorious slurm!'

>>> s = Template("It's ${x}tastic!") #使用{}符号界定了字符串开始和结束的位置
>>> s.substitute(x='slurm')
"It's slurmtastic!"

>>> s = Template('A $thing must never $action.')
>>> d = {}
>>> d['thing'] = 'gentleman'
>>> d['action'] = 'show his socks'
>>> s.substitute(d)
'A gentleman must never show his socks.'

数据字典也可以参与字符串格式化,其效果与Template有类似之处。在%与种类之间加入括号,并在括号中标明键值,输出即可为对应的真值。举例如下:(关于什么是数据字典,本文后面部分会详细展开)

>>> phonebook = {'Beth': '9102', 'Alice': '2341', 'Cecil': '3258'}
>>> "Cecil's phone number is %(Cecil)s." % phonebook
"Cecil's phone number is 3258."
>>> template = '''<html>
<head><title>%(title)s</title></head>
<body>
<h1>%(title)s</h1>
<p>%(text)s</p>
</body>'''
>>> data = {'title': 'My Home Page', 'text': 'Welcome to my home page!'}
>>> print(template % data)
<html>
<head><title>My Home Page</title></head>
<body>
<h1>My Home Page</h1>
<p>Welcome to my home page!</p>
</body>

Python字符串还可使用星号控制读入格式化字符的长度,例如:

>>> '%.*s' % (5, 'Guido van Rossum')
'Guido'

其他Python字符串常见方法:

  1. find函数:find(ele, [start], [end]):从起始下标(可选)到终止下标(可选)找ele元素第一次出现的位置并返回。若没有找到,返回-1。类似方法:rfind, index, rindex, count, startswith, endswith。注意index和find的区别是index找不到时抛出异常,find函数找不到元素时返回-1。
  2. join函数:与split函数相反,用于拼接字符串。类似方法:rsplit, splitlines(返回所有行的列表,可以指定换行符为可选参数).
  3. lower函数:返回用小写字母写的字符串。类似方法:islower, capitalize, swapcase, title, istitle, upper, isupper, title, capwords (跟title函数用法一样)
  4. replace, expandtabs(用空格替代tab,可以指定空格数量,默认为8), maketrans 和 translate的组合使用(需要from string import maketrans)
  5. strip(从开头和结尾处出去相应字符)。类似方法:lstrip(从开头处除去), rstrip(从结尾处除去)

常见方法使用示例:

>>> dirs = '', 'usr', 'bin', 'env'
>>> '/'.join(dirs)
'/usr/bin/env'
>>> print 'C:' + '\\'.join(dirs)
C:\usr\bin\env
>>> 'This is a test'.replace('is', 'eez')
'Theez eez a test'

strip函数裁剪字符串左右双侧的特定字符。

'*** SPAM * for * everyone!!! ***'.strip(' *!')
'SPAM * for * everyone'
>>> from string import maketrans
>>> table = maketrans('cs', 'kz')
>>> a = "this is an incredible test"
>>> b = a.translate(table)
>>> b
'thiz iz an inkredible tezt'
 “”“可选的参数为需要去掉的符号。
如此处模拟快速讲德语可以去掉空格。“”“
>>> c = a.translate(table, ' ')
>>> c
'thizizaninkredibletezt'

四、Python基本数据结构总览:

Python容器(container)分为两大类,一类为列表,还有一类为映射(mapping)。一种数据结构中理论上可包含另一种或同种结构,示例如下:

>>> edward = ['Edward Gumby', 42]
>>> john = ['John Smith', 50]
>>> database = [edward, john]
>>> database

[['Edward Gumby', 42], ['John Smith', 50]]

Python的六个内置序列型数据结构:

列表(list)、元组(tuple)、字符串、Unicode字符串、缓冲对象(buffer objects)和范围(xrange)。其中,元组具有不可修改性

对于Python的序列型数据结构(sequence types),可进行的操作包括查下标(indexing)、分片(slicing)、相加(adding)、乘法(multiplying)、确定相互关系、求长度、查找最大最小元素和迭代。

Python分片示例:

>>> tag = '<a href="http://www.python.org">Python web site</a>'
>>> tag[9:30]
'http://www.python.org'
>>> tag[32:-4]
'Python web site'

>>> numbers[0:10:2] #最后一个数字为所需取的序列步长
[1, 3, 5, 7, 9]

>>> numbers[-3:] #取numbers数组的最后三个元素,注意不能是[-3:0]。否则将会取得空序列。
[8, 9, 10]

Python中取得域名的方法:

# Split up a URL of the form http://www.something.com
url = raw_input('Please enter the URL: ')
domain = url[11:-4]  #第11项包括,倒数第4项不包括
print "Domain name: " + domain

Python使用相乘初始化序列示例:

>>> sequence = [None] * 10

Python确定关系关键词(in),示例:

>>> subject = '$$$ Get rich now!!! $$$'
>>> '$$$' in subject
True

Python中计算长度(len方法)、查找最大(max方法)最小元素(min方法)示例

>>> numbers = [100, 34, 678]
>>> len(numbers)
3
>>> max(numbers)
678
>>> min(numbers)
34

五、Python列表与元组

Python中,通过list函数,可以将非列表元素转化为列表元素。例如:

>>> list('Hello')
['H', 'e', 'l', 'l', 'o']

通过 ''.join(somelist)的方式(‘’为无空格单字符),可以将列表转化为字符串。

Python列表除了在三中提到的各种操作之外, 还包含了修改元素、删除元素、分片赋值以及一些列表方法的操作。

常用list方法: del, append, count(可操作单个或列表元素) extend, reverse, reversed, sort, sorted(只可操作列表元素),
index, insert, pop, remove, random.choice(p.g.159, Ref 1)(只可操作单个元素)。

部分列表方法示例:

del方法示例:

>>> names = ['Alice', 'Beth', 'Cecil', 'Dee-Dee', 'Earl']
>>> del names[2]
>>> names
['Alice', 'Beth', 'Dee-Dee', 'Earl']
{'age': 42, 'first name': 'Robin', 'last name': 'of Locksley'}
>>> robin
{'age': 42, 'first name': 'Robin', 'last name': 'of Locksley'}
>>> scoundrel = None
>>> robin
{'age': 42, 'first name': 'Robin', 'last name': 'of Locksley'}
>>> robin = None

其中,del方法还能够用来删除字典元素。注意,python中若将对象赋值给None,变量名并未删除,对象数据被交给了垃圾回收机制。然而若是使用del方法,则对象的变量名被删除,其值则不一定。对象的值仍然存在于此对象的拷贝对象中或者被python垃圾回收机制回收。详见参考资料1第108页。

>>> scoundrel = {'age': 42, 'first name': 'Robin', 'last name': 'of Locksley'}
>>> robin = scoundrel
>>> scoundrel
{'age': 42, 'first name': 'Robin', 'last name': 'of Locksley'}
>>> robin
{'age': 42, 'first name': 'Robin', 'last name': 'of Locksley'}
>>> scoundrel = None
>>> robin
{'age': 42, 'first name': 'Robin', 'last name': 'of Locksley'}
>>> robin = None
>>> robin
>>> 

分片赋值操作示例:

>>> name = list('Perl')
>>> name[1:] = list('ython')
>>> name
['P', 'y', 't', 'h', 'o', 'n']
>>> numbers = [1, 5]
>>> numbers[1:1] = [2, 3, 4] #用列表[2, 3, 4]取代了空分片[1:1]达到插入效果
>>> numbers
[1, 2, 3, 4, 5]
>>> numbers
[1, 2, 3, 4, 5]
>>> numbers[1:4] = []   #将有代码的分片赋值给空列表,达到删除的效果
#与此操作效果相同:del numbers[1:4]
>>> numbers
[1, 5]
>>> a = [1, 2, 3]
>>> b = [4, 5, 6]
>>> a.extend(b)   #效率比 a = a + b更高,此处a, b均为列表
>>> a
[1, 2, 3, 4, 5, 6]
>>> knights = ['We', 'are', 'the', 'knights', 'who', 'say', 'ni']
>>> knights.index('who')
4
>>> numbers = [1, 2, 3, 5, 6, 7]
>>> numbers.insert(3, 'four')
>>> numbers
[1, 2, 3, 'four', 5, 6, 7]
>>> x = [1, 2, 3]
>>> x.pop()
3
>>> x
[1, 2]
>>> x.pop(0)
1
>>> x         #pop方法是列表方法中唯一既修改列表,又返回值的方法。
[2]

备注:pop方法可与append方法结合构造stack,与insert方法结合构造queue

>>> x = ['to', 'be', 'or', 'not', 'to', 'be']
>>> x.remove('be')
>>> x
['to', 'or', 'not', 'to', 'be']
>>> x = [1, 2, 3]
>>> x.reverse() #sort用法类似   

注意,reversed不返回一个数组,而只是返回了迭代。具体用法如下:

>>> x = [1, 2, 3]
>>> list(reversed(x))
[3, 2, 1]
>>> x = [4, 6, 2, 1, 7, 9]
>>> y = sorted(x)   
#sort仅仅对当前列表操作,不返回任何值。而sorted与reversed类似,事实上仅仅是返回了迭代。(详见参考资料1 102页)
>>> x
[4, 6, 2, 1, 7, 9]
>>> y
[1, 2, 4, 6, 7, 9]

特殊的排序方法示例: Python中的默认排序的顺序是非递减。如果要改变默认排序顺序,需要重写函数compare(x, y)。cmp函数是显示默认排序标准的函数。

>>> cmp(42, 32)
1
>>> cmp(99, 100)
-1
>>> cmp(10, 10)
0
>>> numbers = [5, 2, 9, 7]
>>> numbers.sort(cmp)
>>> numbers
[2, 5, 7, 9]

>>> x = [4, 6, 2, 1, 7, 9]
>>> x.sort(reverse=True)
>>> x
[9, 7, 6, 4, 2, 1]
>>> x = ['aardvark', 'abalone', 'acme', 'add', 'aerate']
>>> x.sort(key=len)
>>> x
['add', 'acme', 'aerate', 'abalone', 'aardvark']

Python元组是一种与列表不同的结构,它的元素不可新修改。可通过用逗号把数值隔开而获得,或者在值串的前后加上括号。

>>> 1, 2, 3
(1, 2, 3)
>>> (1, 2, 3)
(1, 2, 3)

单个值的元组,必须在元组元素后面加上逗号,否则会导致歧义。例如:

>>> 3*(40+2)
126
>>> 3*(40+2,)
(42, 42, 42)

通过tuple()函数,可将非元组元素变为元组元素。如果原来已经是元组,则不变。

>>> tuple([1, 2, 3])
(1, 2, 3)
>>> tuple('abc')
('a', 'b', 'c')
>>> tuple((1, 2, 3))
(1, 2, 3)

元组中的元素可进行分片操作,例如:

>>> x = 1, 2, 3
>>> x[1]
2
>>> y = x[0:2]
>>> y
(1, 2)

六、Python数据字典

根据键值(key,可以是数字、字符或元组等不可变类型)能够找到对应真值(value),且键值的顺序不固定的数据结构叫做映射(mapping)。Python中唯一符合映射条件的数据结构为数据字典。注意,数据字典的键值只能是唯一的,然而真值可以不唯一。因为采用的机构是映射,因此在数据字典中找键的速度要快于在列表中线性查找元素的速度。(哈希表找键值的时间复杂度为O(1))

使用dict函数可以将其他数据结构转化为数据字典。注意,dict和tuple, list, str等一样,事实上不是函数,而只是一种类型。

数据字典建立示例:

>>> phonebook = {'Alice': '2341', 'Beth': '9102', 'Cecil': '3258'}

>>> items = [('name', 'Gumby'), ('age', 42)]
>>> d = dict(items)
>>> d
{'age': 42, 'name': 'Gumby'}
>>> d['name']
'Gumby'

>>> d = dict(name='Gumby', age=42)
>>> d
{'age': 42, 'name': 'Gumby'}

数据字典的建立还可以使用fromkeys的方式,这针对于一个列表中全部是键值需要建立字典的情形,可以与dict方法结合使用:

>>> {}.fromkeys(['name', 'age'])
{'age': None, 'name': None}
>>> dict.fromkeys(['name', 'age'])
{'age': None, 'name': None}
>>> dict.fromkeys(['name', 'age'], '(unknown)')
{'age': '(unknown)', 'name': '(unknown)'}

数据字典有以下常用操作:

  • len(d) returns the number of items (key-value pairs) in d.
  • d[k] returns the value associated with the key k.
  • d[k] = v associates the value v with the key k.
  • del d[k] deletes the item with key k.
  • k in d checks whether there is an item in d that has the key k. (注意,此处说明in方法在字典中是用来判断键值是否存在的)

数据字典常用方法:

  1. d.clear():为对数据字典地址进行清除的函数。调用时会清除所有指向该地址的变量。
  2. d.copy():返回对于该数据字典的浅复制,浅复制的意思是当“复制品”中的基本数值被改变时,原字典数值不影响。然而对字典所在位置调用地址方法(如d[k].remove(val)时),字典就会收到影响。若需要复制一个字典的值以及地址,需要用语句from copy import deepcopy导入deepcopy模块,然后调用d.deepcopy()方法进行复制。
  3. d.get(key, [default_not_found_value]),若在字典中存在key,返回key对应的真值。否则,返回None。如果规定了找不到真值时的返回值default_not_found_value(比如N/A),则返回用户规定的值。其对应的一个类似方法是d.setdefault(key, [default_add_in_value])。该方法若字典d中存在k,则返回对应真值并且不对字典进行修改,否则插入default_add_in_value,未选择该可选参数时设定真值为None。
  4. items(d)和iteritems(d):都是以不定顺序返回数据字典的所有键值对。区别是items返回列表形式,而iteritems返回迭代形式,被返回的迭代需要作为list()方法的参数才能被转化为列表。但是,iteritems的迭代效率高于items。类似的方法:d.keys()和d.iterkeys(),d.values()和d.itervalues()。
  5. d.pop(k)和d.popitem():从字典中删除一个键值,并返回该键值对应的真值。其中,popitem对于键值的删除是任意的。
  6. d1.update(d2):将字典d2添加进d1。若两字典含有键值相同的元素,则d1中对应元素的真值被替换为d2中该键值对应的真值。此处,d2可以不局限于数据字典,可以是任何形式的键-值对或对应的变量。

数据字典常用方法示例:

调用clear方法对数据字典内存地址进行清除示例:

>>> x = {}
>>> y = x
>>> x['key'] = 'value'
>>> y
{'key': 'value'}
>>> x = {}
>>> y
{'key': 'value'}

>>> x = {}
>>> y = x
>>> x['key'] = 'value'
>>> y
{'key': 'value'}
>>> x.clear()
>>> y
{}

如果上例中,想要clear x字典而不影响y字典,可以采用以下办法:

>>> x = {'username': 'admin', 'machines': ['foo', 'bar', 'baz']}
>>> y = x.copy()
>>> y
{'username': 'admin', 'machines': ['foo', 'bar', 'baz']}
>>> x.clear()
>>> y
{'username': 'admin', 'machines': ['foo', 'bar', 'baz']}
>>> x = {'username': 'admin', 'machines': ['foo', 'bar', 'baz']}
>>> y = x.copy()
>>> y['username'] = 'mlh'
>>> y['machines'].remove('bar')
>>> y
{'username': 'mlh', 'machines': ['foo', 'baz']}
>>> x
{'username': 'admin', 'machines': ['foo', 'baz']}  

 “”“” 'username'对应的值仍为'admin',没有被修改过。
然而machines[bar]这个元素被成功remove。 ”“”

另外,若上述例子中调用del删除一整个键值,备份中的键值和真值不受影响:

>>> del y['machines']
>>> y
{'username': 'admin'}
>>> x
{'username': 'admin', 'machines': ['foo', 'bar', 'baz']}
>>> d = {'title': 'Python Web Site', 'url': 'http://www.python.org', 'spam': 0}
>>> d.items()
[('url', 'http://www.python.org'), ('spam', 0), ('title', 'Python Web Site')]

>>> it = d.iteritems()
>>> it
<dictionary-iterator object at 169050>
>>> list(it) # Convert the iterator to a list
[('url', 'http://www.python.org'), ('spam', 0), ('title', 'Python Web Site')]

七、Python方法:

Python中,使用def关键字定义一个模块为python函数。在def关键字之后的表示方法名称的名词叫做方法头(formal parameters),方法头后面括号中的参数叫做传入参数(actual parameters或arguments或values)例如,一个计算并返回n个斐波那契数的方法如下:

# -*- coding: cp936 -*-
def fibs(num):    
    result = [0, 1]
    for i in range(num-2):
        result.append(result[-2] + result[-1])
    return result

#计算并输出10个斐波那契数:
print fibs(10)

其中,在def声明(或class声明)一行之后加一个字符串(可以是引号表示的单行或三引号表示的多行)则表示为此模块添加说明(documentation)。可以采用f.__doc__或help(f)的方法查看此模块的编制说明(f为需要查看的方法、类等特定模块)。

当分支语句与函数一起使用时,各分支的情况都需要考虑,以防函数返回None值。

与其他高级语言类似,python的基本数据类型在方法中一般是值传递的,而内置类型或对象一般是地址传递的。Python也支持传入默认函数,规则与一般高级语言类似。

此外,Python还支持不定数量的参数以及赋值表达式作为参数传入方法。传入不定数量参数时,这不定数量个参数(可以是0个)被作为元组处理(传入参数前加*号)。传入赋值表达式时,被作为数据字典处理(传入参数前加**号)。(详见参考资料1 第125-127页):

例如,print_parameters这个参数就展示了默认函数、列表参数和字典参数的传入和使用方式:

>>> def print_parameters(num1, num2, num3 = 3, * paras, **dicts):
	print num1, num2, num3
	print paras
	print dicts

>>> print_parameters(1, 2, 3, 4, 5, 6, 7, foo = 1, bar = 2)
1 2 3
(4, 5, 6, 7)
{'foo': 1, 'bar': 2}
>>> print_parameters(1, 2)
1 2 3
()
{}
>>> 

在向方法传递的过程中,若加上*或**符号,可自动生成相应传入列表,而不需要对原元组或数据字典进行解包。关于传入参数的快速入门示例,详见参考资料1 129-130页:

>>> def add(x, y): return x + y

>>> params = (1, 2)
>>> add(*params)
3

函数中,当本地变量与全局变量重名时,可以通过global()[para]的方法调用变量名为para的全局变量,举例如下(详见参考资料1 132页):

>>> def combine(parameter):
	print parameter + globals()['parameter']

>>> parameter = 'berry'
>>> combine('Straw')
Strawberry

Python还支持方法的嵌套使用(或称作用域嵌套)和递归。其中,方法的嵌套使用举例如下(参考资料1 133页):

>>> def multiplier(factor):
            def multiplyByFact(num):
		return num * factor
            return multiplyByFact

>>> double = multiplier(2)
>>> double(5)
10
>>> multiplier(5)(4)
20

Python中,还可使用map(f, seq)可以通过f函数处理seq序列,也可使用filter(f, seq)函数根据f函数的情况运行seq序列。在python 3中,它们都在functools模块。也可以通过lambda函数与它们的结合解决一些数值问题。(举例详见参考资料1 第138页)然而,列表推导式仍然是应对此类问题的更佳方案。

>>> numbers = [72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33]
>>> reduce(lambda x, y: x+y, numbers)
1161

备注:此处也可以调用operator模块的add函数。

八、Python类基本知识笔记:

_Python语言是面向对象编程语言之一,因此它与其他语言一样,支持对象的继承、多态、封装这样的面向对象编程的基本特征。 _

Python类Person创建以及使用案例(148 - 150页):

__metaclass__ = type # Make sure we get new style classes
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

Python语言中的类有新样式类和旧样式类之分。其中,在文件开头加上__metaclass__ = type 或类继承object的类均为新类,否则为旧类。在python 3中,不存在旧样式类。(参考资料1 175页)

注意,self关键字用在python的类书写中,特指类指代的对象本身,作用是将此类的变量以及类方法与普通的变量和方法区别开来。

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

此例中,由于members并不是self关键字修饰的变量,因此它的存储是与对象分开的,类似于C++中static关键字变量处理的方法。但是,若此类中的变量被认为修改之后,则变为本地变量。举例如下:

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

对于Person类的调用示例:

>>> foo = Person()
>>> bar = Person()
>>> foo.setName('Luke Skywalker')
>>> bar.setName('Anakin Skywalker')
>>> foo.greet()
Hello, world! I'm Luke Skywalker.
>>> bar.greet()
Hello, world! I'm Anakin Skywalker.
#If I already know foo is an instance of Person.
>>> Person.greet(foo)
Hello, world! I'm Luke Skywalker.

Python也支持对类通过使用构造函数的方式进行初始化。构造函数为写在类中的__init__方法,举例如下:

class FooBar:
def __init__(self, value=42):
self.somevar = value

>>> f = FooBar('This is a constructor argument')
>>> f.somevar
'This is a constructor argument'

Python中也可使用__del__函数作为destructor,然而一般情况下这个析构函数并没有什么卵用。

Python类中的变量封装只是形式上的(因为python代码是开源的)。对于变量有三种封装层次,以下列Person类为例:

class Secretive:
    _name = "SY"

    def __inaccessible(self):
        print "Bet you can't see me..."

    def accessible(self):
        print "The secret message is: "
        self.__inaccessible()

    def setName(self, name):
        self._name = name

    def getName(self):
        return self._name

>>> s = Secretive()
>>> s.getName()
'SY'
>>> s.name
报错
>>> s.setName("John")
>>> s.getName()
'John'
>>> s.__inaccessible()
报错
>>> s._Secretive__inaccessible()
Bet you can't see me...
>>> s._Secretive_name
报错

由此可见,python封装的级别通过下划线确定。其中,单下划线表示类内的私有变量,(理论上)无法被调用(形式上仍然可以通过s._name进行调用)。双下划线不能通过调用类名直接获得,而要通过调用单下划线加类名和方法名(变量名)的方法获得。

Python语言支持继承机制以及多继承,格式如:

class subClass(superClass1, superClass2...):

关于Python语言的继承机制,详细请参考参考资料1 153 - 156页。其中,有几个与继承机制有关的方法和定值值得参考:

  1. issublclass(Subclass, Superclass)方法可以用来确定Subclass(是类名,而不是类对应的变量名)是否是Superclass(是类名,而不是类对应的变量名)的子类。
  2. Subclass.__bases__可以用来查看子类的(一个或多个)父类信息。
  3. isinstance(obj, Class)方法可以用来确定obj是否是class的一个对象。
  4. obj.class__变量可以用来获得对象obj的类的信息,注意,若类中含有__metaclass = type这样表示这是一个新类以及其子类,都可以使用type(obj)来获得对象obj的类的信息。
  5. hasattr(obj, func):检查对象obj对应的类中是否有方法(或变量)func。在python 3.0中,hasattr(x, 'call')可以用来代替callable(x)函数(使用方式见参考资料1第156页)。
  6. getattr(obj, func, defalt_if_not_exist): 得到obj中func(用字符串表示方法名)有关信息。若不能返回,则指定特定返回值default_if_not_exist(如None)。这个方法往往在callable(x)中作为x的部分。 7.setattr(obj, func, value):将对象中的func变量(方法或值,包括在字符串中)设置成value值。 8.Class.dict:用于查看一个类有关的详细信息。

Python中的继承与其他高级语言有所不同,使用的是协议机制,即不要求对象一定要继承父类的全部或部分特点,而是对象要遵守以下可选的一个或几个协议。具体的一些python协议如下:

引用自参考资料1第182页 len(self): 返回集合中对象的数量 getitem(self, key): 返回通过key取得的值 setitem(self, key, value): 修改对象的值(用于可更改对象) delitem(self, key): 删除相应对象(用于可更改对象)

如:

class CounterList(list):
    def __init__(self, *args):
        super(CounterList, self).__init__(*args)
        self.counter = 0
        
    def __getitem__(self, index):
        self.counter += 1
        return super(CounterList, self).__getitem__(index)

可以这样调用:

>>> cl = CounterList(range(10))
>>> cl
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> cl.reverse()
>>> cl
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>> del cl[3:6]
>>> cl
[9, 8, 7, 3, 2, 1, 0]
>>> cl.counter
0
>>> cl[4] + cl[2]
9
>>> cl.counter
2

在python继承机制中,子类的初始化必须通过一定手段调用父类,否则可能出现问题。以SongBird类继承Bird类为例,调用方式有两种:

  1. 在子类中调用父类的构造函数:
class SongBird(Bird):
    def __init__(self):
        Bird.__init__(self)
        self.sound = 'Squawk!'

    def sing(self):
        print self.sound
  1. 使用super()函数:
class SongBird(Bird):
    def __init__(self):
        super(SongBird, self).__init__()
        self.sound = 'Squawk!'
    def sing(self):
        print self.sound

总结:

本文从python语言的基本运算规则出发,接着讲了python的控制语句的使用方法,梳理了python语句中的分支、循环以及一些特殊的控制语句。接着本文梳理介绍了把这些控制语句用于python数据结构的简要学习和处理当中,着重讨论了python中两种最重要最基本的数据结构列表和字典。在对于基本控制语句和基本数据机构有所了解之后,本文探讨了在python中使用方法(函数)以实现模块化和过程化编程的一些常用方式方法。本文以对于python语言面向对象机制的初步探讨作为结尾。

任何面向对象编程语言的基本知识学习初级阶段路线也可以按照类似方法循序渐进地进行,以便于顺利完成对于该编程语言的入门。然而对于任何一门编程语言来说,学习的过程可以是永无止境的,入门仅仅只是小小的冰山一角。在一门编程语言的进阶篇学习阶段,深入了解这些基本知识在其他方面如文件传输和用户界面编程方面的使用也是同样至关重要和精彩纷呈的。进入高级阶段之后,程序员们更要“跟上时代的步伐”,深入挖掘该语言在网络计算、数据处理乃至并行和系统处理、大数据计算和科学计算等各方面最新的应用情况。对于编程语言界正冉冉升起的新星python来说情况更是如此。希望本文能真正帮助IT界的同行们以及python的学习者们迅速扎实地掌握python编程的要点,走好python编程的“入门级”。

参考资料:

  1. Magnus Lie Hetland, Beginning Python, From Novice to Professional, Second Edition, in Apress。群主新年善心大发,居然上传了可以0代价下载的原书英文版哦!地址:http://download.csdn.net/detail/samyjy/9744964
  2. Robert Sedgewick, Kevin Wayne 以及Robert Dondero,普林斯顿大学Python程序设计导论,URL:http://introcs.cs.princeton.edu/python/home/
  3. 有关Python pow函数的使用:URL:https://zhidao.baidu.com/question/571409325.html

转载于:https://my.oschina.net/Samyan/blog/830810

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值