Jul 4, 2011

Learning python 4ed, Aha moments

名字

Everything is an object.

Name: 名字。python中一切(除了名字外)都是对象。1,2,“Hello World!”,[],{1:2},类,实例,函数都是对象。是的,没错,1 也是一个对象;类和实例都是对象

名字可以理解为c指针,它的规则像c指针。名字不能理解为“C++的别名”。python没有 aliasing.

x = "Hello World"
系统要做三件事
创建一个str对象,保存"Hello World"
创建一个名字x(如果x名字还未存在)
把x指向对象

name 是没有类别的,是通用的。类别只跟对象有关系。对象除了保存内容外,还保存
  1. 类别
  2. 引用计数,如果计数为0,则对象被垃圾回收
Variable Vs Name
变量实际上就是名字,全局变量,局部变量都是名字,全局、局部是名字的可见范围

module: 只是包含许多名字的一个包,相当于命名空间
attribute: 包中的名字是这个包的attribute

Qualification: 找到名字的方法
mod.attr

import mod1
mod1.fun

赋值

assign an object to a name,是修改名字的引用
x = [1,2,3];
y = x; # x,y 指向同一个对象。也就是共享的引用,指两个引用指向同一个对象。
使用名字指向对象,可以修改对象
x[0] = 3;
y
[3, 2, 3]

== 比较对象内容
is 比较引用(更严格的相等)
但是注意:对于小整数和短字符串对象,python 缓存并重复使用
>>> x = "word"
>>> y = "word" # 同一个对象,因为短字符串对象被缓存并重复使用的
>>> x is y 
True
>>> x = (1,2)
>>> y = (1,2) # 另一个对象
>>> x is y
False
>>> x == y
True

因为赋值语法 x=... 总是修改x名字的引用,所以不能用它来修改x原先指向的对象。(python 有=操作符重载吗?)
并且注意 x=y,总是使 x,y 指向同一个对象,如果这不是预期的效果,可以使用拷贝代替赋值
• Slice expressions with empty limits (L[:]) copy sequences.
• The dictionary and set copy method (X.copy()) copies a dictionary or set.
• Some built-in functions, such as list, make copies (list(L)).
• The copy standard library module makes full copies.

function

def 是可以执行的代码
def 创建一个函数对象,并赋值给一个名字
lambda 创建一个函数对象,并作为返回结果
result 返回一个对象给 caller
yield 返回一个对象给 caller,同时记住了离开时的状态(以备再次继续)
global
nonlocal python3.0 新语法,enclosing def 中定义的名字。enclosing function 可以作为保持状态的场所

名字的scope

变量(变量只是名字)和函数的关系
  • 在def内定义,为local name, def 外看不到
  • 在 enclosing def (the def enclosing current def)内定义,为 nonlocal name. python 3.0 新语法
  • 在 def 外定义,为 global name
每次调用函数都生成一个新的local scope
名字的查找规则 LEGB
local -> Enclosing -> global -> built-in

import

import 不同于c/c++的include(预编译,代码替换),它是运行时的操作。import 可以放在代码的任何地方。只有当代码走到import的位置,才会执行。它完成三项工作
  1. 找到模块文件
  2. 编译(没有相应的.pyc 或者 .pyc 时间戳比.py 陈旧)
  3. 运行代码
模块文件的查找顺序,以import b为例(这也是为什么不用 import b.py,因为不一定为py文件)
  1. b.py
  2. b.pyc
  3. b directory (package import)
  4. b.so b.dll b.pyd (C/C++)
  5. A compiled built-in module coded in C and statically linked into Python
  6. A ZIP file component that is automatically extracted when imported
  7. An in-memory image, for frozen executables
  8. A Java class, in the Jython version of Python
  9. A .NET component, in the IronPython version of Python
import mod1 # 建立名字mod1, 运行mod1模块文件,找到所有名字,以备用mod1.attr方式使用
from mod1 import fun1 # 建立名字fun1,并赋值 fun1 = mod1.fun1
因为上面的区别,所以
# x.py
a = 3

# y.py
from x import a
a = 6
print a #结果为 6
import x
print x.a #结果为 3

如果要改变 x.a 只能用import,而不能用 from import

dir(M) 列出module的所有attributes,除了作者定义的名字,还有系统自动添加的名字
'__builtins__', '__doc__', '__file__', '__name__', '__package__'
__file__ 文件名(在py文件中使用,包含路径)
__name__ 模块名,dir1.dir2.mod

import, from import 两个语句都会执行 mod1,并且在同一个session (process),多次导入mod1只会执行一次。这是预期的效果,两个py文件导入同一个模块,只需执行一次。
如果你要在同一个session再次执行mod1,可以使用
from imp import reload
reload(mod1)

package module

  • package module dir1 对应一个文件夹 dir1
  • dir1 文件夹中必须有 __init__.py 文件,首次import会执行
  • import dir1 和 from dir1 import * 只能看到 __init__.py 中定义的名字,以及 __init__.py 中 __all__  list 里包含的名字
  • 要看到其他名字,必须使用 import dir1.mod2 或 from dir1 import mod2; mod2 对应一个 package module dir2 或  file module
  • import dir1.dir2.mod1 会执行 dir1/__init__.py, dir1/dir2/__init__.py, dir1/dir2/mod1.py

class



class 和 instance 都是对象
class statement 内的名字为 class attributes
instance 继承了class attributes,但有自己的 namespace
per-instance 名字只能在 def 中赋值,以 self. 开头
class 是 module 的名字
继承
class 继承父类(可以有多个父类)的名字
instance 继承了祖宗类的名字
object.attribute 触发搜索
Each attribute reference triggers a new bottom-up tree search—even references to self attributes within a class’s methods
class method 的第一个参数总是 instance 对象(一般名字为 self)
class.method(instance, args...)
instance.method(args...)
这两者是等同的,你可以用其中一种形式调用类方法
实际上,python 会自动把第一种形式转化为第二种

参见 ex-class.py
Best practice:
一般都用
instance.method(args...)
除非你要调用名字被覆盖的函数
比如子类__init__调用父类的__init__
# -*- coding: gbk -*-
import math
class C:
    num = 0
    def __init__(self, x, y=0):
        self.x = x
        self.y = y
        C.num += 1
    def mod(self):
        print "C.mod %.1f"%math.sqrt(self.x**2+self.y**2)
    def isReal(self):
        return self.y==0
    def __str__(self):
        return "%.1f+%.1fi"%(self.x,self.y)
    def howmany():
        return num;

class Pure(C):
    def __init__(self, y):
        C.__init__(self,0,y) #只能用 class.method 方法
    def mod(self):
        print "Pure.mod %.1f"%math.fabs(self.y)
    def __str__(self):
        return "%.1fi"%self.y

def module(num):
    num.mod()
        
c1 = C(5)
print C.isReal(c1) 
print c1.isReal() #两种调用方法是相同的
print c1

c2 = Pure(5)
print c2.isReal() #继承的父类属性
print c2 # 覆盖父类属性
print C.__str__(c2) #使用被覆盖的父类属性

print Pure.num # 类属性,而非实例的属性

module(c1) #多态
module(c2) #多态
结果
True
True
5.0+0.0i
False
5.0i
0.0+5.0i
2
C.mod 5.0
Pure.mod 5.0

delegate

class Base:
    def delegate(self):
        self.action()
    def action(self):
        raise NotImplementedError('action must be defined!')
       
class Sub(Base):
    def action(self):
        print "Yeah, doing action in Sub"
       
       
c = Base()
try:
    c.delegate()
except NotImplementedError as e:
    print("Failed, because ",e)
   
d = Sub()
d.delegate() 


运算符重载



多重继承

python 允许多重继承,当碰到子类的一个名字时,搜索顺序

  • python 2.x 父类依继承定义从左到右,每个父类穷尽其继承树
  • python 3.x 深度优先?


多重继承一般用于 mix in 技巧
被 mix in 的父类定义一些方法,子类继承该 mix in 类,继承了这些方法

0 comments: