python学习笔记
1.1 先编辑成.pyc字节码文件,源代码底层的、平台无关的表现形式
1.2 然后发送到PVM python虚拟机
1.3. 程序开始之前不需要预编译和连接,是python具有更多的动态语言特性:可以运行时构建和运行另一个python程序(如eval,exec)
1.4. cpython;jpython(与java集成);ironpython(与.net等集成)
1.5. 冻结二进制文件,使用py2exe之类的系统,冻结二进制文件中内置了pvm,所以会变大
1.6. 如何制作unix可执行脚本
1.6.1. #! /usr/local/bin/python3 (或者#!/usr/local/bin/env python)
1.6.2. chmod +x
1.7. windows中点击自动运行的python文件需要添加input()
1.8. 属性就是绑定在特定的对象上的变量名;dir可以获取此le
1.9. exec(open(../testunixrun.py).read()) exec运行相当于粘贴了代码运行
1.10 help(dir)打印帮助文档
调用解释器时,脚本名和附加参数传入一个名为 sys.argv 的字符串列表。
BSD 类的 Unix 系统中,Python 脚本可以像 Shell 脚本那样直接执行。只要在脚本文件开头写一行命令,指定文件和模式
#! /usr/bin/env python3.3
默认情况下,Python 源文件是 UTF-8 编码。你也可以为源文件指定不同的字符编码。 为此,在 #! 行(首行)后插入至少一行特殊的注释行来定义源文件的编码。
# -*- coding: encoding -*-
Python 提供了两个钩子(方法)来本地化: sitecustomize 和 usercustomize。
sitecustomize.py 是python中的一个特殊脚本,可以放在目录下的任意位置,不过一般放在home\Lib\site-packages下面,当python开始运行时会先运行该脚本中的代码,因此可以用来设置一些default的东西。
//
oct(64),hex(64),bin(64) #('0o100', '0x40', '0b1000000')
int('100000',2),int('40',8)# (32,32)
eval('0b100000'),eval('0O40')# (32,32)'{0:b},{1:o}'.format(32,32)#'100000,40'
"""
或 '''
。三引号中,不需要行属转义,它们已经包含在字符串中aStr = r"/n"
word = 'Help' + 'A' #或word = 'Help' 'A'
words = '<' + word*5 + '>'
word[:2]/word[:-2]
;内置函数 len()
返回字符串长度#切片位置图
+---+---+---+---+---+
| H | e | l | p | A |
+---+---+---+---+---+
(-)0 1 2 3 4 5
-5 -4 -3 -2 -1
ord()
chr()
>>> B = b'spam'# Make a bytes object (8-bit bytes)>>> S = 'eggs'# Make a str object (Unicode characters, 8-bit or wider)>>> type(B), type(S)#(<class 'bytes'>, <class 'str'>)
//转换
>>> a = "好">>> a.encode('utf-8') #b'\xe5\xa5\xbd'>>> b = b'\xe5\xa5\xbd' #list(b)[229, 165, 189]>>> b.decode('utf-8') #'好'>>> str(b)#"b'\\xe5\\xa5\\xbd'" #不带编码的一个s t r调用返回b y t e s对象的打印字符串,而不是其 str转换后的形式>>> str(b,encoding="utf-8")#'好'
//系统默认编码
sys.getdefaultencoding()
//区别unicode str和真正的bytes Unicode只是一个符号集UTF-8是在互联网上使用最广的一种Unicode的实现方式 http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html
>>> S = '\u550d'#'唍' 这个unicode编码 是 '唍' >>> '唍'.encode("utf-8")#b'\xe5\x94\x8d' 当这个字 用utf-8编码实现的时候是 '\xe5\x94\x8d'
Python 3.0 开始所有的字符串都支持 Unicode
>>> 'Hello\u0020World !''Hello World !'
>>> "Äpfel".encode('utf-8')
b'\xc3\x84pfel'
a[:2] + ['bacon', 2*2]
>>> a[:]
['spam', 'eggs', 100, 1234]
a[1:1] = ['bletch', 'xyzzy'] # Insert some:
a[0:2] = [] # Remove some:
append
在列表末尾添加内容;len()
返回长度>>> a = '1',b = a, a = 2#b没有改变 字符串和整数都是不可变的,修改的时候改变了引用的对象(a='1',b='1',a is b:true) sys.getrefcount(1) 1,‘1’会被复用>>> a = [],b= a , a.append(1)#b也改变了,对象还是同一个(可变对象) >>> a= [1],b= a[:], a.append(2)#b不变,两个指向的是不同的对象 >>> c=[a],d=c[:],c[0].append(2)#d也变了 这个copy不是deepcopy 里面都是a>>> c=[a],d=copy.deepcopy(c),c[0].append(2)#d不变了 是deepcopy 会嵌套copy
>>> a, b = 0, 1 #多重赋值>>> while b < 10:
... print(b)
... a, b = b, a+b #变量赋值前,右边首先完成计算。右边的表达式从左到右计算
if x < 0:
for x in a:
for i in range(5):;
range(0, 10, 3)
for i in range(len(a)):
#range 是一个可迭代对象;为了节省空间,它并不真正构造列表>>> list(range(5))
[0, 1, 2, 3, 4]
循环可以有一个 else 子句;它在循环迭代完整个列表(对于 for )或执行条件为 false (对于 while )时执行,但循环被 break 中止的情况下不会执行。
>>> for n in range(2, 10):
... for x in range(2, n):
... if n % x == 0:
... print(n, 'equals', x, '*', n//x)
... break... else:
... # loop fell through without finding a factor... print(n, 'is a prime number')
pass 语句什么也不做。它用于那些语法上必须要有什么语句,但程序什么也不做的场合
>>> def fib(n): # write Fibonacci series up to n... """Print a Fibonacci series up to n.""" #docstring... a, b = 0, 1... while a < n:
... print(a, end=' ')
... a, b = b, a+b
... #return None 默认return None
...
函数的作用:增加代码重用,减少代码冗余;分解流程.函数也是对象.
模块
中的全局变量->python内置变量LEGB
gcount = 0 #global域 模块顶层文件 gcount和函数global_counter都是global的def global_counter():
global gcount #如果不是要修改 global可以不写 直接引用
gcount +=1
return gcount
def make_counter():
count = 0
def counter():
nonlocal count
count += 1
return count
return counter
>>> def createGenerator() :... mylist = range(3)
... for i in mylist :
... yield i*i
...
>>> mygenerator = createGenerator() # create a generator>>> print(mygenerator) # mygenerator is an object!
<generator object createGenerator at 0xb7555c34>
>>> for i in mygenerator:
... print(i)
if a:
def fun():
else:
def fun()
fun()
fun.attr = value
def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
重要警告
: 默认值只被赋值一次。这使得当默认值是可变对象时会有所不同,比如列表、字典或者大多数类的实例。
def f(a, L=[]):
L.append(a)
return L
print(f(1))#[1]
print(f(2))#[1, 2]
print(f(3))#[1, 2, 3]
#如果你不想让默认值在后续调用中累积,你可以像下面一样定义函数:def f(a, L=None):
if L is None:
L = []
L.append(a)
return L
引入一个形如 **name 的参数时,它接收一个字典,该字典包含了所有未出现在形式参数列表中的关键字参数。这里可能还会组合使用一个形如 *name的形式参数,它接收一个元组,包含了所有没有出现在形式参数列表中的参数值。(*name 必须在 **name 之前出现) 例如,我们这样定义一个函数:
def cheeseshop(kind, *arguments, **keywords):
print("-- Do you have any", kind, "?")
print("-- I'm sorry, we're all out of", kind)
for arg in arguments:
print(arg)
keys = sorted(keywords.keys())
for kw in keys:
print(kw, ":", keywords[kw])
#调用
cheeseshop("Limburger", "It's very runny, sir.","It's really very, VERY runny, sir.",
shopkeeper="Michael Palin",client="John Cleese",sketch="Cheese Shop Sketch")
def f(a,*pargs,**kargs):print(a,pargs,kargs) #提取参数到a-》元组pargs-》字典kargs
>>>f(1,2,3,x = 4, y = 5)
1,(2,3),{'x':4,'y':5}
另有一种相反的情况: 当你要传递的参数已经是一个列表,但要调用的函数却接受分开一个个的参数值。这时候你要把已有的列表拆开来. 你可以在调用函数时加一个 * 操作符来自动把参数列表拆开,以同样的方式,可以使用 ** 操作符分拆关键字参数为字典:
>>> args = [3, 6]
>>> list(range(*args))
>>> def parrot(voltage, state='a stiff', action='voom'):... print("-- This parrot wouldn't", action, end=' ')
... print("if you put", voltage, "volts through it.", end=' ')
... print("E's", state, "!")
...
>>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"}
>>> parrot(**d)
>>> def make_incrementor(n):... return lambda x: x + n
...
>>> f = make_incrementor(42)
>>> f(0)
42
//默认参数也能在lambda中使用
>>>f = (lambda a =1,b=2,c=3:a+b+c)
>>>f(2) #7
L = [lambda x:x**2,lambda x:x**3,lambda x:x**4]
for f in L:print(f(2))
参考标准库写法
//一个小例子
def sum(L):
return L[0] if len(L) == 1 else return L[0] + sum(L[1:])
>>>def fun():a=1
>>>dir(fun.__code__)
>>>print(fun.__name__)
>>>fun.__code__.co_varnames #('a',)
type()获得元素,变量类型 返回class(3.0);注意使用type并不是pythonic的思维,应该关注接口,而不是关注类型
//3种方法判断 类型if type(L) == type([])
if type(L) == listif isinstance(L,list)
list.append(x)
把一个元素添加到链表的结尾,相当于 a[len(a):] = [x]
。list.extend(L)
将一个给定列表中的所有元素都添加到另一个列表中,相当于 a[len(a):] = L
。list.insert(i, x)
在指定位置插入一个元素。第一个参数是准备插入到其前面的那个元素的索引,例如 a.insert(0, x) 会插入到整个链表之前,而 a.insert(len(a), x) 相当于 a.append(x) 。list.remove(x)
删除链表中值为 x 的第一个元素。如果没有这样的元素,就会返回一个错误。list.pop([i])
从链表的指定位置删除元素,并将其返回。如果没有指定索引, a.pop() 返回最后一个元素。元素随即从链表中被删除。(方法中 i 两边的方括号表示这个参数是可选的)list.index(x)
返回链表中第一个值为 x 的元素的索引。如果没有匹配的元素就会返回一个错误。list.count(x)
返回 x 在链表中出现的次数。list.sort()
对链表中的元素就地进行排序。list.reverse()
就地倒排链表中的元素。使用list的append()+ pop()
可以使用list的insert(0,x) + pop()但是这样效率很低,正确的做法是使用collections.deque
的append()
+popleft()
列表推导式为从序列中创建列表提供了一个简单的方法squares
相当于
= [x**2 for x in range(10)]squares = map(lambda x: x**2, range(10))
>>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
# flatten a list using a listcomp with two 'for'>>> vec = [[1,2,3], [4,5,6], [7,8,9]]
>>> [num for elem in vec for num in elem]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> matrix = [
... [1, 2, 3, 4],
... [5, 6, 7, 8],
... [9, 10, 11, 12],
... ]
>>> [[row[i] for row in matrix] for i in range(4)]
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
>>> list(zip(*matrix))#参数列表的分拆
[(1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12)]
有个方法可以从列表中按给定的索引而不是值来删除一个子项:
。语句 del 还可以从列表中删除切片或清空整个列表。
del 语句del a[0]
= a[0:1] = []
>>> a = [-1, 1, 66.25, 333, 333, 1234.5]
>>> del a[0]
>>> del a[2:4]
>>> del a[:]
>>> a
[]
>>> del a #再次引用a将发生错误
一个元组由数个逗号分隔的值组成(另参考namedtuple)
>>> t = 12345, 54321, 'hello!' # 一个元素的元组需要后面加, >>> singleton = 'hello',>>> t[0]
12345>>> # Tuples may be nested:... u = t, (1, 2, 3, 4, 5)
>>> # Tuples are immutable:... t[0] = 88888
TypeError: 'tuple' object does not support item assignment
>>> # but they can contain mutable objects:... v = ([1, 2, 3], [3, 2, 1])
python 3 后元组还加了 t.index('a');t.count('a')元组除了使用方便之外,不可变性的约束也是重要的使用原因
Python 还包含了一个数据类型—— set (集合) 。集合是一个无序不重复元素的集。基本功能包括关系测试和消除重复元素。集合对象还支持 union(联合),intersection(交),difference(差)和 sysmmetric difference(对称差集)等数学运算。
大括号或 set() 函数可以用来创建集合。 注意:想要创建空集合,你必须使用 set() 而不是 {} 。后者用于创建空字典。
>>> basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
>>> 'orange' in basket # fast membership testingTrue>>> # Demonstrate set operations on unique letters from two words
...
>>> a = set('abracadabra')
>>> b = set('alacazam')
>>> a # unique letters in a>>> a - b # letters in a but not in b 《=》{x for x in a if x not in b}>>> a | b # letters in either a or b>>> a & b # letters in both a and b>>> a ^ b # letters in a or b but not both
#集合也可以使用解析构造>>> a = list(range(97,107))
>>> b = [chr(x) for x in a]#['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']>>> c = {chr(x) for x in a}#{'a', 'h', 'e', 'f', 'g', 'j', 'b', 'i', 'd', 'c'}>>> d = {chr(x):x for x in a}#{'i':105,'h':104,'a':97,'g':103,'d':100,'e':101,'f':102,'j':106, 'c':99,'b':98}
无序的键: 值对 (key:value pairs)集合
因为字典的key可以是任何不可变的对象,比如数字,字典可以模拟list而且比list更灵活(如不用担心越界,稀疏矩阵)
>>> tel = {'jack': 4098, 'sape': 4139} # 创建方法1>>> dict(sape=4139, guido=4127, jack=4098) # 创建方法2
{'sape': 4139, 'jack': 4098, 'guido': 4127}
>>> tel['guido'] = 4127 # set value for key>>> del tel['sape'] # del a pair of key-value>>> list(tel.keys()) # ['irv', 'guido', 'jack']>>> 'guido' in tel # <=> 'guido' in tel.keys()True#dict() 构造函数可以直接从 key-value 对中创建字典:>>> dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])# 创建方法3#字典推导式可以从任意的键值表达式中创建字典:>>> {x: x**2 for x in (2, 4, 6)} # 创建方法4
{2: 4, 4: 16, 6: 36}
字典key没有直接访问会出错,使用判断或者使用get语句。
#D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.
value = D.get("key",0)
value = D["key"] if key in D else 0
iteritems()
方法同时解读出来。>>> knights = {'gallahad': 'the pure', 'robin': 'the brave'}
>>> for k, v in knights.items():
... print(k, v)
...
enumerate()
函数同时得到。>>> for i, v in enumerate(['tic', 'tac', 'toe']):
... print(i, v)
...
zip()
整体打包。>>> questions = ['name', 'quest', 'favorite color']
>>> answers = ['lancelot', 'the holy grail', 'blue']
>>> for q, a in zip(questions, answers):
... print('What is your {0}? It is {1}.'.format(q, a))
...
reversed()
函数。>>> for i in reversed(range(1, 10, 2)):
... print(i)
...
sorted()
函数,它不改动原序列,而是生成一个新的已排序的序列。(不同于list.sort(),后者是原地排序)>>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
>>> for f in sorted(set(basket)):
... print(f)
...
in
和 not in
审核值是否在一个区间之内。操作符 is
和 is not
比较两个对象是否相同
;这只和诸如链表这样的可变对象有关。所有的比较操作符具有相同的优先级,低于所有的数值操作。and
和 or
组合,比较的结果可以用 not 来取反义。not 具有最高的优先级, or 优先级最低, A and not B or C 等于 (A and (notB)) or C ,这些操作符的优先级低于比较操作符。序列对象可以与相同类型的其它对象比较。比较操作按
进行:首先比较前两个元素,如果不同,就决定了比较的结果;如果相同,就比较后两个元素,依此类推,直到所有序列都完成比较。如果两个元素本身就是同样类 型的序列,就递归字典序比较。如果两个序列的所有子项都相等,就认为序列相等。如果一个序列是另一个序列的初始子序列,较短的一个序列就小于另一个。字符 串的字典序按照单字符的 ASCII 顺序。
字典序
X是一个可以迭代的对象比如X = iter([1,2,3]) next(X)<=> X.\_\_next\_\_() (文件的iter就是自己)
for x in [1,2,3]:
print(x)
<=>
I = iter([1,2,3])
while True:
try:x = next(I)
except StopIteration:break
print(x)
(1):next 执行到一个yield。然后程序返回。并且挂起。此时所有的状态被保留。如全局变量(=send(None))
(2):send(msg) 从上次挂起的yield那边开始执行。并且把msg赋值给yield的表达式。例如上一次是在 m = yield 5断掉。那么send(10),m将被赋值成10.然后继续执行,直到执行到下一个yield。然后依然挂起。所以不能在第一次调用的时候,就send,因为这个时候,根本就还没有执行到任何的yield。
(3)throw(type[, value[, traceback]]),可以抛出指定异常终止程序
(4):close(). 其实就是执行throws(GeneratorExit)
>>> def gen():
for i in range(10):
x = yield i
print("x:",x)
>>> g = gen()
>>> next(g)
0>>> next(g)
x: None1>>> g.send(100)
x: 1002
注意没有元组解析
>>> (x**2 for x in range(10))//生成器
<generator object <genexpr> at 0x10414c090>
>>> tuple((x**2 for x in range(10)))//没有元组解析
(0, 1, 4, 9, 16, 25, 36, 49, 64, 81)
>>> [x**2 for x in range(10)]//列表解析
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> {x**2 for x in range(10)}//集合解析
{0, 1, 64, 4, 36, 9, 16, 49, 81, 25}
>>> {x:x**2 for x in range(10)}//字典解析
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
模块是包括 Python 定义和声明的文件。文件名就是模块名加上 .py 后缀。模块的模块名(做为一个字符串)可以由全局变量
得到。
__name__
>>> import fibo
>>> fibo.__name__
'fibo'>>> fib = fibo.fib #如果打算频繁使用一个函数,你可以将它赋予一个本地变量>>> fib(500
每个模块都有自己私有的符号表,被模块内所有的函数定义作为全局符号表
使用。 因此,可以在模块内部使用全局变量,而无需担心它与某个用户的全局变量意外冲突。可以使用引用模块函数的表示法访问模块的全局变量, modname.itemname 。
模块可以导入其他的模块。 一个(好的)习惯是将所有的 import 语句放在模块的开始,但非强制。 被导入的模块名会放入当前模块的全局符号表中。
模块的其他导入方法:
#import 语句的一个变体直接从被导入的模块中导入命名到本模块的语义表中。例如:>>> from fibo import fib, fib2
#导入模块中的所有定义,这样可以导入所有除了以下划线( _ )开头的命名。>>> from fibo import *
#需要注意的是在实践中往往不鼓励从一个模块或包中使用 * 导入所有,因为这样会让代码变得很难读。不过,在交互式会话中这样用很方便省力。# Note 出于性能考虑,每个模块在每个解释器会话中只导入一遍。因此,如果你修改了你的模块,需要重启解释器——或者,如果你就是想交互式的测试这么一个模块,可以用 reload() 重新加载,例如 reload(modulename) 。
当你使用以下方式运行 Python 模块时,模块中的代码便会被执行:
python fibo.py <arguments>
模块中的代码会被执行,就像导入它一样,不过此时 name 被设置为 "main" 。这相当于,如果你在模块后加入如下代码:
if __name__ == "__main__":
import sys
fib(int(sys.argv[1]))
这通常用来为模块提供一个便于测试的用户接口(将模块作为脚本执行测试需求)。
导入一个叫 spam 的模块时,解释器先在当前目录中搜索名为 spam.py 的文件。如果没有找到的话,接着会到 sys.path 变量中给出的目录列表中查找。 sys.path 变量的初始值来自如下:
对于引用了大量标准模块的短程序,有一个提高启动速度的重要方法,如果在 spam.py 所在的目录下存在一个名为 spam.pyc 的文件,它会被视为 spam 模块的预“编译”( byte-compiled ,二进制编译)版本。用于创建 spam.pyc 的这一版 spam.py 的修改时间记录在 spam.pyc 文件中,如果两者不匹配,.pyc 文件就被忽略。
部分高级技巧:
以 -O 参数调用 Python 解释器时,会生成优化代码并保存在 .pyo 文件中。现在的优化器没有太多帮助;它只是删除了断言( assert )语句。使用 -O 参数, 所有 的字节码( bytecode )都会被优化; .pyc 文件被忽略, .py 文件被编译为优化代码。
向 Python 解释器传递两个 -O 参数( -OO )会执行完全优化的二进制优化编译,这偶尔会生成错误的程序。现在的优化器,只是从字节码中删除了 doc 符串,生成更为紧凑的 .pyo 文件。因为某些程序依赖于这些变量的可用性,你应该只在确定无误的场合使用这一选项。
来自 .pyc 文件或 .pyo 文件中的程序不会比来自 .py 文件的运行更快; .pyc 或 .pyo 文件只是在它们加载的时候更快一些。
通过脚本名在命令行运行脚本时,不会将为该脚本创建的二进制代码写入 .pyc 或 .pyo 文件。当然,把脚本的主要代码移进一个模块里,然后用一个小的启动脚本导入这个模块,就可以提高脚本的启动速度。也可以直接在命令行中指定一个 .pyc 或 .pyo 文件。
对于同一个模块(这里指例程 spam.py),可以只有 spam.pyc 文件(或者 spam.pyc ,在使用 -O 参数时)而没有 spam.py 文件。这样可以打包发布比较难于逆向工程的 Python 代码库。
compileall 模块可以为指定目录中的所有模块创建 .pyc 文件(或者使用 -O 参数创建 .pyo 文件)。
Python 带有一个标准模块库,并发布有独立的文档,名为 Python 库参考手册(此后称其为“库参考手册”)。有一些模块内置于解释器之中,这些操作的访问接口不是语言内核的一部分,但是已经内置于解释器了。这既是为了提高效率,也是为了给系统调用等操作系统原生访问提供接口。
内置函数 dir() 用于按模块名搜索模块定义,它返回一个字符串类型的存储列表;无参数调用时, dir() 函数返回当前定义的命名;会列出所有类型的名称:变量,模块,函数,等等。dir() 不会列出内置函数和变量名。如果你想列出这些内容,它们在标准模块__builtin__
中定义。
包通常是使用用“圆点模块名”的结构化模块命名空间。正如同用模块来保存不同的模块架构可以避免全局变量之间的相互冲突,使用圆点模块名保存像 NumPy 或 Python Imaging Library 之类的不同类库架构可以避免模块之间的命名冲突。
需要注意的是使用 from package import item 方式导入包时,这个子项(item)既可以是包中的一个子模块(或一个子包),也可以是包中定义的其它命名,像函数、类或变量。import 语句首先核对是否包中有这个子项,如果没有,它假定这是一个模块,并尝试加载它。如果没有找到它,会引发一个 ImportError 异常。相反,使用类似 import item.subitem.subsubitem 这样的语法时,这些子项必须是包,最后的子项可以是包或模块,但不能是前面子项中定义的类、函数或变量。
执行 from package import 时,如果包中的
代码定义了一个名为
__init__.py__all__
的列表,就会按照列表中给出的模块名进行导入。如果没有定义 __all__
, from Sound.Effects import 语句 不会 从 sound.effects 包中导入所有的子模块。
__all__ = ["echo", "surround", "reverse"]
#这意味着 from Sound.Effects import * 语句会从 sound 包中导入以上三个已命名的子模块。
两种输出到终端的方式
:直接使用表达式语句 和 print() 函数。(第三种访求是使用文件对象的 write() 方法)
有两种方法可以格式化你的输出
: 第一种方法是由你自己处理整个字符串,通过使用字符串切割和连接操作。 第二种方法是使用
方法。
str.format()
>>> s = 'The value of x is ' + repr(x) + ', and y is ' + repr(y) + '...'
The value of x is 32.5, and y is 40000...
# 有两种方式可以写平方和立方表:>>> for x in range(1, 11):
... print(repr(x).rjust(2), repr(x*x).rjust(3), end=' ')
... # Note use of 'end' on previous line... print(repr(x*x*x).rjust(4))
>>> for x in range(1, 11):
... print('{0:2d} {1:3d} {2:4d}'.format(x, x*x, x*x*x))
...
#(注意 print 在每列之间加了一个空格,它总是在参数间加入空格。)
>>> print('We are the {} who say "{}!"'.format('knights', 'Ni'))
>>> print('{0} and {1}'.format('spam', 'eggs'))#spam and eggs>>> print('{1} and {0}'.format('spam', 'eggs'))#eggs and spam>>> print('This {food} is {adjective}.'.format(
... food='spam', adjective='absolutely horrible'))
>>> print('The story of {0}, {1}, and {other}.'.format('Bill', 'Manfred',
other='Georg'))
# '!a' (应用 ascii()), '!s' (应用 str() ) 和 '!r' (应用 repr() ) 可以在格式化之前转换值:>>> print('The value of PI is approximately {}.'.format(math.pi))
>>> print('The value of PI is approximately {!r}.'.format(math.pi))
#字段名后允许可选的 ':' 和格式指令。这允许对值的格式化加以更深入的控制。下例将 Pi 转为三位精度。在字段后的 ':' 后面加一个整数会限定该字段的最小宽度,这在美化表格时很有用。>>> print('The value of PI is approximately {0:.3f}.'.format(math.pi))#3.142.>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678}
>>> for name, phone in table.items():
... print('{0:10} ==> {1:10d}'.format(name, phone))
#如果你有个实在是很长的格式化字符串,不想分割它。如果你可以用命名来引用被格式化的变量而不是位置就好了。有个简单的方法,可以传入一个字典,用中括号访问它的键:>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
>>> print('Jack: {0[Jack]:d}; Sjoerd: {0[Sjoerd]:d}; '
'Dcab: {0[Dcab]:d}'.format(table))
#也可以用 ‘**’ 标志将这个字典以关键字参数的方式传入。>>> print('Jack: {Jack:d}; Sjoerd: {Sjoerd:d}; Dcab: {Dcab:d}'.format(**table))
#这种方式与新的内置函数 vars() 组合使用非常有效。该函数返回包含所有局部变量的字典。
如何将值转化为字符串
:函数 str() 用于将值转化为适于人阅读的形式,而 repr() 转化为供解释器读取的形式(如果没有等价的语法,则会发生 SyntaxError 异常) 某对象没有适于人阅读的解释形式的话, str() 会返回与 repr() 等同的值。
>>> # The repr() of a string adds string quotes and backslashes:... hello = 'hello, world\n'>>> hellos = repr(hello)
>>> print(hellos)
'hello, world\n'
print('The value of PI is approximately %5.3f.' % math.pi)
>>> f = open('/tmp/workfile', 'w')
#Windows 平台上文本文件与二进制文件是有区别的 b
f.read(size)
, size 是可选的数值,指定字符串长度。如果没有指定 size 或者指定为负数,就会读取并返回整个文件。如果到了文件末尾,f.read() 会返回一个空字符串(”“)。f.readline()
从文件中读取单独一行,字符串结尾会自动加上一个换行符( \n ),只有当文件最后一行没有以换行符结尾时,这一操作才会被忽略。这样返回值就不会有混淆,如果如果 f.readline() 返回一个空字符串,那就表示到达了文件末尾,如果是一个空行,就会描述为 '\n' ,一个只包含换行符的字符串。f.readlines()
返回一个列表,其中包含了文件中所有的数据行。如果给定了 sizehint 参数,就会读入多于一行的比特数,从中返回多行文本。>>> for line in f:
... print(line, end='')
f.write(string)
方法将 string 的内容写入文件,并返回写入字符的长度。f.tell()
返回一个整数,代表文件对象在文件中的指针位置,该数值计量了自文件开头到指针处的比特数。需要改变文件对象指针话话,使用 f.seek(offset,from_what)
。f.close()
方法就可以关闭它并释放其占用的所有系统资源。 在调用 f.close() 方法后,试图再次使用文件对象将会自动失败。>>> with open('/tmp/workfile', 'r') as f:
... read_data = f.read()
isatty()
和 truncate()
在库参考手册中有文件对象的完整指南。pickle.dump(x, f)
x = pickle.load(f)
Python 中(至少)有两种错误:语法错误和异常(syntax
和
errorsexceptions
)
语法错误,也被称作解析错误
运行期检测到的错误称为 异常;可以被处理。
for arg in sys.argv[1:]:
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except IOError as err:
print("I/O error: {0}".format(err))
except ValueError: #注:用户产生的中断会引发一个KeyboardInterrupt 异常。
print("Could not convert data to an integer.")
else: #当 try 语句没有抛出异常时,执行else
print(arg, 'has', len(f.readlines()), 'lines')
f.close()
finally: #不管有没有发生异常,都会执行finally... print("executing finally clause")
>>> try:
... raise NameError('HiThere') #raise一个异常实例或异常类(继承自 Exception 的类)... except NameError:
... print('An exception flew by!')
... raise #raise 语句可以让你很简单的重新抛出该异常
用 C++ 术语来讲,所有的类成员(包括数据成员)都是公有public(除了Private
。有伪私有、但只是约定,理念的区别
Variables))的,所有的成员函数都是虚(virtual)的
def scope_test():
def do_local():
spam = "local spam"
def do_nonlocal():
nonlocal spam
spam = "nonlocal spam"
def do_global():
global spam
spam = "global spam"
spam = "test spam"
do_local()
print("After local assignment:", spam)
do_nonlocal()
print("After nonlocal assignment:", spam)
do_global()
print("After global assignment:", spam)
scope_test()
print("In global scope:", spam)
#以上示例代码的输出为:
After local assignment: test spam
After nonlocal assignment: nonlocal spam
After global assignment: nonlocal spam
In global scope: global spam
//在任何类的外面
>>>def upperName(self):
return self.name.upper()
>>>upperName(instanceName)
>>>className.upperName = upperName
>>>instanceName.upperName()
>>> class classx:pass>>> classx.x = 1>>> instancex = classx();instancex2 = classx()
>>> instancex.x //只是从类上取的属性
1>>> instancex.x = 2//实例也有x属性了 但是和类的x不一样
>>> instancex.x
2>>> classx.x
1
>>> classx.__dict__.keys()
dict_keys(['__dict__', '__module__', '__doc__', 'x', '__weakref__']
>>> instancex.__dict__.keys()
dict_keys(['x'])
>>> instancex2.__dict__.keys()
dict_keys([])
class test:
x = 1
if x:
y = 1
else:
y = 2
对象接口
,而不是类型.和C++等不同的是,python的class不是声明式的,就像def一样class语句执行的时候产生类对象,和def一样是可执行的代码,知道python运行定义class的语句钱,类都不存在.
X = 11 #globalclass <name>(superclass,..):
data = value #类的数据
def method(self,..) #类的方法
x = 33 #类方法的本地数据
self.member = value #实例的数据
@classmethod
def classmd(cls): #类方法 可以访问类的数据,不能访问实例的数据
@staticmethod #可以省略
def staticmd(): #静态方法 不能访问类和实例的数据
class Super:
@abstractmethod #3.0之后用
def action(self):
#assert False,'action must be implemented'#或者:
#raise NotImplementedError('action must be implemented')
class warpper:
def __init__(self, object):
self.warpped = object;
def __getattr__(self, attr):
print(attr)
return getattr(self.warpped, attr)
def factory(aClass, *args, **kwargs):
return aClass(*args, **kwargs)
object = factory(list, (1 , 2))
>>> class limit:
__slots__ = ['a','b']
>>> a = limit()
>>> a.a=1>>> a.c=1
Traceback (most recent call last):
File "<pyshell#100>", line 1, in <module>
a.c=1
AttributeError: 'limit' object has no attribute 'c'>>> a.__dict__
Traceback (most recent call last):
File "<pyshell#103>", line 1, in <module>
a.__dict__
AttributeError: 'limit' object has no attribute '__dict__'
>>> class limit2:
__slots__=['a','__dict__']
>>> x = limit2()
>>> x.a =1>>> x.c=1>>> x.__dict__
{'c': 1}
>>>class limit3(limit): #因为__slots__是伪私有?,受类限制所以集成之后没有__slots__了
pass #默认有__dict__,如果需要,再主动声明__slots__=
>>> class A:
def getAge(self):
return 40
age = property(getAge,None,None,None)#依次是 getter,setter,del,doc
>>> a = A()
>>> a.age
40
>>> a.age = 4Traceback (most recent call last):
File "<pyshell#150>", line 1, in <module>
a.age = 4AttributeError: can't set attribute
>>>class classic:#使用__setattr__ __getattr__实现
def __getattr__(self,name):
if name =='age':retun 40
else:raise AttribureError
def __setattr__(self,name,value):#没写判断
self.__dict__[name] = value
class C:
@staticmethod
def method():pass
//等价于
method = staticmethod(method)
//函数装饰器
class testTracer:
def __init__(self,fun):
self.calls = 0
self.fun = fun
def __call__(self, *args, **kwargs):
self.calls += 1
print('call %s to %s'%(self.calls, self.fun.__name__))
self.fun(*args,**kwargs)
@testTracerdef fun(a,b): #fun变成了TestTracer实例,执行fun的时候会执行TestTracer实例的__call__函数
print(a,b) # 即fun = testTracer(fun)
//类装饰器类似
def decorator(aClass):..
@decorator
class C:..
//相当于
class C:..
C = decorator(C)
已读 未补充
attribute = property(fget, fset, fdel, doc)
// 或者使用装饰器来实现
class Person:
def __init__(self, name):
self._name = name
@property
def name(self):
print('fetch..')
return self._name
@name.setter
def name(self, name):
print('change..')
self._name = name
@name.deleter
def name(self):
del self._name
3.gerattribute方法把所有属性获取都指向Python 2.6的新式类和Python 3.0的 所有类中的一个泛型处理器方法;
4.描述符协议,把特定属性访问定位到具有任意get和set处理器方法的类的实例(上面的特性只是描述符的一种);描述符作为单独的类编写,并且针对想要拦截的属性访问操作提供 特定命名的访问器方法——当以相应的方式访问分配给描述符类实例的属性时,描述符 类中的获取、设置和删除等方法自动运行
class Descriptor:
def __get__(self, instance, owner):pass# Return attr value
def __set__(self, instance, value):pass# Return nothing (None)
def __delete__(self, instance):pass # Return nothing (None)
#定义class Subject:
aAttr = Descriptor()
#访问
X.attr <=>Descriptor.__get__(Subject.attr,X,Subject)
#一个例子class Name: #这个定义可以嵌套进Person类
def __get__(self, instance, owner):
print('fetch..')
return instance._name
def __set__(self, instance, value):
print('change..')
instance._name = value
def __delete__(self, instance):
print('remove..')
del instance._name
class Person1:
def __init__(self, name):
self._name = name
name = Name()
#一个描述符类来模拟property内置函数 学习手册p985
函数装饰器
在函数定义的时候进行名称重绑定,提供一个逻辑层来管理函数和方法 或随后对它们的调用。类装饰器
在类定义的时候进行名称重绑定,提供一个逻辑层来管理类,或管理随后 调用它们所创建的实例。// 1.表现
@decoratordef F(arg):
<=>
F = decorator(F)
//2.实现
// 用函数实现
def decorator(F):
def wrapper(*args):
...
F(*args)
...
return wrapper
// 用类实现 这种方法实现的装饰器用于类方法的时候会出问题!!!self不能准确传递
class decorator:
def __init__(self,F):
self.F = F
def __call__(self, *args, **kwargs):
...
self.F()
...
//用函数实现
//一种实现 加工后返回原来的类
def decorator(C):
#process C
return C
//另一种实现,返回C的包装类
def decorator(C):
class Warpper:
def __init__(self,*args):
self.wrapped = C
def __getattr__(self,name):
return getattr(self.warpped, name)
return Warpper
// 用类实现 错误版!!多次使用会覆盖
class Warpper:
def __init__(self,C):
self.C = C
def __call__(self, *args):
self.wrapped = self.C(*args)
return self;
def __getattr__(self,name):
return getattr(self.warpped, name)
//修改:增加下面的函数即可
def decorator(C):
def onCall(*args):
return Warpper(C(*args))
return onCall
@A
@B
@C
def f()
<=>f = A(B(C(f)))
@decorator(A,B)
def f()
<=>f = @decorator(A,B)(f)
//由于创建新的类的时候,Python在语句的末尾自动调用元类,因此它可以根据需要 扩展、注册或管理类。此外,客户类唯一的需求是,它们声明元类
def extra(self, *arg):pass
class Extras(type):
def __init__(Class, className, superClass, attributeDict):
if required():
Class.extra = extra()
class Client1(metaclass = Extras):passclass Client2(metaclass = Extras):passclass Client3(metaclass = Extras):pass
x = Client1()
x.extra()
//在这种角色中,装 饰器对应到元类的__init__方法,但是,元类还有其他的定制钩子。正如我们还将看到 的,除了类初始化,元类可以执行任意的构建任务,而这些可能对装饰器来说更难
class Meta(type):
def __new__(meta, className, superClass, attributeDict):
print('in meta:',className,superClass,attributeDict,sep='\n....')
return type.__new__(meta, className, superClass, attributeDict)
print('making class')
class TestMeta(metaclass = Meta):
data = 1
print('making instance')
testMeta = TestMeta()
• 元类继承自type类。尽管它们有一种特殊的角色元类,但元类是用class语句编写 的,并且遵从Python中有用的OOP模型。
• 元类声明由子类继承。
• 元类属性没有由类实例继承。
//一个工厂函数
def MetaFunc(className, superClass, attributeDict):
print('in MetaFunc:',className,superClass,attributeDict,sep='\n....')
return type(className, superClass, attributeDict)
print('making class')
class TestMetaFunc(metaclass = MetaFunc):
data = 1
• 向类中添加方法;在new中添加
#用元类添加方法def sayHello(obj):
print('hello world')
class MetaHello(type):
def __new__(meta, className, superClass, attributeDict):
attributeDict['sayHello'] = sayHello
return type.__new__(meta, className, superClass, attributeDict)
class TestMetaHello(metaclass = MetaHello):
pass
#用装饰器也可以实现 略
类装饰器和元类
• 类装饰器可以管理类和实例。
• 元类可以管理类和实例,但是管理实例需要一些额外工作。如前面的tracer的例子 p1101
用元类和装饰器跟踪:互补使用
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。