--Python:  基本运算、基本函数(包括复数)、Math模块、NumPy模块

--基本运算


x**2 : x^2 若x是mat矩阵,那就表示x内每个元素求平方

inf:  表示正无穷

逻辑运算符:  and,or,not

--基本函数


字典的get方法


a.get(k,d)

1

get相当于一条if…else…语句。若k在字典a中,则返回a[k];若k不在a中,则返回参数d。


l = {5:2,3:4}

l.get(3,0)  返回值是4;

l.get(1,0)  返回值是0;

1

2

3

type函数:  返回数据类型


type(x):返回x的类型

type(x)._name_:  返回该类型的字符串表示

1

2

len函数:  获得list或str的长度


reload函数:  将之前导入过的模块重新加载进来


next函数    本函数是返回迭代器的下一个元素的值。

在Python 3中,只能使用next()函数(试图调用.next()方法会触发AttributeError)。


my_generator = (letter for letter in 'abcdefg')

next(my_generator)


>>>'a'








--2-----------Python 编码格式-----中文编码---------------------------------------------------------------------------------------------------------------

Python中默认的编码格式是 ASCII 格式,在没修改编码格式时无法正确打印汉字,所以在读取中文时会报错。

注意:  Python3.X 源码文件默认使用utf-8编码,所以可以正常解析中文,无需指定 UTF-8 编码。

注意:  如果你使用编辑器,同时需要设置 py 文件存储的格式为 UTF-8,否则会出现类似以下错误信息

#!/usr/bin/python

# -*- coding: UTF-8 -*-   ##解决法1:  只要在文件开头加入 或~ 代码中包含中文,要在头部指定编码

#coding: UTF-8            ##解决法2:  只要在文件开头加入 或#coding=utf-8 就行(注意:  #coding=utf-8 的 = 号两边不要空格)

print "Hello, World!";    ##英文没有问题

print "你好,世界";       ##但是如果输出中文字符"你好,世界"就有可能会碰到中文编码问题。

Python 文件中如果未指定编码,在执行过程会出现报错:

SyntaxError: Non-ASCII character '\xe4' in file test.py on line 2, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details

--3-----------Python 基础语法----------------------------------------------------------------------------------------------------------------------------

--标识符------区分大小写

所有标识符,可以包括:  字母、数字、下划线。

     字母......区分大小写

     数字......不能以数字开头

     下划线....以下划线开头的标识符是有特殊意义的:

               以单下划线开头          _foo     代表不能直接访问的类属性,需通过类提供的接口进行访问,不能用"from xxx import *"而导入;

               以双下划线开头的        __foo    代表类的私有成员;

               以双下划线开头和结尾的  __foo__  代表python里特殊方法专用的标识,如__init__()代表类的构造函数。

--保留关键字------所有Python关键字只包含小写字母

这些保留字不能用作常数或变数,或任何其他标识符名称。

and       exec      not      assert    finally   or

break     for       pass     class     from      print

continue  global    raise    def       if        return

del       import    try      elif      in        while

else      is        with     except    lambda    yield

--注释------单行注释------采用 # 开头

--注释------多行注释------使用三个单引号'''  或  三个双引号"""

注释可以在语句或表达式行末

#!/usr/bin/python

# -*- coding: UTF-8 -*-

# 文件名:  test.py

# 第1个注释

print "Hello, Python!";  # 第2个注释

name = "Madisetti"       # 这是3个注释

'''

这是多行注释,使用单引号。

'''

"""

这是多行注释,使用双引号。

"""

--行和缩进------python 最具特色的:用缩进来写模块

学习 Python 与其他语言最大的区别就是,Python 的代码块不使用大括号 {} 来控制类,函数以及其他逻辑判断。

缩进的空白数量是可变的,但是所有代码块语句必须包含相同的缩进空白数量,这个必须严格执行。

#!/usr/bin/python

# -*- coding: UTF-8 -*-

# 文件名:  test.py

if True:

    print "Answer"

    print "True"

else:

    print "Answer"

    # 没有严格缩进,在执行时会报错

  print "False"

执行以上代码,会出现如下错误提醒:

$ python test.py

  File "test.py", line 5

    if True:

    ^

IndentationError: unexpected indent

IndentationError: unexpected indent 错误是 python 编译器是在告诉你"Hi,老兄,你的文件里格式不对了,可能是tab和空格没对齐的问题",所有 python 对格式要求非常严格。

如果是 IndentationError: unindent does not match any outer indentation level错误表明,你使用的缩进方式不一致,有的是 tab 键缩进,有的是空格缩进,改为一致即可。

因此,在 Python 的代码块中必须使用相同数目的行首缩进空格数。

建议你在每个缩进层次使用 单个制表符 或 两个空格 或 四个空格 , 切记不能混用

--多行语句

Python语句中一般以新行作为为语句的结束符。

但是我们可以使用斜杠( \)将一行的语句分为多行显示,

total = item_one + \

        item_two + \

        item_three

语句中包含 [], {} 或 () 括号就不需要使用多行连接符。

days = ['Monday', 'Tuesday', 'Wednesday',

        'Thursday', 'Friday']

--引号

Python 可以使用引号( ' )、双引号( " )、三引号( ''' 或 """ ) 来表示字符串,引号的开始与结束必须的相同类型的。

其中三引号可以由多行组成,编写多行文本的快捷语法,常用于文档字符串,在文件的特定地点,被当做注释。

word = 'word'

sentence = "这是一个句子。"

paragraph = """这是一个段落。

包含了多个语句"""

--空行

函数之间或类的方法之间用空行分隔,表示一段新的代码的开始。类和函数入口之间也用一行空行分隔,以突出函数入口的开始。

空行与代码缩进不同,空行并不是Python语法的一部分。书写时不插入空行,Python解释器运行也不会出错。但是空行的作用在于分隔两段不同功能或含义的代码,便于日后代码的维护或重构。

记住:  空行也是程序代码的一部分。

--等待用户输入

下面的程序执行后就会等待用户输入,按回车键后就会退出:

#!/usr/bin/python

raw_input("\n\nPress the enter key to exit.")

以上代码中 ,"\n\n"在结果输出前会输出两个新的空行。一旦用户按下 enter(回车) 键退出,其它键显示。

--同一行显示多条语句

Python可以在同一行中使用多条语句,语句之间使用分号(;)分割,以下是一个简单的实例:

#!/usr/bin/python

import sys; x = 'runoob'; sys.stdout.write(x + '\n')

执行以上代码,输入结果为:

$ python test.py

runoob

--Print 输出

print 默认输出是换行的,如果要实现不换行需要在变量末尾加上逗号 ,

Python 可以同一行显示多条语句,方法是用分号 ; 分开,如:

>>> print 'hello';print 'runoob';

hello

runoob

#!/usr/bin/python

# -*- coding: UTF-8 -*-

x="a"

y="b"

# 换行输出

print x

print y

print '---------'

# 不换行输出

print x,

print y,

# 不换行输出

print x,y

以上实例执行结果为:

a

b

---------

a b a b

--多个语句构成代码组

缩进相同的一组语句构成一个代码块,我们称之代码组。

像if、while、def和class这样的复合语句,首行以关键字开始,以冒号( : )结束,该行之后的一行或多行代码构成代码组。

我们将首行及后面的代码组称为一个子句(clause)。

如下实例:

if expression :

   suite

elif expression :

   suite

else :

   suite

--命令行参数

很多程序可以执行一些操作来查看一些基本信息,Python 可以使用 -h 参数查看各参数帮助信息:

$ python -h

usage: python [option] ... [-c cmd | -m mod | file | -] [arg] ...

Options and arguments (and corresponding environment variables):

-c cmd : program passed in as string (terminates option list)

-d     : debug output from parser (also PYTHONDEBUG=x)

-E     : ignore environment variables (such as PYTHONPATH)

-h     : print this help message and exit

[ etc. ]

我们在使用脚本形式执行 Python 时,可以接收命令行输入的参数,具体使用可以参照 Python 命令行参数。

执行脚本传入参数,使用sys模块,编辑 test.py 如下

#!/usr/bin/python

# -*- coding: UTF-8 -*-

import sys

print sys.argv

sys.argv 用来获取命令行参数

运行命令,执行结果:

./test.py hello

['./test.py', 'hello']

sys.argv[0] 代表文件本身路径,所带参数从 sys.argv[1] 开始。

脚本语言的第一行,目的就是指出,你想要你的这个文件中的代码用什么可执行程序去运行它,就这么简单。

#!/usr/bin/python : 是告诉操作系统执行这个脚本的时候,调用 /usr/bin 下的 python 解释器;

#!/usr/bin/env python(推荐): 这种用法是为了防止操作系统用户没有将 python 装在默认的 /usr/bin 路径里。当系统看到这一行的时候,首先会到 env 设置里查找 python 的安装路径,再调用对应路径下的解释器程序完成操作。

#!/usr/bin/python 相当于写死了python路径;

#!/usr/bin/env python 会去环境设置寻找 python 目录,推荐这种写法

--4-----------Python 标准数据类型 及 转换----------------------------------------------------------------------------------------------------------------------------

在内存中存储的数据可以有多种类型。

变量存储在内存中的值。这就意味着在创建变量时会在内存中开辟一个空间。

基于变量的数据类型,解释器会分配指定内存,并决定什么数据可以被存储在内存中。

因此,变量可以指定不同的数据类型,这些变量可以存储整数,小数或字符。

Python 定义了5个标准类型,用于存储各种类型的数据。

有2种:  数字型  非数字型

(1) 数字型     包括 1. 符号整型 int

                    2. 长整型   long     (也可以代表8进制和16进制)      Python的长整型,使用 L 来显示,也可以使用小写 l,但建议使用大写 L,避免与数字 1 混淆

                    3. 浮点型   float

                    4. 复数类型 complex  (复数由实数部分和虚数部分构成,虚数部分以j或J标识) 可以用 a + bj,或者 complex(a,b) 表示, 复数的实部 a 和虚部 b 都是浮点型。

(2) 非数字型   包括 1. 字符串       表示方式:  str="hello,world"

                    2. 列表         表示方式:  list=['hello',2,3,4,'world']

                    3. 元组         表示方式:  tuple=('hello',2,3,4,'world')        相当于只读列表,不可以二次赋值

                    4. 字典         key值对


非数字型的共同点:  都可以使用切片、链接(+)、重复(*)、取值(a[])等相关运算;

非数字型的不同点:  列表 可以直接赋值,元组不可以赋值,字典按照 dict[k]=v 的方式赋值。

截取方式相同:  名称[头下标:尾下标]

下标是从0开始算起,可以是正数或者负数,下标为空则表示取到头或者尾

开始截取时,包含了下边界,而截取到最大范围不包括上边界。

元组不能二次赋值,列表可以

--变量赋值--Python 中的变量赋值不需要类型声明。

每个变量在内存中创建,都包括变量的标识,名称和数据这些信息。

每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建。

等号= 用来给变量赋值。

等号= 运算符左边是一个变量名,等号(=)运算符右边是存储在变量中的值。例如:

#!/usr/bin/python

# -*- coding: UTF-8 -*-

counter = 100 # 赋值整型变量

miles = 1000.0 # 浮点型

name = "John" # 字符串

print counter

print miles

print name

以上实例中,100,1000.0和"John"分别赋值给counter,miles,name变量。

执行以上程序会输出如下结果:

100

1000.0

John

--多个变量赋值--Python允许同时为多个变量赋值

a = b = c = 1

以上实例,创建一个整型对象,值为1,三个变量被分配到相同的内存空间上。

您也可以为多个对象指定多个变量。例如:

a, b, c = 1, 2, "john"

以上实例,两个整型对象1和2的分配给变量 a 和 b,字符串对象 "john" 分配给变量 c。

--Python数字类型--用于存储数值

他们是不可改变的数据类型,这意味着改变数字数据类型会分配一个新的对象。

当你指定一个值时,Number对象就会被创建:

var1 = 1

var2 = 10

您也可以使用del语句删除一些对象的引用。

del语句的语法是:

del var1[,var2[,var3[....,varN]]]]

您可以通过使用del语句删除单个或多个对象的引用。

del var

del var_a, var_b

--Python字符串--接收单引号' 双引号" 三引号(''' """) 来表示字符串,引号的开始与结束必须的相同类型的。

其中三引号可以由多行组成,编写多行文本的快捷语法,常用语文档字符串,在文件的特定地点,被当做注释。

包含了多个语句"""

字符串或串(String)是由数字、字母、下划线组成的一串字符。

一般记为 :

s="a1a2···an"(n>=0)

它是编程语言中表示文本的数据类型。

python的字串列表有2种取值顺序:

从左到右索引默认0开始的,最大范围是字符串长度少1

从右到左索引默认-1开始的,最大范围是字符串开头

如果你要实现从字符串中获取一段子字符串的话,可以使用变量 [头下标:尾下标],就可以截取相应的字符串,其中下标是从 0 开始算起,可以是正数或负数,下标可以为空表示取到头或尾。

当使用以冒号分隔的字符串,python返回一个新的对象,结果包含了以这对偏移标识的连续的内容,左边的开始是包含了下边界。

上面的结果包含了s[1]的值l,而取到的最大范围不包括上边界,就是s[5]的值p。

#!/usr/bin/python

# -*- coding: UTF-8 -*-

word = 'word'

sentence = "这是一个句子。"

paragraph = """这是一个段落。

s = 'ilovepython'

print s[1:5]        # 结果是love

str = 'Hello World!'

print str           # 输出完整字符串                         Hello World!

print str[0]        # 输出字符串中的第1个字符                H

print str[2:5]      # 输出字符串中第3个至第5个之间的字符串   llo

print str[2:]       # 输出从第3个字符开始的字符串            llo World!

print str * 2       # 输出字符串2次                          Hello World!Hello World!         星号(*)是重复操作

print str + "TEST"  # 输出连接的字符串                       Hello World!TEST                 加号(+)是字符串连接运算符

dict(),dict(list) 转换成一个dictionary

max(...) 求最大值

min(...) 求最小值

int(x [,base])     转换成一个integer           将x转换为一个整数

long(x [,base] )   转换成一个long interger     将x转换为一个长整数

float(x)           转换成一个浮点数            将x转换到一个浮点数

complex(real [,imag])    转换成复数            创建一个复数

str(x)          得到obj的字符串描述     将对象 x 转换为字符串

repr(x)         将对象 x 转换为表达式字符串

eval(str)       用来计算在字符串中的有效Python表达式,并返回一个对象

tuple(seq)        把一个sequence转换成一个tuple 将序列 s 转换为一个元组

list(seq)         把一个sequence转换成一个list     将序列 s 转换为一个列表

set(s)          转换为可变集合

dict(d)         创建一个字典。d 必须是一个序列 (key,value)元组。

frozenset(s)    转换为不可变集合

chr(x)          把一个ASCII数值,变成字符    将一个整数转换为一个字符

unichr(x)       将一个整数转换为Unicode字符

ord(x)          把一个字符或者unicode字符,变成ASCII数值   将一个字符转换为它的整数值

hex(x)          把整数x变成十六进制表示的字符串    将一个整数转换为一个十六进制字符串

oct(x)          把整数x变成八进制表示的字符串    将一个整数转换为一个八进制字符串

--查看变量的数据类型--python 的所有数据类型都是类,可以通过 type() 查看该变量的数据类型

>>> n=1

>>> type(n)      

>>> n="runoob"

>>> type(n)      

--查看变量的数据类型--还可以用 isinstance 来判断

a = 111

isinstance(a, int)      输出 True

--isinstance 和 type 的区别在于

>>> class A:

...     pass

...

>>> class B(A):

...     pass

...

>>> isinstance(A(), A)

True

>>> type(A()) == A

False

>>> isinstance(B(), A)

True

>>> type(B()) == A

False

区别就是:

 type()不会认为子类是一种父类类型。

 isinstance()会认为子类是一种父类类型。

--5-----------Python 运算符----------------------------------------------------------------------------------------------------------------------------

--比较运算符

== 等于           != 不等于         <> 不等于

> 大于           < 小于

>= 大于等于       <= 小于等于

--位运算符

& 按位与运算符:  参与运算的两个值,如果两个相应位都为1,则该位的结果为1,否则为0 (a & b) 输出结果 12 ,二进制解释:   0000 1100

| 按位或运算符:  只要对应的二个二进位有一个为1时,结果位就为1。 (a | b) 输出结果 61 ,二进制解释:   0011 1101

^ 按位异或运算符:  当两对应的二进位相异时,结果为1 (a ^ b) 输出结果 49 ,二进制解释:   0011 0001

~ 按位取反运算符:  对数据的每个二进制位取反,即把1变为0,把0变为1 (~a ) 输出结果 -61 ,二进制解释:   1100 0011, 在一个有符号二进制数的补码形式。

<< 左移动运算符:  运算数的各二进位全部左移若干位,由"<<"右边的数指定移动的位数,高位丢弃,低位补0。 a << 2 输出结果 240 ,二进制解释:   1111 0000

>> 右移动运算符:  把">>"左边的运算数的各二进位全部右移若干位,">>"右边的数指定移动的位数 a >> 2 输出结果 15 ,二进制解释:   0000 1111

--逻辑运算符

and x and y   布尔"与" - 如果 x 为 False,x and y 返回 False,否则它返回 y 的计算值。 (a and b) 返回 20。

 or x  or y   布尔"或" - 如果 x 是 True,它返回 True,否则它返回 y 的计算值。 (a or b) 返回 10。

not x         布尔"非" - 如果 x 为 True,返回 False 。如果 x 为 False,它返回 True。 not(a and b) 返回 False

--成员运算符

in 如果在指定的序列中找到值返回 True,否则返回 False。 x 在 y 序列中 , 如果 x 在 y 序列中返回 True。

not in 如果在指定的序列中没有找到值返回 True,否则返回 False。 x 不在 y 序列中 , 如果 x 不在 y 序列中返回 True。

--赋值运算符

变量赋值,简单粗暴不需要声明类型, 灵活多变,非常好用。

数字数据类是不可改变的数据类型,改变数字数据类型会分配一个新的对象。

字符串的操作有基本的功能不需要再自己进行拼接遍历的操作。

  对于字符串来说,最常用的有+和*两种运算,+表示把两个字符串进行连接,*表示连乘。比如:

  注意:  一个字符串*0结果是空字符串,一个字符串*一个负数也是空字符串。

=   简单的赋值运算符    例 c = a + b   将 a + b 的运算结果赋值为 c

+=  加法赋值运算符      例 c += a 等效于 c = c + a

-=  减法赋值运算符      例 c -= a 等效于 c = c - a

*=  乘法赋值运算符      例 c *= a 等效于 c = c * a

/=  除法赋值运算符      例 c /= a 等效于 c = c / a

%=  取模赋值运算符      例 c %= a 等效于 c = c % a

**= 幂赋值运算符        例 c **= a 等效于 c = c ** a

//= 取整除赋值运算符    例 c //= a 等效于 c = c // a

a = 1         # 变量赋值

b = "god"

str = 'this is string 1'                        # 字符串赋值

list = ['this', 'is', 'list', 2]                # 列表串赋值   用 "[ ]" 标识类似 C 语言中的数组。

tuple = ('this', 'is', 'tuple', 3)              # 元组赋值     用 "( )" 标识。内部元素用逗号隔开。但是元组不能二次赋值,相当于只读列表。

dict = {1:'this', 2:'is', 3:'dictionary', 4:4}  # 字典赋值     用 "{ }" 标识。字典由索引 key 和它对应的值 value 组成。

--算术运算符

+ 加           两个对象相加 a + b 输出结果 30

- 减 或 取反   得到负数或是一个数减去另一个数 a - b 输出结果 -10

* 乘           两个数相乘或是返回一个被重复若干次的字符串 a * b 输出结果 200

/ 整除         整除运算最终值取的是中间值的floor值     x除以y b / a 输出结果 2

% 取模/取余    返回除法的余数 b % a 输出结果 0

** 幂/乘方      返回x的y次幂 a**b 为10的20次方, 输出结果 100000000000000000000

// 取整除       返回商的整数部分 9//2 输出结果 4 , 9.0//2.0 输出结果 4.0

--优先级 和运算符

** 指数 (最高优先级)

~ + - 按位翻转, 一元加号和减号 (最后两个的方法名为 +@ 和 -@)

* / % // 乘,除,取模和取整除

+ - 加法减法

>> << 右移,左移运算符

& 位 'AND'

^ | 位运算符

<= < > >= 比较运算符

<> == != 等于运算符

= %= /= //= -= += *= **= 赋值运算符

is is not 身份运算符

in not in 成员运算符

not or and 逻辑运算符




--1.1-------------import------import shelve 模块--------shelve也是python提供给我们的序列化工具,比pickle用起来更简单一些。------------------------------------------------------

import shelve

f = shelve.open('shelve_file')            # shelve只提供给一个open方法,是用key来访问的,使用起来和字典类似。

f['key'] = {'int':10, 'float':9.5, 'string':'Sample data'} #直接对文件句柄操作,就可以存入数据

f.close()

import shelve

f1 = shelve.open('shelve_file')

existing = f1['key'] #取出数据的时候也只需要直接用key获取即可,但是如果key不存在会报错

f1.close()

print(existing)    # 这个模块有个限制,它不支持多个应用同一时间往同一个DB进行写操作。所以当我们知道我们的应用如果只进行读操作,我们可以让shelve通过只读方式打开DB

import shelve

f = shelve.open('shelve_file', flag='r')

existing = f['key']

f.close()

print(existing)    # 由于shelve在默认情况下是不会记录待持久化对象的任何修改的,所以我们在shelve.open()时候需要修改默认参数,否则对象的修改不会保存。

import shelve

f1 = shelve.open('shelve_file')

print(f1['key'])

f1['key']['new_value'] = 'this was not here before'

f1.close()

f2 = shelve.open('shelve_file', writeback=True)

print(f2['key'])

f2['key']['new_value'] = 'this was not here before'

f2.close()

"""

writeback方式有优点也有缺点。优点是减少了我们出错的概率,并且让对象的持久化对用户更加的透明了;

但这种方式并不是所有的情况下都需要,

首先,使用writeback以后,shelf在open()的时候会增加额外的内存消耗,并且当DB在close()的时候会将缓存中的每一个对象都写入到DB,这也会带来额外的等待时间。

因为shelve没有办法知道缓存中哪些对象修改了,哪些对象没有修改,因此所有的对象都会被写入。

"""

--1.2-------------import------import pickle 模块-------------提供了4个功能:   dumps、dump、loads、load------用于python特有的类型 和 python的数据类型间进行转换-----------------------

import pickle

dic = {'k1':'v1','k2':'v2','k3':'v3'}

str_dic = pickle.dumps(dic)               # 功能1-dumps

print(str_dic) #一串二进制内容

dic2 = pickle.loads(str_dic)              # 功能3-loads-反序列化,读

print(dic2) #字典

import time

struct_time = time.localtime(1000000000)

print(struct_time)

f = open('pickle_file','wb')

pickle.dump(struct_time,f)                # 功能2-dump-序列化,存

f.close()

f = open('pickle_file','rb')

struct_time2 = pickle.load(f)             # 功能4-load-不仅可以序列化字典,列表...可以把python中任意的数据类型序列化

print(struct_time2.tm_year)


--12.4-------------import------import logging 模块-------------xx-----------------------------------------------------------------

--python中使用sys模板和logging模块获取行号和函数名的方法

对于python,这几天一直有两个问题在困扰我:

1.python中没办法直接取得当前的行号和函数名。这是有人在论坛里提出的问题,底下一群人只是在猜测python为什么不像__file__一样提供__line__和__func__,但是却最终也没有找到解决方案。

2.如果一个函数在不知道自己名字的情况下,怎么才能递归调用自己。这是我一个同事问我的,其实也是获取函数名,但是当时也是回答不出来。

但是今晚!所有的问题都有了答案。

一切还要从我用python的logging模块说起,logging中的format中是有如下选项的:

%(name)s            Name of the logger (logging channel)

%(levelno)s         Numeric logging level for the message (DEBUG, INFO, WARNING, ERROR, CRITICAL)

%(levelname)s       Text logging level for the message ("DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL")

%(pathname)s        Full pathname of the source file where the logging call was issued (if available)

%(filename)s        Filename portion of pathname

%(module)s          Module (name portion of filename)

%(lineno)d          Source line number where the logging call was issued (if available)

%(funcName)s        Function name

%(created)f         Time when the LogRecord was created (time.time() return value)

%(asctime)s         Textual time when the LogRecord was created

%(msecs)d           Millisecond portion of the creation time

%(relativeCreated)d Time in milliseconds when the LogRecord was created, relative to the time the logging module was loaded (typically at application startup time)

%(thread)d          Thread ID (if available)

%(threadName)s      Thread name (if available)

%(process)d         Process ID (if available)

%(message)s         The result of record.getMessage(), computed just as the record is emitted

也就是说,logging是能够获取到调用者的行号和函数名的,那会不会也可以获取到自己的行号和函数名呢?

我们来看一下源码,主要部分如下:

def currentframe():

    """Return the frame object for the caller's stack frame."""

    try:

        raise Exception

    except:

        return sys.exc_info()[2].tb_frame.f_back

def findCaller(self):

    """

    Find the stack frame of the caller so that we can note the source

    file name, line number and function name.

    """

    f = currentframe()

    #On some versions of IronPython, currentframe() returns None if

    #IronPython isn't run with -X:Frames.

    if f is not None:

        f = f.f_back

    rv = "(unknown file)", 0, "(unknown function)"

    while hasattr(f, "f_code"):

        co = f.f_code

        filename = os.path.normcase(co.co_filename)

        if filename == _srcfile:

            f = f.f_back

            continue

        rv = (co.co_filename, f.f_lineno, co.co_name)

        break

    return rv

def _log(self, level, msg, args, exc_info=None, extra=None):

    """

    Low-level logging routine which creates a LogRecord and then calls

    all the handlers of this logger to handle the record.

    """

    if _srcfile:

        #IronPython doesn't track Python frames, so findCaller throws an

        #exception on some versions of IronPython. We trap it here so that

        #IronPython can use logging.

        try:

            fn, lno, func = self.findCaller()

        except ValueError:

            fn, lno, func = "(unknown file)", 0, "(unknown function)"

    else:

        fn, lno, func = "(unknown file)", 0, "(unknown function)"

    if exc_info:

        if not isinstance(exc_info, tuple):

            exc_info = sys.exc_info()

    record = self.makeRecord(self.name, level, fn, lno, msg, args, exc_info, func, extra)

    self.handle(record)

我简单解释一下,实际上是通过在currentframe函数中抛出一个异常,然后通过向上查找的方式,找到调用的信息。其中

rv = (co.co_filename, f.f_lineno, co.co_name)

的三个值分别为文件名,行号,函数名。(可以去http://docs.python.org/library/sys.html来看一下代码中几个系统函数的说明)

OK,如果已经看懂了源码,那获取当前位置的行号和函数名相信也非常清楚了,代码如下:

#!/usr/bin/python

# -*- coding: utf-8 -*-

'''

#=============================================================================

#  FileName:        xf.py

#  Description:     获取当前位置的行号和函数名

#  Version:         1.0

#=============================================================================

'''

import sys

def get_cur_info():

    """Return the frame object for the caller's stack frame."""

    try:

        raise Exception

    except:

        f = sys.exc_info()[2].tb_frame.f_back

    return (f.f_code.co_name, f.f_lineno)

def callfunc():

    print get_cur_info()

if __name__ == '__main__':

    callfunc()

输入结果是:

('callfunc', 24)

符合预期~~

哈哈,OK!现在应该不用再抱怨取不到行号和函数名了吧~

=============================================================================

后来发现,其实也可以有更简单的方法,如下:

import sys

def get_cur_info():

    print sys._getframe().f_code.co_name

    print sys._getframe().f_back.f_code.co_name

get_cur_info()

调用结果是:

get_cur_info

--1.1-------------import------import copy 模块      提供了对复合对象进行浅拷贝和深拷贝的功能。(list,tuple,dict,custom class)

功能: 用于对象的拷贝操作。      复制操作只对复合对象有效。

方法: 该模块非常简单,只提供了2个主要的方法:

copy.copy        表示浅复制    拷贝后,对象的引用没有发生变化,而对象的行为发生变化,会反映到拷贝后的对象身上     只复制对象本身,没有复制该对象所引用的对象。

copy.deepcopy    表示深复制    拷贝后,对象的引用发生了变化,即对象不同,所以,即使对象再怎么变,也不会对其他对象产生影响

#coding=gbk

import copy

l1 = [1,2,[3,4]]

l2 = copy.copy(l1)

print l1    输出结果 [1,2,[3,4]]

print l2    输出结果 [1,2,[3,4]]

l2[2][0]=50

print l1    输出结果 [1,2,[50,4]]

print l2    输出结果 [1,2,[50,4]]

l3 = [1,2,[3,4]]

l4 = copy.deepcopy(l1)

print l3    输出结果 [1,2,[3,4]]

print l4    输出结果 [1,2,[50, 4]]

l4[2][0]=50

print l3    输出结果 [1,2,[3,4]]

print l4    输出结果 [1,2,[50,4]]

改变copy的默认行为

在定义类时,通过定义__copy__和__deepcopy__方法,可以改变copy的默认行为。

class CopyObj(object):

    def __repr__(self):

        return "CopyObj"

    def __copy__(self):

        return "Hello"

obj = CopyObj()

obj1= copy.copy(obj)

print obj     输出结果 CopyObj

print obj1    输出结果 Hello

举例  https://www.cnblogs.com/hongten/p/hongten_python_copy.html

http://blog.csdn.net/xmnathan/article/details/36217631

--########################################################################################################################

--1.1-------------import------import paramiko 模块---

最近在写Python脚本的时候,需要一个功能就是使用ssh登录Linux主机A,然后在主机A上执行scp命令将主机上的文件自动给拷贝到Linux主机B上。远程登录使用pycrypto和paramiko模块实现了,但是在执行scp命令的时候需要输入密码没有搞定,最后换了个角度思考,可不可以不输入密码就实现scp拷贝,到网上一搜就解决了。解决步骤如下(以从A主机向B主机拷贝文件为例):

在A主机上以root用户登录,执行命令:  ssh-keygen -b 1024 -t rsa,之后连续三次回车即可

在A主机上进入/root/.ssh目录就会发现几个新生成的文件,其中一个是id_rsa.pub

在A主机上scp /root/.ssh/id_rsa.pub root@B:/root/.ssh/authorized_keys

会发现在这次拷贝的时候需要输入密码。

但是之后如果需要将A主机文件使用scp拷贝到B主机上的时候就可以不输入密码直接执行了

至此,信任关系配置完毕

参照:  http://eric-gcm.iteye.com/blog/912071

http://blog.csdn.net/doublefalse/article/details/1955922

之后就可以使用paramiko模块,首先以root用户身份登录到A主机上,然后使用exec_command方法执行scp命令即可

#!/usr/bin/env python

import paramiko

import os

hostname  = '192.168.56.101'

port      = 22

username  = 'root'

password  = '111111'

dir_path  = '/root/perl'

if __name__ == "__main__":

    t = paramiko.Transport((hostname, port))

    t.connect(username=username, password=password)

    sftp = paramiko.SFTPClient.from_transport(t)

    files = sftp.listdir(dir_path)

    for f  in files:

        print 'Retrieving', f

        sftp.get(os.path.join(dir_path, f), f)

    t.close()

--########################################################################################################################

--1.1-------------import------import shutil 模块      提供大量的文件的高级操作。特别针对文件拷贝,删除,改名。 目录和文件操作以及压缩操作。对单个文件的操作也可参见os模块。

                                                      shutil操作只针对一般的文件,不支持pipes,block devices等文件类型。

--########################################################################################################################

--shutil.copy(src, dst)    实现文件复制功能,将src文件复制到dst文件夹中

参数:   2个都是字符串格式。如果dst是一个文件名称,那么它等同于复制 + 重命名。

返回值: 复制成功后的字符串格式的文件路径

import shutil

import os

os.chdir('D:\\PythonStudy\\pyfiles\\')

shutil.copy('D:\\PythonStudy\\pyfiles\\Hello_apple.py', 'D:\\PythonStudy\\target\\')

--shutil.copy2( src, dst)  在copy基础上,再复制文件最后访问时间与修改时间也复制过来了,类似于cp –p的东西

                           如果两个位置的文件系统是一样的话相当于是rename操作,只是改名;

                           如果是不在相同的文件系统的话就是做move操作

--shutil.copyfile(src, dst) 将源的内容复制给目标,如果当前的dst已存在的话就会被覆盖掉

                            前提是目标地址是具备可写权限。如果没有权限写目标文件则产生IoError,IOException.

                            实际是使用了底层函数copyfileobj()

--shutil.copymode(src, dst) 复制文件元数据

                            只是会复制其权限,其他的东西是不会被复制的(在UNIX创建一个新文件,会根据当前用户的umask接受权限。要把权限从一个文件复制到另一个文件)

--shutil.copystat(src, dst) 复制权限、最后访问时间、最后修改时间(要复制其他元数据)

--shutil.copytree(olddir, newdir, True/Flase)  把olddir拷贝一份newdir,

                            如果第3个参数是True,则复制目录时将保持文件夹下的符号连接,

                            如果第3个参数是False,则将在复制的目录下生成物理副本来替代符号连接

shutil.move( src, dst)  移动文件或重命名

shutil.rmtree( src ) 递归删除一个目录以及目录内的所有内容

shutil包含三个函数处理目录树。要把一个目录从一个位置复制到另一个位置,使用copytree()。这会递归遍历源目录树,将文件复制到目标。

copytree()可以将当前这个实现当作起点,在使用前要让它更健壮,可以增加一些特性,如进度条。

from shutil import *

from commands import *

print 'BEFORE:'

print getoutput('ls -rlast /tmp/example')

copytree('../shutil', '/tmp/example')

print '\nAFTER:'

print getoutput('ls -rlast /tmp/example')

symlinks 参数控制着符号链接作为链接复制还是文件复制。默认将内容复制到新文件,如果选项为true,会在目标中创建新的符号链接。

要删除一个目录及其内容,可以使用rmtree()。

from shutil import *

from commands import *

print 'BEFORE:'

print getoutput('ls -rlast /tmp/example')

rmtree('/tmp/example')

print '\nAFTER:'

print getoutput('ls -rlast /tmp/example')

将一个文件或目录从一个位置移动到另一个位置,可以使用move()。

from shutil import *

from glob import glob

with open('example.txt', 'wt') as f:

  f.write('i love you')

print 'BEFORE: ', glob('example*')

move('example.txt', 'example.out')

print 'AFTER: ',glob('example*')

其语义与UNIX命令mv类似。如果源与目标都在同一个文件系统内,则会重命名源文件。否则,源文件会复制到目标文件,将源文件删除。

>>> ================================ RESTART ================================

>>>

BEFORE: ['example', 'example.txt']

AFTER: ['example', 'example.out']

from shutil import *

import os

from commands import *

with open('file_to_change.txt', 'wt') as f:

  f.write('i love you')

os.chmod('file_to_change.txt', 0444)

print 'BEFORE:'

print getstatus('file_to_change.txt')

copymode('shutil_copymode.py', 'file_to_change.txt')

print 'AFTER:'

print getstatus('file_to_change.txt')

from shutil import *

import os

import time

def show_file_info(filename):

  stat_info = os.stat(filename)

  print '\tMode    :', stat_info.st_mode

  print '\tCreated  :', time.ctime(stat_info.st_ctime)

  print '\tAccessed  :', time.ctime(stat_info.st_atime)

  print '\tModified  :', time.ctime(stat_info.st_mtime)

with open('file_to_change.txt', 'wt') as f:

  f.write('i love you')

os.chmod('file_to_Change.txt', 0444)

print 'BEFORE:'

show_file_info('file_to_Change.txt')

copystat('shutil_copystat.py', 'file_to_Change.txt')

print 'AFTER:'

show_file_info('file_to_Change.txt')

使用copystat()只会复制与文件关联的权限和日期。

from shutil import *

from glob import glob

print 'BEFORE:', glob('huanhuan.*')

copyfile('huanhuan.txt', 'huanhuan.txt.copy')

print 'AFTER:', glob('huanhuan.*')

这个函数会打开输入文件进行读写,而不论其类型,所以某些特殊文件不可以用copyfile()复制为新的特殊文件。

参数是文件名,copyfileobj()的参数是打开的文件句柄。第三个参数可选,用于读入块的缓冲区长度。

默认行为是使用大数据块读取。使用-1会一次性读取所有输入,或者使用其他正数可以设置特定块的大小。

类似于UNIX命令行工具cp,copy()函数会用同样的方式解释输出名。如果指定的目标指示一个目录而不是一个文件,会使用源文件的基名在该目录中创建一个新文件。

from shutil import *

import os

import time

dir = os.getcwd()

if not os.path.exists('%s\\example' % dir):

  os.mkdir('%s\\example' % dir)

def show_file_info(filename):

  stat_info = os.stat(filename)

  print '\tMode  :', stat_info.st_mode

  print '\tCreated :', time.ctime(stat_info.st_ctime)

  print '\tAccessed:', time.ctime(stat_info.st_atime)

  print '\tModified:', time.ctime(stat_info.st_mtime)

print 'SOURCE:'

show_file_info('huanhuan.txt')

copy2('huanhuan.txt', 'example')

print 'DEST:'

show_file_info('%s\\example\\huanhuan.txt' % dir)

--python实现拷贝指定文件到指定目录               python实现这个功能非常简单,因为库太强大了

import os

import shutil

alllist=os.listdir(u"D:\\notes\\python\\docx\\")

for i in alllist:

    aa,bb=i.split(".")

    if 'python' in aa.lower():

        oldname=u"D:\\notes\\python\\docx\\"+aa+"."+bb

        newname=u"d:\\copy\\newname"+aa+"."+bb

        shutil.copyfile(oldname,newname)

用python实现了一个小型的自动发版本的工具。这个“自动发版本”有点虚, 只是简单地把debug 目录下的配置文件复制到指定目录,把Release下的生成文件复制到同一指定,过滤掉不需要的文件夹(.svn),然后再往这个指定目录添加几个特定的文件。

首先插入必要的库:

import os

import os.path

import shutil

import time,  datetime

然后就是一大堆功能函数。第一个就是把某一目录下的所有文件复制到指定目录中:

def copyFiles(sourceDir,  targetDir):

    if sourceDir.find(".svn") > 0:

        return

    for file in os.listdir(sourceDir):

        sourceFile = os.path.join(sourceDir,  file)

        targetFile = os.path.join(targetDir,  file)

        if os.path.isfile(sourceFile):

            if not os.path.exists(targetDir):

                os.makedirs(targetDir)

            if not os.path.exists(targetFile) or(os.path.exists(targetFile) and (os.path.getsize(targetFile) != os.path.getsize(sourceFile))):

                    open(targetFile, "wb").write(open(sourceFile, "rb").read())

        if os.path.isdir(sourceFile):

            First_Directory = False

            copyFiles(sourceFile, targetFile)

--删除一级目录下的所有文件

def removeFileInFirstDir(targetDir):

    for file in os.listdir(targetDir):

        targetFile = os.path.join(targetDir,  file)

        if os.path.isfile(targetFile):

            os.remove(targetFile)

复制一级目录下的所有文件到指定目录:

def coverFiles(sourceDir,  targetDir):

        for file in os.listdir(sourceDir):

            sourceFile = os.path.join(sourceDir,  file)

            targetFile = os.path.join(targetDir,  file)

            #cover the files

            if os.path.isfile(sourceFile):

                open(targetFile, "wb").write(open(sourceFile, "rb").read())

--复制指定文件到目录

def moveFileto(sourceDir,  targetDir):

    shutil.copy(sourceDir,  targetDir)

--往指定目录写文本文件

def writeVersionInfo(targetDir):

    open(targetDir, "wb").write("Revison:")

--返回当前的日期,以便在创建指定目录的时候用:

def getCurTime():

    nowTime = time.localtime()

    year = str(nowTime.tm_year)

    month = str(nowTime.tm_mon)

    if len(month) < 2:

        month = '0' + month

    day =  str(nowTime.tm_yday)

    if len(day) < 2:

        day = '0' + day

    return (year + '-' + month + '-' + day)

--然后就是主函数的实现了:

if  __name__ =="__main__":

    print "Start(S) or Quilt(Q) \n"

    flag = True

    while (flag):

        answer = raw_input()

        if  'Q' == answer:

            flag = False

        elif 'S'== answer :

            formatTime = getCurTime()

            targetFoldername = "Build " + formatTime + "-01"

            Target_File_Path += targetFoldername

            copyFiles(Debug_File_Path,   Target_File_Path)

            removeFileInFirstDir(Target_File_Path)

            coverFiles(Release_File_Path,  Target_File_Path)

            moveFileto(Firebird_File_Path,  Target_File_Path)

            moveFileto(AssistantGui_File_Path,  Target_File_Path)

            writeVersionInfo(Target_File_Path+"\\ReadMe.txt")

            print "all sucess"

        else:

            print "not the correct command"          感觉是果然简单, 不过简单的原因是因为库函数丰富,语言基本特性的简单真没感觉出来。

--12.4-------------import------import filecmp 模块---比较目录的不同

--12.4-------------import------import difflib 模块---提供的类和方法用来进行序列的差异化比较,它能够比对文件并生成差异结果文本或者html格式的差异化比较页面

class difflib.SequenceMatcher    此类提供了比较任意可哈希类型序列对方法。此方法将寻找没有包含‘垃圾'元素的最大连续匹配序列。

                                 通过对算法的复杂度比较,它由于原始的完形匹配算法,在最坏情况下有n的平方次运算,在最好情况下,具有线性的效率。

                                 它具有自动垃圾启发式,可以将重复超过片段1%或者重复200次的字符作为垃圾来处理。可以通过将autojunk设置为false关闭该功能。

class difflib.Differ             此类比较的是文本行的差异并且产生适合人类阅读的差异结果或者增量结果,结果中各部分的表示如下:

class difflib.HtmlDiff           此类可以被用来创建HTML表格 (或者说包含表格的html文件) ,两边对应展示或者行对行的展示比对差异结果。

make_file(fromlines, tolines [, fromdesc][, todesc][, context][, numlines])    用来生成包含一个内容为比对结果的表格的html文件,并且部分内容会高亮显示

make_table(fromlines, tolines [, fromdesc][, todesc][, context][, numlines])   用来生成包含一个内容为比对结果的表格的html文件,并且部分内容会高亮显示

--difflib.context_diff(a, b[, fromfile][, tofile][, fromfiledate][, tofiledate][, n][, lineterm])    比较a与b(字符串列表),并且返回一个差异文本行的生成器  

>>> s1 = ['bacon\n', 'eggs\n', 'ham\n', 'guido\n']

>>> s2 = ['python\n', 'eggy\n', 'hamster\n', 'guido\n']

>>> for line in context_diff(s1, s2, fromfile='before.py', tofile='after.py'):

...   sys.stdout.write(line)

--difflib.get_close_matches(word, possibilities[, n][, cutoff])     返回最大匹配结果的列表

>>> get_close_matches('appel', ['ape', 'apple', 'peach', 'puppy'])         ['apple', 'ape']

>>> import keyword

>>> get_close_matches('wheel', keyword.kwlist)       ['while']

>>> get_close_matches('apple', keyword.kwlist)       []

>>> get_close_matches('accept', keyword.kwlist)      ['except']

--difflib.ndiff(a, b[, linejunk][, charjunk])     比较a与b(字符串列表),返回一个Differ-style 的差异结果

>>> diff = ndiff('one\ntwo\nthree\n'.splitlines(1), 'ore\ntree\nemu\n'.splitlines(1))

>>> print ''.join(diff),

--difflib.restore(sequence, which)      返回一个由两个比对序列产生的结果

>>> diff = ndiff('one\ntwo\nthree\n'.splitlines(1),  'ore\ntree\nemu\n'.splitlines(1))

>>> diff = list(diff) # materialize the generated delta into a list

>>> print ''.join(restore(diff, 1)),

>>> print ''.join(restore(diff, 2)),

--difflib.unified_diff(a, b[, fromfile][, tofile][, fromfiledate][, tofiledate][, n][, lineterm])   比较a与b(字符串列表),返回一个unified diff格式的差异结果.

>>> s1 = ['bacon\n', 'eggs\n', 'ham\n', 'guido\n']

>>> s2 = ['python\n', 'eggy\n', 'hamster\n', 'guido\n']

>>> for line in unified_diff(s1, s2, fromfile='before.py', tofile='after.py'):

实际应用示例

比对两个文件,然后生成一个展示差异结果的HTML文件

#coding:utf-8

'''

file:difflibeg.py

date:2017/9/9 10:33

author:lockey

email:[email protected]

desc:diffle module learning and practising

'''

import difflib

hd = difflib.HtmlDiff()

loads = ''

with open('G:/python/note/day09/0907code/hostinfo/cpu.py','r') as load:

 loads = load.readlines()

 load.close()

mems = ''

with open('G:/python/note/day09/0907code/hostinfo/mem.py', 'r') as mem:

 mems = mem.readlines()

 mem.close()

with open('htmlout.html','a+') as fo:

 fo.write(hd.make_file(loads,mems))

 fo.close()

运行结果:

这里写图片描述

生成的html文件比对结果:

这里写图片描述

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。


--37-----------Python 100例----------------------------------------------------------------------------------------------------------------------------

一.变量、表达式和语句

  Python中的语句也称作命令,比如print "hello python"这就是一条语句。

  表达式,顾名思义,是指用运算符将运算对象连接起来的式子,在Python中表达式是语句的一种(注意在C语言和Java中表达式是表达式,语句是语句,表达式不可能是语句)。举个例子,在Python中,"3+2"这是一个表达式,同时也是一条语句,但是在C和java中完全是两个不同的概念。

  变量,用来存储可变的值,同其他的解释型编程语言一样,在Python中使用变量不需要预先定义,也不需要定义其类型,只需要在使用时进行定义和初始化即可。比如:

i=3

print i

  另外,在Python中,同一变量名在不同阶段可以存储不同类型的数据(至于其中的缘由在以后会慢慢作解释)。比如:

i=3

print i

i='hello python'

print i

i=2.3

print i

  Python中的变量的命名规则同C语言中的变量命名规则基本一样。不过在Python中以下划线开始或者结束的变量名通常有特殊的意义,比如__name__这个是每个模块保留的内置属性。

##简单例子,推python运行原理,包含了两个文件 foo.py 和 demo.py

[foo.py]

def add(a, b):

return a + b

[demo.py] import foo

a = [1, 'python'] a = 'a string'

def func():

a = 1 b = 257

print(a + b)

print(a) if __name__ == '__main__': func() foo.add(1, 2)

执行这个程序

python demo.py

输出结果

a string 258

同时,该文件目录多出一个 foo.pyc 文件

## 命名空间 (namespace)

在介绍上面的这些代码时,还漏掉了一个关键的信息就是命名空间。在 Python 中,类、函数、module 都对应着一个独立的命名空间。而一个独立的命名空间会对应一个 PyCodeObject 对象,所以上面的 demo.py 文件编译后会生成两个 PyCodeObject,只是在 demo.py 这个 module 层的 PyCodeObject 中通过一个变量符号 func 嵌套了一个函数的 PyCodeObject。

命名空间的意义,就是用来确定一个变量符号到底对应什么对象。命名空间可以一个套一个地形成一条命名空间链,Python 虚拟机在执行的过程中,会有很大一部分时间消耗在从这条命名空间链中确定一个符号所对应的对象是什么。

在 Python中,命名空间是由一个 dict 对象实现的,它维护了(name,obj)这样的关联关系。

说到这里,再补充一下 import foo 这行代码会在 demo.py 这个模块的命名空间中,创建一个新的变量名 foo,foo 将绑定到一个 PyCodeObject 对象,也就是 foo.py 的编译结果。

--LEGB 规则

Python 使用 LEGB 的顺序来查找一个符号对应的对象

locals -> enclosing function -> globals -> builtins

locals,当前所在命名空间(如函数、模块),函数的参数也属于命名空间内的变量

enclosing,外部嵌套函数的命名空间(闭包中常见)

def fun1(a): def fun2(): # a 位于外部嵌套函数的命名空间 print(a)

globals,全局变量,函数定义所在模块的命名空间

a = 1 def fun(): # 需要通过 global 指令来声明全局变量 global a # 修改全局变量,而不是创建一个新的 local 变量 a = 2

builtins,内置模块的命名空间。Python 在启动的时候会自动为我们载入很多内置的函数、类,比如 dict,list,type,print,这些都位于 __builtins__ 模块中,可以使用 dir(__builtins__) 来查看。这也是为什么我们在没有 import 任何模块的情况下,就能使用这么多丰富的函数和功能了。

介绍完命名空间,就能理解 print(a) 这行代码输出的结果为什么是 a string 了。

--内置属性 __name__

现在到了解释 if __name__ == '__main__' 这行代码的时候了。当 Python 程序启动后,Python 会自动为每个模块设置一个属性 __name__ 通常使用的是模块的名字,也就是文件名,但唯一的例外是主模块,主模块将会被设置为 __main__。利用这一特性,就可以做一些特别的事。比如当该模块以主模块来运行的时候,可以运行测试用例。而当被其他模块 import 时,则只是乖乖的,提供函数和功能就好。

--动态类型

继续看函数 func 里面的代码,这时又有一条赋值语句 a = 1。变量 a 现在已经变成了第三种类型,它现在是一个整数了。那么 Python 是怎么实现动态类型的呢?答案就藏在具体存储的对象上。变量 a 仅仅只是一个符号(实际上是一个字符串对象),类型信息是存储在对象上的。在 Python 中,对象机制的核心是类型信息和引用计数(引用计数属于垃圾回收的部分)。

用 type(a),可以输出 a 的类型,这里是 int

b = 257 跳过,我们直接来看看 print(a + b),print 是输出函数,这里略过。这里想要探究的是 a + b。

因为 a 和 b 并不存储类型信息,因此当执行 a + b 的时候就必须先检查类型,比如 1 + 2 和 "1" + "2" 的结果是不一样的。

看到这里,我们就可以想象一下执行一句简单的 a + b,Python 虚拟机需要做多少繁琐的事情了。首先需要分别检查 a 和 b 所对应对象的类型,还要匹配类型是否一致(1 + "2" 将会出现异常),然后根据对象的类型调用正确的 + 函数(例如数值的 + 或字符串的 +),而 CPU 对于上面这条语句只需要执行 ADD 指令(还需要先将变量 MOV 到寄存器)。

--小整数对象池

在 demo.py 这里例子中,所用的整数特意用了一个 257,这是为了介绍小整数对象池的。整数在程序中的使用非常广泛,Python 为了优化速度,使用了小整数对象池,避免为整数频繁申请和销毁内存空间。

Python 对小整数的定义是 [-5, 257),这些整数对象是提前建立好的,不会被垃圾回收。在一个 Python 的程序中,所有位于这个范围内的整数使用的都是同一个对象,从下面这个例子就可以看出。

>>> a = 1 >>> id(a) 40059744 >>> b = 1 >>> id(b) 40059744 >>> c = 257 >>> id(c) 41069072 >>> d = 257 >>> id(257) 41069096

id 函数可以用来查看一个对象的唯一标志,可以认为是内存地址

对于大整数,Python 使用的是一个大整数对象池。这句话的意思是:

每当创建一个大整数的时候,都会新建一个对象,但是这个对象不再使用的时候,并不会销毁,后面再建立的对象会复用之前已经不再使用的对象的内存空间。(这里的不再使用指的是引用计数为0,可以被销毁)

--字符串对象缓冲池

如果仔细思考一下,一定会猜到字符串也采用了这种类似的技术,我们来看一下

>>> a = 'a' >>> b = 'a' >>> id(a) 14660456 >>> id(b) 14660456

没错,Python 的设计者为一个字节的字符对应的字符串对象 (PyStringObject) 也设计了这样一个对象池。同时还有一个 intern 机制,可以将内容相同的字符串变量转换成指向同一个字符串对象。

intern 机制的关键,就是在系统中有一个(key,value)映射关系的集合,集合的名称叫做 interned。在这个集合中,记录着被 intern 机制处理过的 PyStringObject 对象。不过 Python 始终会为字符串创建 PyStringObject 对象,即便在interned 中已经有一个与之对应的 PyStringObject 对象了,而 intern 机制是在字符串被创建后才起作用。

>>> a = 'a string' >>> b = 'a string' >>> a is b False >>> a = intern('a string') # 手动调用 intern 方法 >>> b = intern('a string') >>> a is b True

关于 intern 函数 可以参考官方文档,更多扩展阅读:

http://stackoverflow.com/questions/15541404/python-string-interning

值得说明的是,数值类型和字符串类型在 Python 中都是不可变的,这意味着你无法修改这个对象的值,每次对变量的修改,实际上是创建一个新的对象。得益于这样的设计,才能使用对象缓冲池这种优化。

Python 的实现上大量采用了这种内存对象池的技术,不仅仅对于这些特定的对象,还有专门的内存池用于小对象,使用这种技术可以避免频繁地申请和释放内存空间,目的就是让 Python 能稍微更快一点。更多内容可以参考这里。

如果想了解更快的 Python,可以看看 PyPy

--垃圾回收

在讲到垃圾回收的时候,通常会使用引用计数的模型,这是一种最直观,最简单的垃圾收集技术。Python 同样也使用了引用计数,但是引用计数存在这些缺点:

? 频繁更新引用计数会降低运行效率

? 引用计数无法解决循环引用问题

Python 在引用计数机制的基础上,使用了主流垃圾收集技术中的标记——清除和分代收集两种技术。

关于垃圾回收,可以参考

http://hbprotoss.github.io/posts/pythonla-ji-hui-shou-ji-zhi.html

2. 背后的魔法

看完程序的执行结果,接下来开始一行行解释代码。

2.7 绝对引入和相对引入

前文已经介绍了 import foo 这行代码。这里隐含了一个问题,就是 foo 是什么,如何找到 foo。这就属于 Python 的模块引入规则,这里不展开介绍,可以参考 pep-0328。

2.8 赋值语句

接下来,执行到 a = [1, 'python'],这是一条赋值语句,定义了一个变量 a,它对应的值是 [1, 'python']。这里要解释一下,变量是什么呢?

按照[维基百科]("https://en.wikipedia.org/wiki/Variable_(computer_science") 的解释

变量是一个存储位置和一个关联的符号名字,这个存储位置包含了一些已知或未知的量或者信息。

变量实际上是一个字符串的符号,用来关联一个存储在内存中的对象。在 Python 中,会使用 dict(就是 Python 的 dict 对象)来存储变量符号(字符串)与一个对象的映射。

那么赋值语句实际上就是用来建立这种关联,在这个例子中是将符号 a 与一个列表对象 [1, 'python'] 建立映射。

紧接着的代码执行了 a = 'a string',这条指令则将符号 a 与另外一个字符串对象 a string 建立了映射。今后对变量 a 的操作,将反应到字符串对象 a string 上。

4. 参考文献

? Python 源码剖析

? Python 官方文档

-------------Python数据分析几个比较常用的方法

##--1,表头或是excel的索引如果是中文的话,输出会出错

解决方法:  python的版本问题!换成python3就自动解决了!当然也有其他的方法,这里就不再深究

##--2,如果有很多列,如何输出指定的列?

需求情况:  有的时候,数据很多,但是只要仅仅对部分列的数据进行分析的话,要怎么做?

解决方法:

df = pandas.read_excel('1.xls',sheetname= '店铺分析日报')

df = df.loc[:,['关键词','带来的访客数','跳失率']] #访问指定的列

一行读取数据,第二行访问指定列

##--3,如何为数据框添加新的列?

需求情况:  有一个表格,里面的列是单价,数量,想再输出一个总价的列,或是对一些数据进行总结

解决方法:  直接上代码

from pandas import read_csv;

import pandas;

df = read_csv("1.csv", sep="|");

#把计算结果添加为一个新的列

df['result'] = df.price*df.num     #新的列名,后面是对应的数值

print (df)

##--4,如何对百分号的数值进行计算,再将其输出

需求情况:  比较蛋疼的一个情况,电商很多数据都是百分比的,带有百分号,不能进行直接的计算,需要对其进行转换,然后再输出

解决方法:

from pandas import read_csv;

import pandas;

df = read_csv("1.csv", sep="|");

f = df['跳失率'].str.strip("%").astype(float)/100;

f.round(decimals=2)  #保留小数点后面2位

f_str = f.apply(lambda x: format(x, '.2%'));  #再转换成百分号并且保留2位数(精度可以调整)

df['跳失率'] = f_str     #重新赋值

##--5,如何获取导入的数据有几行和几列(数值)

需求情况:  有的时候需要写一个通用脚本,比如随机抽样分析,程序自动获取行和列的话,写出来的脚本通用性明显会很强

解决方法:

df.columns.size   #获取列数

df.iloc[:, 0].size  #获取行数

##--6,如何对数据进行排序

需求情况:  这个就不用说了,到处都要用到

解决方法:

df['跳失率'].size   #对数据进行排序

newDF = df.sort(['曝光量', '带来的访客数'], ascending=[True, False]);  #多重排序

##--7,如何删除指定的列?

需求情况:  同样,十几列的数据,如果你想获取指定的输出数据,可以用方法2,但是如果想要获取的数据列比较多,只有1-2行不想要,这样就可以用指定删除列的方法了

解决方法:

df.columns.delete(1)

一行代码搞定!

总结:  整体来说的,python的语法在做数据分析还是相当简单的,很多的需求基本上就是一行代码搞定!

##--8,如何添加整行数据?

df.append([1,2,34,,5])


--python中的__slots__使用示例

__slots__  用来限制class能添加的属性

正常情况下,当定义了一个class,创建了一个class的实例后,可以给该实例绑定任何属性和方法,这就是动态语言的灵活性。

先定义class:

>>> class Staff(object):

...     pass

...

然后,尝试给实例绑定一个属性:

>>> s = Staff()

>>> s.name = 'jack'

>>> print s.name        #jack

>>>

还可以尝试给实例绑定一个方法:

>>> def set_age(self,age):

...     self.age = age

...

>>> from types import MethodType

>>> s.set_age = MethodType(set_age, s, Staff)

>>> s.set_age(34)

>>> s.age         #34

但是,给一个实例绑定的方法,对另一个实例是不起作用的:

>>> s2 = Staff()

>>> s2.set_age(35)

Traceback (most recent call last):

  File "", line 1, in

AttributeError: 'Staff' object has no attribute 'set_age'

为了给所有实例都绑定方法,可以给class绑定方法:

>>> def set_score(self, score):

...     self.score = score

...

>>> Staff.set_score = MethodType(set_score, None, Staff)

给class绑定方法后,所有实例均可调用:

>>> s.set_score(100)

>>> s.score      #100

>>> s2.set_score(99)

>>> s2.score      #99

通常情况下,上面的set_score方法可以直接定义在class中,但动态绑定允许我们在程序运行的过程中动态给class加上功能,这在静态语言中很难实现。

使用__slots__

但是,如果我们想要限制class的属性怎么办?比如,只允许对Staff实例添加name和age属性。

为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class能添加的属性:

>>> class Staff(object):

...     __slots__ = ('name', 'age')

...

然后,我们试试:

>>> s = Staff()

>>> s.name = 'jack'

>>> s.age = 34

>>> s.score = 99

Traceback (most recent call last):

  File "", line 1, in

AttributeError: 'Staff' object has no attribute 'score'

由于‘sorce'没有被放到__slots__中,所以不能绑定score属性,试图绑定score将得到AttributeError的错误。

使用__slots__要注意,__slots__定义的属性仅对当前类起作用,对继承的子类是不起作用的:

>>> class GraduateStaff(Staff):

...     pass

...

>>> g = GraduateStaff()

>>> g.score = 9999

>>> g.score

9999

除非在子类中也定义__slots__,这样,子类允许定义的属性就是自身的__slots__加上父类的__slots__。



--********************************************************************************************************************************

--python循环控制----------------------------------------------------------------------------

--********************************************************************************************************************************

--条件语句 if else-----------------------------------------------------------------------------------------------------------------

--循环语句 while--for--break--continue--pass----------------------------------------------------------------------------------------