python核心编程第二版

第三章 python基础

模块结构布局

起始行
模块文档
模块倒入
变量定义
类定义
函数定义
主程序

main是放置测试代码的好地方

垃圾收集

python解释器会负责跟踪对象的引用计数,当引用计数为0时,垃圾收集器会负责释放内存。垃圾收集器也会负责清理那些虽然引用计数大于0,但也应该被销毁的对象

第四章 python对象

type()的返回值是对象,事实上,type类型是python所有类型的根,也是所有python标准类的元类


用户创建的类实例如果定义了nonzero(nonzero())或length(len())且值为0,那么它们的布尔值就是false

>>> class A(object):
    def __len__(ob):
        return 0
>>> a = A()
>>> bool(a)
False

int和str类型是不可改变的,所以python会缓存常用的int类型,当我们试图创建a,b两个值为1的对象时,其实对象并没有被创建,只是引用了已缓存的对象这时候a is b或者id(a)==id(b)的值都是True

第五章 数字

所谓工厂函数是指:这些内建函数都是类对象,当你调用它们时,实际上是创建了一个类实例

第六章 序列:字符串,列表和元组

切片操作:第三个参数是步长,list1[::-1] 视为翻转操作

python默认所有的编码都是ASCII,可以通过在字符串前面加u前缀的方式声明inicode字符串。如果一个unicode字符串被当做参数传给str()函数,那么这个unicode会先被转换成ASCII字符串再交给str()函数,如果该unicode字符串中有不被ASCII支持的字符,会导致异常。而新的内建函数unicode()和unichar()可以看做unicode版本的str()和char(),它们会把python的任何数据类型转换为一个unicode字符串。

unicode和utf-8关系:unicode每个字符要占用两个字节,utf-8是为解决unicode占用空间较大的一种编码方式,utf-8变长编码的,当字符在ASCII码的范围时,就用一个字节表示,保留了ASCII字符一个字节的编码做为它的一部分,注意的是unicode一个中文字符占2个字节,而UTF-8一个中文字符占3个字节)。从unicode到uft-8并不是直接的对应,而是要过一些算法和规则来转换 (https://www.zhihu.com/question/23374078)

unicode字符串处理原则
程序中出现字符串时在前面加u
不要使用str()函数,使用unicode()
不到必要时不使用encode和decode,除非在读写文件或数据库时
pickle模块对unicode的支持很差
当使用%s时,会把字符串中的unicode对象执行str(默认编码)
举例

>>> u'%s %s' %(u'a', 'a')
u'a a'

>>> a = u'%s' %('哈哈'.decode('gbk'))
>>> a
u'\u54c8\u54c8'
>>> print a
哈哈

>>> u'哈哈'
u'\xb9\xfe\xb9\xfe'      # gbk编码
>>> '哈哈'
'\xb9\xfe\xb9\xfe'
>>> '哈哈'.decode('gbk')
u'\u54c8\u54c8'          # unicode编码

对list使用 + 会新建一个list,而extend()方法是把新列表加到了原有列表里面

浅拷贝和深拷贝

浅拷贝只是拷贝了对象的引用
实现:
(1)切片 [:]  
(2)工厂函数  list()  dict()
(3)copy.copy()

深拷贝
copy.deepcopy()

第八章 条件和循环

条件表达式(三元操作符): x if y else z

迭代器

迭代器是一种支持next()操作的对象。它包含一组元素,当执行next()操作时,返回其中一个元素;当所有元素都被返回后,生成一个StopIteration异常。

生成器是一种迭代器,是一种特殊的函数,使用yield操作将函数构造成迭代器。普通的函数有一个入口,有一个返回值;当函数被调用时,从入口开始执行,结束时返回相应的返回值。生成器定义的函数,有多个入口和多个返回值;对生成器执行next()操作,进行生成器的入口开始执行代码,yield操作向调用者返回一个值,并将函数挂起;挂起时,函数执行的环境和参数被保存下来;对生成器执行另一个next()操作时,参数从挂起状态被重新调用,进入上次挂起的执行环境继续下面的操作,到下一个yield操作时重复上面的过程。


迭代器不能向后移动,不能回到开始,也不能复制  
reversed()函数会返回一个反序访问的迭代器,enumerate()也会返回一个迭代器

创建迭代器
list_a = [1,2,3]
i = iter(list_a)
i.next()

对字典创建迭代器
myDict.iterkeys()  myDict.itervalues()  myDict.iteritems()

对文件创建迭代器
f = open('file', 'r')
for eachline in f:    
    print eachline    # 这样会自动调用readline()方法

列表解析

在一定程度上,列表解析可以取代map()和lambda,而且效率更高

[x ** 2 for x in range(10) if x % 2]
[(x, y) for x in range(10) for y in range(10)]

生成器表达式

生成器表达式是列表解析的一个扩展,列表解析的一个不足是必须一次创建整个list。
生成器表达式的使用方法和列表解析很相似,但是并不真正创建list,而是返回一个生成器。

((x, y) for x in range(10) for y in range(10))

第十一章 函数和函数式编程

python中的过程就是函数,因为解释器会隐式的返回None。没有返回值的函数也会隐式返回None

函数式编程
lambda
a = lambda x, y:x + y

filter() 不管他,用列表解析吧
map() 不管他,用列表解析吧
reduce():取出序列的前两个数,返回结果,与第三个数做运算,以此类推
reduce((lambda:x, y:x + y),range(5))

第十二章 模块

名称空间

a.py  

www = 'abc'

def show():
    print www



b.py  

from a import www,show
www = '123'  # 这是不改变a的www的值的
show()

import a
a.www = '123'  # 这是改变a的www的值的
a.show()

这里所说的改变,指的是模块a的名称空间里www的值,不是a.py文件里www的值


init 里面的 all 指定 from a import * 时会导入的模块

绝对导入:必须使用sys.path中的路径
相对导入:from ..a import b
第一个据点标明是相对导入

from a import * 不会导入以 _ 开始的属性

PYTHONCASEOK环境变量指定不区分大小写的导入

当遇到循环导入的问题时,可以把其中一个导入写到函数的内部,解决导入失败的问题

第十三章 面向对象编程

self参数代表的是实例对象本身,类中的一般方法需要这个参数,而类中的静态方法或类方法不需要  

__init__ 方法类似于类构造器,在实例化的过程中,__init__ 方法会被调用  

dir(Myclass)返回对象属性的一个名字列表,而Myclass.__dict__返回的是一个字典。vars(Myclass)实现了Myclass.__dict__  

类的特殊属性  
Myclass.__name__  类名  
Myclass.__doc__  文档字符串  
Myclass.__bases__  其父类构成的元组  
Myclass.__dict__  类的属性  
Myclass.__module__  类所在的模块  
Myclass.__class__  实例对应的类


__new__方法在 __init__方法之前被调用,它比__init__更像一个构造器,暂时没用到  

__del__ 解构器,用它干嘛,不用  

在类属性中有静态变量的时候,实例会直接访问类的静态变量,在实例中改变这个静态变量的值,会影响到类属性,这个要小心  

静态方法,不需要传参数  
@staticmethod  
def foo():
    print 'a'  

类方法,传递cls作为参数  
@classmethod  
def foo(cls):
    print 'a'

实例方法,传递self作为参数  
def foo(self):
    print 'a'  

class C(P):
    def __init__(self):
        super(C, self).__init__() # 这样能调用C的父类的__init__  

使用__new__方法返回两位小数  
class RoundFloat(float):
    def __new__(cls, val):
        return super(RoundFloat, cls).__new__(cls, round(val, 2))

issubclass()  # 判断一个类是否是另一个类的子类
isinstance()  # 判断一个对象是否是给定类的实例

hasattr() getattr() setattr() delattr()  # *attr系列方法操作给出的对象和属性


13.13 用特殊方法定制类

简单定制
# coding:utf-8
class RoundFloatManual(object):
    '''
    保留两位小数
    上面的__new__ 实现保留两位小数的例子,因为继承自float,所以__str__等方法不需要自己去实现,少踩好多坑
    '''
    def __init__(self, val):
        assert isinstance(val, float), "value must be a float"  # 断言,判断输入是否为float类型
        self.value = round(val, 2)

    # a = RoundFloatManual(2.033),当你实现__str__方法后,print a 显示的是 str(self.value),否则显示的是实例对象
    def __str__(self):  
        return str(self.value)

    # a = RoundFloatManual(2.033),当你实现__repr__方法后,RoundFloatManual 显示的是 str(self.value),否则显示的是实例对象
    # __repr__ = __str__   这样写的另一个好处是,DRY
    __repr__ = __str__  

数值定制
# coding:utf-8

class Time60(object):
    '''
    操作时间, 精确到小时和分
    '''
    def __init__(self, hr, min):
        self.hr = hr
        self.min = min

    def __str__(self):
        return '%d:%d' %(self.hr, self.min)

    __repr__ = __str__


    def __add__(self, other):
        '''重载运算符 +'''
        # self.class 代表实例化的类,调用self.class与调用Time60()是一样的
        return self.__class__(self.hr + other.hr, self.min + other.min)

    def __iadd__(self, other):
        '''重载 += 运算符'''
        self.hr += other.hr
        self.min += other.min
        return self   # 重载 __i*__时必须返回self


私有化
__  双下划綫开始的属性,在运行时会将类名加到属性前,这更多的是防止同名冲突
_   单下划线开始的属性,来防止from a import *,这是基于作用域的,所以也适用于类


授权
getattr(my_class, "class_function")和my_class.class_function调用的都是 __getattr__方法。授权的关键就是覆盖__getattr__方法。__getattr__的工作方式是:当搜索一个属性时,先搜索局部字典,再搜索类名称空间,如果都没有搜索到,则调用__getattr__方法处理

新式类的高级特性
isinstance(obj, int)并没有进行严格的匹配,如果obj是一个给定类型的实例或其子类的实例,也会返回True。严格匹配使用is

__slots__属性,可以替代__dict__,使用__slots__时用户不能增加__slots__中不存在的属性,并且节约内存

__getattribute__,使用这个函数对类的属性做访问,先不管

property :更好的控制对实力属性的访问,没找到场景,略

元类和__metaclass__
元类用来定义某些类是如何创建的
在执行类定义时,解释器会去寻找类属性__metaclass__(还有其他步骤,略),将这个属性赋值给此类作为元类

元类是为程序员服务的,它可以强制程序员在定义类时做某些操作

# coding:utf-8
from time import ctime

# 一个类的定义过程,其实就是完成某些工作

print "start Metac"

class MetaC(type):
    def __init__(cls, name, bases, attrd):
        super(MetaC, cls).__init__(name, bases, attrd)
        print "create class %r at: %s" %(name, ctime())

print "\tClass Foo next"

class Foo(object):
    __metaclass__ = MetaC # 在定义类的时候,这里就执行了。__init__需要在实例化的时候才执行
    def __init__(self):
        print "instantiated class %r at:%s" %(self.__class__.__name__, ctime())

print "\tClass Foo instantiation next."
f = Foo()
print "\tDone"

第十四章 执行环境

call : 在类中实现call方法后,类实力就成为可调用的对象,调用的就是call

callable(a) :判断a是否可以通过函数操作符()调用

compile()  允许在运行时声称函数对象,然后通过eval() , exec()等执行

可求值表达式,和eval()一起使用
eval_code = compile('100 + 200', '', 'eval')
eval(eval_code)

单一可执行语句,和exec()一起使用
single_code = compile('print "hello"', '', 'single')
exec(single_code)

可执行语句组,通过exec()执行
exec_code = compile('''
for i in range(10):
    print i
''', '', 'exec')
exec(exec_code)

第十八章 多线程编程

进程:进程是程序的一次执行,每个进程都有自己的地址空间,内存等,操作系统管理这些进程,为这些进程公平的分配时间

线程:线程运行在一个进程中,共享运行环境,对于单CPU,每个线程也是被安排成执行一小会

对一些例子做的测试和注释

1.基本使用
# coding:utf-8

import threading
from time import sleep, ctime

loops = [4, 2]

def loop(nloop, nsec):
    print 'start loop', nloop, 'at:', ctime()
    sleep(nsec)
    print 'loop', nloop, 'done at:', ctime()

def main():
    print 'starting at:', ctime()
    threads = []
    nloops = range(len(loops))

    for i in nloops:
        t = threading.Thread(target=loop, args=(i, loops[i])) # target 函数入口
        threads.append(t)

    for i in nloops:
        threads[i].start()  # 开始线程执行

    for i in nloops:
        threads[i].join()  # 程序挂起,直到线程结束

    print 'all DONE at:', ctime()

if __name__ == '__main__':
    main()

2.传一个实例作为线程启动的时候执行
# coding:utf-8

import threading
from time import sleep, ctime

loops = [4, 2]


class ThreadFunc(object):
    def __init__(self, func, args, name=''):
        self.name = name
        self.func = func
        self.args = args

    def __call__(self):
        self.func(*self.args)

def loop(nloop, nsec):
    print 'start loop', nloop, 'at:', ctime()
    sleep(nsec)
    print 'loop', nloop, 'done at:', ctime()

def main():
    print 'starting at:', ctime()
    threads = []
    nloops = range(len(loops))    

    for i in nloops:
        t = threading.Thread(target=ThreadFunc(loop, (i, loops[i]), loop.__name__))
        threads.append(t)

    for i in nloops:
        threads[i].start()

    for i in nloops:
        threads[i].join()

    print 'all DONE at:', ctime()

if __name__ == '__main__':
    main()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值