《Python核心编程》读书笔记(二)

条件和循环

>>> smaller = x if x < y else y

使用映射对象(eg 字典)最大的好处:搜索操作比if-elif-else语类/for循环这样的序列查找快很多

for:

for循环:访问一个可迭代对象中的所有元素,并在所有条目都处理后结束循环
当迭代字符串时:迭代变量只会包含一个字符(长度为1的字符串)

  1. 通过迭代项迭代:
>>>nameList = ['Walter', 'Nicole', 'Henry']
>>>for eachName in nameList:
    print eachName
  1. 通过序列索引迭代:
>>>for nameIndex in range(len(nameList)):
    print nameList[nameIndex]
  1. 通过项和索引迭代:
>>>for i,eachLee in enumerate(nameList):
    print "%d %s" % (i+1, eachLee)

pass:

不做任何事情—即NOP(No Operation)

>>>def func():
    pass

else:

在循环中使用时:else子句只在循环(while、for)完成后执行(break语句也会跳过else块)

迭代器:

根本上说,迭代器:有一个next() 方法的对象,而不是通过索引来计数。当条目全取出后,引发一StopIteration异常,不表示错误发生,只是告诉外部调用者,迭代完成。

>>>for i in seq:
    do_sth()

//实际上:
/*
fetch = iter(seq)
while True:
    try:
        i = fetch.next()
    except StopIteration:
        break
    do_sth()
*/

对于字典,迭代器遍历它的键(key):

myDict.iterkeys()          通过键迭代
myDict.itervalues()        。。值。。
myDict.iteritems()         。。键-值对。。

列表解析:

计算非空白字符的数目:

>>>f = open('hhga.txt','r')
>>>len([word for line in f for word in lin.split()])

计算文件大小:

>>>import os
>>>os.stat('hhga.txt').st_size

所有单词之和:

>>>f.seek()                #回到文件的开头
>>>sum([len(word) for line in f for word in line.split()])

生成器表达式:

列表解析:缺点:必须要生成所有的数据,用以创建整个列表。 若大量数据 —>生成器表达式

[expr for iter_var in iterable if cond_expr]

生成器表达式:

(expr for iter_var in iterable if cond_expr)
  1. 还可用于交叉配对样例:
>>>x_product_pairs = ((i, j) for i in rows for j in cols())
(1,56)
(1,...)
(1,...)
(2,56)
(2,...)
(2,...)
  1. 重构样例:
    eg:寻找文件最长的行:
f = open('/etc/motd','r')
longest = 0
while True:
    lineLne = len(f.readline().strip())
    if not lineLen:break
    if lineLen > longest:
        longest = lineLen
f.close()            #一直占用文件 ——>下一版本:
return longest
allLines = [x.strip() for x in f.readlines()]   #x.strip():存一行——>下一版本
f.close()
for line in allLines:
    lineLen = len(line)
    if lineLen > longest:
        longest = lineLen
return longest
allLineLens = [len(x.strip()) for x in f]        #len(x.strip())存长度
f.close()
return max(allLineLens)

列表解析——生成器表达式——>:

longest = max(len(x.strip()) for x in f)
f.close()
return longest

文件和输入输出

file_object = open(file_name, access_mode = ‘r’, buffering = -1) 失败返回IOError

             file_name与access_mode均为字符串

access_mode:
‘r’ ‘w’
‘a’ :追加模式,加至文件末尾(从EOF开始),无视seek到哪了,必要时创建新文件
‘U’:通用换行符支持
‘+’:可读可写

文件内建方法:

  1. 输入:

    read():直接读取字节到字符串中,最多读给定数目个字节。若未给出(默认-1),则读至末尾
    readline():读取打开文件的一行(读下个行结束符之前的所有字节)整行,包括行结束符,作为字符串返回
    有可迭代的size参数,默认-1,若有size,则最多读size个字节后返回不完整的行
    readlines():读取所有(剩余的)行,把它们作为一个字符串列表返回

  2. 输出

    write()
    writelines():针对列表的操作。
    行结束符不会被自动加入 —> 在调用前给每行结尾加上行结束符
    **无**writeline(),等价于write()一个以行结束符结尾的单行字符串

  3. 文件内移动:

    seek():在文件中移动文件指针到不同的位置
    offset:字节代表相对于某个位置(见下:)偏移量
    位置:默认为0(从文件开头算起)
    1:当前位置算起
    2:从文件末尾算起
    tell():告诉当前文件指针在文件中的位置——从文件起始算起,单位:字节

  4. 文件迭代:

 for eachLine in f:
 #eachLine 代表文本文件的一行(包括末尾的行结束符)(等效于调用f.readline())
     print eachLine,

注:
(1)因为readline()本身读取了文本中的换行符,print不加 , 的话,多输出了一个换行符
(2)
aLine = raw_input(‘…’)
f.write(‘%s.%s’ % (aLine, os.linesep)) #import os

flush():直接把内部缓冲区中的数据立刻写入文件,而不是被动等待输出缓冲区被写入
truncate():方法把文件截取到当前文件指针位置/到给定size,以字节为单位

文件内建属性:

数据属性:

file.closed:  表示文件已关闭,否则为False
file.mode:    文件打开时的访问模式
file.name:

标准文件:

只要程序一执行,预先打开了三个文件:

标准输入           
标准输出(缓冲输出)
标准错误(非缓冲输出)    #该缓冲指的是open()函数的第三个参数:

可通过sys模块访问这些文件:

sys.stdin, sys.stdout, sys.stderr

缓冲方式(buffering:)

0:不缓冲
1:只缓冲一行数据
>1:使用给定值作为缓冲区大小

错误和异常

-BaseException              所有错误的基类
 |-KeyboardInterrupt        ^c
 |-SystemExit               当前Python应用程序需要退出
 |-Exception                常规错误的基类
    |-AssertionError        断言语句失败
    |-EOFError              没有内建输入,到达EOF标记
    |-IOError               输入/出 操作失败
    |-IndexError            序列中无此索引
    |-KeyError              映射中没有这个键
    |-MemoryError           内存溢出错误
    |-SyntaxError           Python语法错误
    |-IndentationError      缩进错误
    |-TabError              Tab和空格混用

函数和函数式编程

对没返回值的函数,若保存返回值,则该值为None:

#eg:
>>>def hello():
    print 'hello world'
>>>res = hello()
hello world
>>>print res
None
>>>res
>>>type(res)
<type 'None'>

若函数返回多个对象,Python把它们聚集起来以一个元组返回:
eg:

return 'abc',[42, 'python'] / return ('abc',[...])   #元祖不必须带圆括号

默认参数:声明了默认值的参数(参数名 = 默认值)
给参数赋予了默认值 —> 在函数调用时,不向该参数传入值也是允许的
所有必需的参数必须都在默认参数之前关键字参数可以给不按顺序的未知参数提供参数,eg:

net_conn(stype = 'udp', host = 'solo')      #这两个参数前后顺序无所谓

函数属性:

bar.__doc__ = 在函数声明后第一个没有复制的字符串   #help(bar)也返回这个
func.__name__

传递函数:

>>>def foo():
    print 'in foo()'
>>>bar = foo                #foo:函数对象的引用
>>>bar()                    #foo():函数对象的调用
in foo()
>>>def bar(argument):
    argument()
>>>bar(foo)                 #把函数作为参数传入其它函数来进行调用
in foo()

可变长的参数:

  1. 非关键字可变长参数(元组):
def function_name([format_args,] *vargs_tuple):
    for each in vargs_tuple

*操作符之后的形参将作为元组传给函数 —> 所有形式参数:必先于非正式的参数之前出现
2. 关键字变量参数(字典)

在有不定数目的/额外集合的关键字时:参数被放一字典中,字典中键:参数名,值:相应的参数值

def function_name([formal_args,] [*vargst,] **vargsd):
    for eachKW in vargsd.keys():
        print '%s: %s' % (eachKW, vargsd[eachKW])

#调用:
>>>function_name(2, 3, *(6, 8), **{'foo':10, 'bar':12})

内建函数:
filter(func, seq)
调用func()(布尔函数),迭代遍历每个seq中的元素;返回一使func返回值为True的元素的序列
map(func, seq1[, seq2…])
将func()作用于给定序列的每个元素,并用一列表来提供返回值
reduce(func, seq[, init])
将二元函数作用于seq序列中的元素,每次携带一对(先前的结果以及下一个序列元素)
若初始值init给定,则第一个代入为init和第一个序列元素,而不是序列头两个元素

变量作用域
搜索标识符(变量):
当一函数执行时,所有在局部命名空间的名字都在局部作用域内(第一个被搜索的名称空间)
全局变量存在一个全局内建名称空间

func_closure
使用函数的func_closure属性来追踪自由变量
eg:如果f2() 使用了任何定义在f1() 作用域的变量 —> 非全局与非f2() 的局部域的:他们为自由变量,将会被f2.func_closure 追踪到:

w = x = y = z = 1
def f1():
    x = y = z =2
def f2():
    y = z = 3
    print "f2 closure:", [str(c) for c in f2.func_closure]  #打印的为x

变量作用域和名称空间:
任何时候,总有1个/2个 活动的作用域: 全局作用域 + (函数局部作用域)
任何时候,存在2个/3个活动的名称空间:

  • 函数内:局部作用域包围了局部名称空间
  • 检查全局作用域(全局和内建的名称空间)

生成器:
一个带yield语句的函数
生成器能暂停执行并返回一中间的结果,当生成器的next() 方法被调用时,他会准确从离开地方继续
当到达一真正的返回/ 函数结束无更多的值返回:抛出一StopIteration异常

def simpleGen():
    yield 1
    yield '2 -> punch'

#for循环自带next()调用,和对StopIteration的处理
for eachItem in simpleGen():
    print eachItem

加强生成器特性:
send():将值回送给生成器 ->yield语句必为一表达式

val = (yield count)       #count :next() 的返回值
    if val is not None:         #send(9)——> val 置为 9
        count = val 

模块

名称空间:

首先加载内建名称空间(由builtins模块中的名字构成) 随后加载执行模块的全局名称空间,若在执行期间调用了一函数,将创建第三个名称空间:局部名称空间

通过globals()(全局名称空间)、locals()(局部名称空间) 内建函数可判断一名字属于哪个名称空间:{字典} -> locals().keys()

 名称空间:纯粹意义上的名字和对象间的映射关系
 作用域:还指出了从用户代码的哪些物理位置可访问到这些名字

导入模块:

    1.
 >>>import longmodulename
 >>>short = longmodulename
 #把模块赋给一变量
 #这样可以用short.attribute来访问
>>>import ... as tk
>>>from ... import ... as tk
# 该...可以为名字-> 可以不用句点属性,即可访问模块标识符
# ...也可以为*:导入所有名字

  1. 一个模块植被加载一次,无论他被导入多少次

  2. 只从模块导入名字 —> 这些名字会成为局部名称空间的一部分
    并且对这些变量的改变只影响他的局部拷贝,而不是所导入模块的原始名称空间
    使用import + 完整的标识符名称:imptee.foo = 123

reload() :
重新导入一个已经导入的模块

>>>reload(module) #module必为模块本身,而不是'module'

会再次执行模块中的代码

模块搜索路径:
(1)启动Python命令行的PYTHONPATH环境变量
(2)

>>>sys.path     #需import sys
>>>sys.path.append('/home/...')
>>>sys.modules     #返回一字典,模块名为键,对应物理地址为值

面向对象编程

  1. 类与实例
class MyNewObject(bases):
    pass
myFirstObject = MyNewObject()
myFirstObject.x = 1         #实力属性,x不是类的属性,实例对象myFirstObject独有的属性
  1. 方法:
class ...:
    def printFoo(self):        #self:方法中第一个参数,必为self。self代表实例对象本身,不需
                               #自己传递,自动传入的
        ...

_ init _()方法:
Python创建实例后,在实例化过程中,自动调用该方法,调用类时,川井的任何参数都交给了该方法 —> 可以定义一些行为

def __init__(self, nm, ph):
    self.name = nm                #实例化时,self被实例名替换掉 eg: john.name
    self.phone = ph
  1. 创建子类:
    继承 —> 新的子类将保持已存在类的所有特性
class EmpAddrBook(AddrBock):               #子类声明中提到父类(即()内的内容)
    def __init__(self, nm, ph):
        AddrBook.__init__(self, nm, ph)   #显式传递self实例对象给基类的方法,
                                          #因为我们不是通过实例来调用它
  1. 类的属性

     -  dir(MyClass)                #返回对象的属性的一个名字列表
     MyClass.__dict__            #返回一字典:键为属性名,值为相应的属性对象的数据值
                 等同于vars(C)   若在此未找到 —> 在基类的字典中搜索,对类的修改只影响此类的字
                                 典,基类的__dict__不变
    

类的特殊属性:

     - C.__name__               返回类C的名字(字符串)
     - C.__doc__                  类C的文档字符串                    #不能被派生类继承
     - C.__bases__               类C的所有父类构成的元组
     - C.__module__            类C定义所在的模块                #‘__main__’
     - C.__class__                 实例C对应的类                       
     -              #<type 'type'>   ( <-- C.__class__)  !类与类型统一了,定义一类后,已创建一新类型!
     -              #‘C'             (<-- c.__class__)
  1. 绑定和方法调用:

    方法:只有在其所属的类拥有实例时,才能被调用

    • 拥有实例:被认为绑定的 —> 不需要传self
      • 但调用未绑定的方法时,必传self,通过父类调用(见下一“继承中的(2)”)

任何一方法,第一参数都是self

  1. 继承:
    (1)

    若类C父类为P,C中未定义__init__(),则C会继承P中的__init__()
    

    (2)
    super()

class C(P):
    def foo(self):
        super(C, self).foo()    #super()找到C的基类的方法,且传进了self,不需再自己写了
  1. 内建函数:
    issubclass():布尔函数,判断一个类(sub)是另一个类(sup)的子类(子孙类)
>>>issubclass(sub, sup)      #sup可为父类组成的元组

isinstance():布尔函数,判断一对象是否为另一个给定类的实例

isinstance(obj1, obj2)     #obj1为类obj2的实例 / obj2的子类的一个实例:返回True

hasattr():看一对象是否有一特定的属性

hasattr(myInst, 'foo')

getattr():取得对象的属性

getattr(myInst, 'bar', ['oops'])     #若无bar,则AttributeError,除非给了默认参数(opps)

setattr():赋值给对象的属性

setattr(myInst, 'bar', 'my attr')

delattr():从一对象中删除某属性

  1. 用特殊方法定制类:
    (1):
#想要实例化有输出 -> 实现repr()、str()
>>>rfm              #真正的字符串对象表示repr()
>>>print rfm        #print,使用str()
def __str__(self):
    return str(self.value)      

#改为:
return '%.2f' % self.value  / __repr__ = __str__
#则rfm与print rfm 均有输出了

(2):数值定制

def __add__(self, other):
    return self.__class__(self.hr + other.hr, self.min + other.min)

class Time(object):
    def __init__(self.hr, min):
        self.hr = hr
        self.min = min

>>>mon = Time(10, 30)
>>>tue = Time(11, 15)
>>>print mon + tue           #此 + 符号,则会采用我们定义的__add__函数执行

你可能感兴趣的:(类,读书笔记,python,python核心编程)