Andy Niu �����ĵ�

Andy Niu

Andy Niu Help  1.0.0.0
Python知识点

变量

 Python导入导出
 
 理解import
 
 Python_Swap
 
 Python的设计哲学
 
 Python命令行查看帮助文档
 
 查看帮助信息
 
 pyc文件和pyo文件
 
 __name__
 
 元祖不可变
 

详细描述

变量说明

__name__
1、考虑下面的需求,写了一个模块,里面有测试代码,运行的时候,执行测试代码。
    但是,当这个模块被import的时候,我们不期望执行测试代码,怎么办?
2、这就需要使用,__name__,如下:
    if __name__ == '__main__':
        print "this is animal"
        raw_input()
    __name__可以认为是条件编译,当运行的时候,取值为'__main__' 
    被import的时候,取值为 模块名称
3、测试如下:
    class Animal(object):
    name=''
    age=0
    
    print __name__
    
    if __name__ == '__main__':
        print "this is animal"
        raw_input()
pyc文件和pyo文件
1、pyc文件,是python编译后的字节码(bytecode)文件。只要你运行了py文件,python编译器就会自动生成
    一个对应的pyc字节码文件。这个pyc字节码文件,经过python解释器,会生成机器码运行。
    (这也是为什么pyc文件可以跨平台部署,类似于java的跨平台,java中JVM运行的字节码文件)。
    下次调用直接调用pyc,而不调用py文件。直到你这个py文件有改变。
    python解释器会检查pyc文件中的生成时间,对比py文件的修改时间,如果py更新,那么就生成新的pyc。
2、pyo文件,是python编译优化后的字节码文件。pyo文件在大小上,一般小于等于pyc文件。
    如果想得到某个py文件的pyo文件,可以这样:
    python -O -m py_compile xxxx.py
    python文档是这样描述的:这个优化没有多大作用,只是移除了断言。
3、至于速度,运行几乎一样,加载pyc和pyo稍占优势。
Python_Swap
1、在C++中有值语义和引用语义,而Python中只有引用的语义。
2、示例如下:
>>> a=1
>>> a
1
>>> id(a)
19310280
>>> b=a
>>> b
1
>>> b=2
>>> b
2
>>> id(2)
19310268
解释如下:
b=a,b和a指向同一个对象,对象的引用计数为2,
b=2,修改b的指向,指向2,a的引用计数减1,为1
3、因此,对于swap的实现,
def swap(a,b):
    t=a
    a=b
    b=t
    return
是错误的,这里这是修改了形参的指向,实参的指向,并没有改变。解决办法如下:
def swap(a,b):
    return b,a
调用如下:
a,b=swap(a,b)
Python命令行查看帮助文档
1、使用dir,列出所有的属性
    >>> dir(str)
    >>> dir(str.split)
    在python中任何东西都是对象,str.split是个方法,也是个对象
2、使用__doc__ 查看对象的描述
    >>> print(str.__doc__)
    >>> print(str.split.__doc__)
3、使用help,返回使用说明
    >>> help(str)
    >>> help(str.split)
Python导入导出
1、import xxx,导入某个模块。如下:
    >>> import time
    >>> print time.strftime('%Y-%m-%d %H:%M:%S')
    2015-08-21 21:59:43
注:time.strftime 中的time是模块名,也就是文件名
2、上面还要写上 print time.strftime('%Y-%m-%d %H:%M:%S'),如果想省略time,可以使用:
    >>> from time import *
    >>> print strftime('%Y-%m-%d %H:%M:%S')
    2015-08-21 22:02:32
3、使用from time import *,导致一个问题,就是从模块time导入太多的东西,会污染当前的名称空间。怎么解决?
    只导入自己需要的东西,要使用方法strftime,就只导入方法strftime,如下:
    >>> from time import strftime
    >>> print strftime('%Y-%m-%d %H:%M:%S')
    2015-09-01 08:48:24 
Python的设计哲学
Python的设计哲学是优雅、明确、简单。
Perl语言,同一件事,提供多种方法来做。
而Python,同一件事最好只有一种方法来做。
Python这样做有什么好处?

这会减轻程序员的心智负担,举例来说,C++中的string,计算字符串长度,有两种方法length()和size()
程序员就会想这两种方法有什么区别。孟岩在博客中写道,相对于C,C++增加了程序员的心智负担。这个
影响很严重,语言提供的相似接口越多,参数越多,特性越多,程序员写程序的时候越没有自信,总是在想
:这样固然可以work,但恐怕还有更好的方案吧?会是什么呢? 使用模板参数,抽象出一个基类,使用策略模式
,使用编译时多态,还是运行时多态,内存谁来回收呢?使用智能指针,各种智能指针有什么区别呢?哎呀不行行不行了,
太复杂了,还是能够work就算了。而C程序员没有这些负担,C语言提供的够用,想要啥就写啥没有什么事先不了。

语言新特性也有同样的问题:
1、新特性加重了编译器的编译负担。 
2、新特性加重了运行时的运行负担。 
3、新特性加重了程序员的心智负担。
元祖不可变
1、Python彻底分离了指针和内容,每次修改内容,都相当于,修改指针指向另一块内容。
2、需要注意的是,Python使用了共享内存,如果内容相同,指向同一块内存。如下:
    >>> a='hello'
    >>> b='hello'
    >>> id(a)
    43861376
    >>> id(b)
    43861376
    可以这样理解,a='hello' 分配一块内存,内容为"hello",a指向这块内存。
    b='hello' 先检查有没有这样的一块内存,内容为"hello",刚好找到,地址返回给b
    从内容到地址,可以使用哈希表,内容映射到地址。每次修改内容,对新的内容哈希,看看是否存在一个地址,保存的内容刚好为
    新的内容,如果存在,直接返回地址。如果不存在,new出一个,返回地址。
    C++静态存储区也是同样的道理。
3、查看下面的情况:
    >>> a=123
    >>> b=a
    >>> b=456
    >>> a
    123
    >>> b
    456
    这和C++中的写时拷贝(copy-on-write),道理一样。b=a是指针语义,只复制指针。
    b=456修改b的时候,b指向新的内容,但是a的指向不变,这个时候是值语义。
4、元祖的元素也是指针,元祖的不可变指的是,元素不能指向其他地方,从C++角度理解,就是const指针,不能修改指向。
    但是,元祖本身是可以变的,可以指向其他的内容。如下:
    >>> aTuple=(1,2)
    >>> aTuple[0]=5     // 元素不能修改指向
    
    Traceback (most recent call last):
    File "<pyshell#34>", line 1, in <module>
        aTuple[0]=5
    TypeError: 'tuple' object does not support item assignment
    >>> aTuple=(3,4)    // 元祖本身可以修改指向
    >>> aTuple
    (3, 4)
5、list与tuple之间的转化,使用list方法和tuple方法,返回一个list或者tuple,如下:
    >>> aList=list(aTuple)
    >>> aList
    [3, 4]
    >>> aList[1]=100
    >>> aList
    [3, 100]
    >>> bTuple=tuple(aList)
    >>> bTuple
    (3, 100)
查看帮助信息
1、help
>>> help(Animal)
Help on class Animal in module animal:

class Animal(__builtin__.object)
 |  Methods defined here:
 |  
 |  say(self)
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |  
 |  age = 0
 |  
 |  name = ''
2、dir
>>> dir(Animal)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'name', 'say']
3、查询父类
>>> Animal.__base__
<type 'object'>
4、是否有某个属性
>>> hasattr(Animal,'name')
True
5、方法的参数
>>> inspect.getargspec(Animal.say)
ArgSpec(args=['self'], varargs=None, keywords=None, defaults=None)
理解import
1、import一个模块,如下:
    >>> import c
    >>> c1=C();
    
    Traceback (most recent call last):
    File "<pyshell#1>", line 1, in <module>
        c1=C();
    NameError: name 'C' is not defined
    >>> c1=c.C();
    >>> c1.say();
    I am c
    需要注意的是,import一个模块,使用模块中的对象时,需要在对象前面加上模块名称,也就是文件名。
2、怎么解决上面的问题?
    使用import,从模块中import对象,如下:
    >>> from c import C
    >>> c1=C();
    >>> c1.say();
    I am c
    这种情况下,可以直接使用对象。
3、如何import子目录中的模块?
    考虑当前有  ./a/a.py, 如何import a.py
    在./a目录创建一个空的文件 __init__.py 即可
        >>> import a.a
    
    Traceback (most recent call last):
    File "<pyshell#0>", line 1, in <module>
        import a.a
    ImportError: No module named a.a
    >>> import a.a
4、如何引用父目录中模块?
    考虑当前目录为./a/ 父目录下有./b/b.py, 如何import a.py
    使用 sys增加搜索路径
    >>> import sys;
    >>> sys.path.append('../b');
    >>> import b;
    对于import子目录中的模块,也可以使用这种方式。
Copyright (c) 2015~2016, Andy Niu @All rights reserved. By Andy Niu Edit.