'%(n)d %(x)s' % {'n':1,'x':'spam'}
>>>'1 spam '
在脚本的第一行或第二行声明以下注释可以指明想要的编码,从而将默认编码修改为支持任意的字符集
# -*- coding: latin-1 -*-
python 2.x
python 3
转换(python 3)
bytes.decode()和str(b, encoding)把raw bytes转换为其字符串形式。
s='eggs'
s.encode()
>>>b'eggs'
bytes(s, encoding='ascii')
>>>b'eggs'
b=b'spam'
b.decode()
>>>'spam'
str(b, encoding='ascii')
>>>'spam'
如果str函数省略了编码参数,返回的是打印字符串而不是转换后的字符串,e.g.
b=b'spam'
str(b)
>>>"b'spam'"
len(str(b))
>>>7
字节常量要求字符要么是ascii字符,如果它们的值大于127就进行转义(只能以十六进制转义)。
字符串常量可以包含字符集中的任何字符(十六进制或Unicode转义)。
LEGB法则
在函数内引用全局变量不需要global声明,赋值则需要。
nonlocal的作用与global类似,不过是用于嵌套的函数作用域。
在某个函数内部调用一个以后才定义的函数是可行的,只要第二个函数定义的运行是在第一个函数调用前就行。
nonlocal使得对变量的查找从嵌套的函数作用域中开始,而不是从声明函数的本地作用域开始,并且不会继续到全局或内置作用域中。
nonlocal声明的变量必须在一个嵌套的函数中提前定义过,否则会产生一个错误。
unicode是python字符串的内部编码方式,因此encode和decode都是围绕着unicode编码来进行编码转化的。decode是将其他编码的字符串解码为unicode编码,而encode则是将unicode编码的字符串编码为另一种编码。
例如:str.decode(‘utf8’),这个语句将已知是utf8编码的字符串str解码为unicode,而str.encode(‘utf8’)则是将unicode编码的字符串str编码为utf-8。
一般情况下,字符串的编码跟代码文件的编码保持一致,通过在字符串面量值前面加上字母u(例如:str = u’test’)可以强制指定为unicode编码而忽略文件的编码。
参数顺序:
参数匹配顺序:
注意:
位置参数的匹配优先于关键字参数,e.g.
def f(a,b,c):
print a,b,c
f(a=1,*(1,2))
这样的调用会出错,参数a会被匹配两次,因为位置参数先匹配,所以参数a会赋值为1,参数b会赋值为
2,接着再进行关键字参数的匹配,这时再次对参数a进行匹配,所以就出错了 再看个例子:
def f(a,b,c,d):
print a,b,c,d
f(1,c=3,*(2,),d=4)
位置参数会先匹配,所以参数b被赋值为2,在* sequence形式的后面只能是关键字参数或* * dict形式,如果是这样调用则会出错:f(1,c=3,*(2,),4)
在函数调用时,*sequence形式接受任意可迭代对象,e.g.
def f(a,b,c,d):
print a,b,c,d
l = [1,2,3,4]
it = iter(l)
f(*it)
f(*open('XXX'))
python3支持keyword-only参数,在函数声明中,keyword-only参数只能出现*arg或单独的*字符(不需要可变数量位置参数)后面,在函数调用时,这些参数只能使用关键字语法来传递。e.g.
def f(a,*b,c): print a,b,c f(1,2,3) #出错,c只能以关键字形式传递 def f(a,*,b,c):
print a,b,c f(1,2,3) #出错,b,c都只能以关键字形式传递 keyword-only参数也支持默认参数
def f(a:'test',b:1,c:(1,2)=100)->'hello':
print(a,b,c)
>>> f.__annotations__
{'return': 'hello', 'c': (1, 2), 'a': 'test', 'b': 1}
函数注解只在def语句中有效,在lambda表达式中无效
send函数传入的参数会作为yield表达式的返回值,e.g.
def f():
for i in range(10):
x = yield i
print 'send ' + str(x)
>>> g = f()
>>> next(g)
0
>>> g.send(10)
send 10
1
e.g.
g = (x for x in range(10)
>>> next(g)
0
>>> next(g)
1
实际上,列表解析基本等同于在list内置调用中包含一个生成器表达式以迫使其一起生成列表中所有的结果。e.g.
[x ** 2 for x in range(8)]
list(x ** 2 for x in range(8))
如果生成器表达式作为函数调用中的唯一参数,括号是可以省略的,其他情况则不行。e.g.
sum(x for x in range(10))
sorted(x for x in range(10))
sorted((x for x in range(10)), reverse=True)
x = 99
def f():
print x
x = 1
>>> f()
Traceback (most recent call last):
File "" , line 1, in
File "" , line 2, in f
UnboundLocalError: local variable 'x' referenced before assignment
在编译时,python看到对x的赋值语句(也包括import,嵌套def,嵌套类等)决定了x将在函数中的任何地方都将是本地变量名,即使运行时赋值语句是在print语句之后运行的
因为上述的原因,所以在函数中,不可能同时使用同一变量名的本地变量和全局变量,如果希望在函数内打印全局变量,之后使用同一变量名的本地变量,可以通过以下方式实现:
#test.py
x=99
def f():
import test
print test.x #打印全局变量x的值
x = 88
print x #打印本地变量x的值
if __name__ == '__main__':
f()
print x #打印全局变量x的值
$python test.py
99
88
99
默认参数是在def语句运行时评估并保存的,而不是在这个函数被调用的时候,从内部来讲,python会为每个默认参数保存成为一个对象,附加在这个函数本身。e.g.
>>> def f(x=[]):
... x.append(1)
... print x
...
>>> f()
[1]
>>> f()
[1, 1]
>>> f()
[1, 1, 1]
python会把载入的模块存储到一个名为sys.modules的表中,只有在模块第一次导入时才会进行加载。
import的三个步骤:
按照搜索的顺序排列如下:
import b形式的可能会加载:
相对导入只适用在包内的import
不带点号的import,e.g.
import A
from A import B
在python2.6中先相对(包目录)再绝对(sys.path)的搜索路径顺序
在python3中则是绝对的(sys.path),而不会在包目录下搜索
带点号的import,e.g.
from . import A
from .A import B
from .. import A
from ..A import B
在python2.6和python3中都是只会在包目录下搜索
>>> sys=__import__('sys')
>>> sys
'sys' (built-in)>
class Child(Base):
def method(self,arg):
Base.method(self,arg)
_ repr_,_ str_ 打印,转换
_ str_只对打印操作顶层才有用,嵌套到其他对象中的对象用_ repr_或默认方式打印
class Printer:
def __init__(self, val):
self.val = val
def __str__(self):
return str(self.val)
>>> objs = [Printer(2), Printer(3)]
>>> for x in objs: print(x)
2
3
>>> print(objs)
[<__main__.Printer object at 0x025D06f0>, <__main__.Printer object at ...
为了确保一个定制显示在所有的环境下都显示而不管容器是什么,请编写_ repr_,而不是_ str_
class Printer:
def __init__(self, val):
self.val = val
def __repr__(self):
return str(self.val)
>>> objs = [Printer(2), Printer(3)]
>>> for x in objs: print(x)
2
3
>>> print(objs)
[2, 3]
_ call_ 函数调用
_ getattr_ 点号运算 X.undefined
当通过对未定义(不存在)属性名称和实例进行点号运算时,就会用属性名称作为字符串调用这个方法,如果通过其继承树搜索流程找到这个属性,该方法就不会被调用。
class X:
def __init__(self):
self.attr1 = 1
def __getattr__(self, attrname):
print attrname
>>> x = X()
>>> x.attr1
1
>>> x.attr2
'attr2'
_ setattr_ 属性赋值语句 e.g. X.any = value
该方法会拦截所有属性的赋值语句,如果在该函数中对任何self属性做赋值,就会再调用该函数,导致了无穷递归循环,所以得通过对属性字典做索引运算来赋值任何实力属性。
_ getitem_ 索引或分片运算,e.g. X[key],X[i:j]
class X:
def __getitem__(self, index):
print x
>>> x = X()
>>> x[2]
2
>>> x[0:10:2]
slice(0, 10, 2)
_ setitem_ 索引或分片赋值语句,e.g. X[key]=value,X[i:j]=value
class X:
def __setitem__(self, index, value):
print index, value
>>> x = X()
>>> x[0] = 1
0 1
_ index_ 整数值,e.g. hex(X),bin(X),oct(X)
class X:
def __index__(self):
return 255
>>> x = X()
>>> hex(x)
'0xff'
>>> bin(x)
'0b11111111'
>>> oct(x)
'0o377'
>>> ('c'*256)[x]
'c'
_ enter_,_ exit_ 环境管理器,e.g. with obj as var:
python 3.0
from abc import ABCMeta, abstractmethod
class Super(metaclass=ABCMeta):
@abstractmethod
def method(self, ...):
pass
python 2.6
class Super:
__metaclass__ = ABCMeta
@abstractmethod
def method(self, ...):
pass
#对于经典类来说,对用户自定义类型和内置类型的处理是不一样的
Class C:pass
>>> I = C()
>>> type(I)
<type 'instance'>
>>> I.__class__
<class __main__.C at 0x025085A0>
>>> type(C)
<type 'classobj'>
>>> C.__class__
AttributeError: class C has no attribute '__class__'
>> type([1,2,3])
<type 'list'>
>>> type(list)
<type 'type'>
>>> list.__class__
<type 'type'>
对新式类来说,用户自定义类型和内置类型是一样的
class C(object): pass
>>> I = C()
>>> type(I)
<class '__main__.C'>
>>> I.__class__
<class '__main__.C'>
>>> type(C)
<type 'type'>
>>> C.__class__
<type 'type'>
>> type([1,2,3])
<type 'list'>
>>> type(list)
<type 'type'>
>>> list.__class__
<type 'type'>
class语句内开头有两个下划线,但结尾没有两个下划线的变量名(无论是类还是实例属性,无论是方法还是数据),会自动扩张,从而包含了所在类的名称:原始的变量名会在头部加入一个下划线,然后是所在类名称
class X:
def __init(self):
self.__a = 1
>>> x = X()
>>> x.__dict__
{'_X__a':1}
属性搜索处理沿着树层级,以更加广度优先的方式进行
在class语句顶层内将字符串名称顺序赋值给变量_ slots_:只有_ slots_列表内的这些变量名可以赋值为实例属性,使用了slots,实例通常没有一个属性字典。通过在_ slots_中包含_ dict_仍然可以容纳额外的属性
class X(object):
__slots__ = ['a','b','__dict__']
c = 1
def __init__(self):
self.a = 1
self.d = 1
>>> x = X()
>>> x.__slots__
['a','b','__dict__']
>>> x.__dict__
{'d':1}
(新式类的)特性是一种可以替代_ getattr_和_ setattr_的方法
class X(object):
def getage(self):
return 40
def setage(self, value):
print 'set age:', value
self._age = value
age = property(getage, setage, None, None)
>>> x = X()
>>> x.age
40
>>> x.age = 42
set age: 42
>>> x._age
42
>>> x.job = 'trainer'
>>> x.job
'trainer'
class X:
def sf():
print 'static method'
def cf(cls):
print 'class method', cls
sf = staticmethod(sf)
cf = classmethod(cf)
>>> x = X()
>>> x.sf()
'static method'
>>> x.cf()
'class method' <class '__main__.X'>
>>> X.sf()
'static method'
>>> X.cf()
'class method' <class '__main__.X'>
函数装饰器把一个函数当作参数并且返回一个可调用对象
class tracer:
def __init__(self, func):
self.func = func
def __call__(self, *args):
print 'call tracer'
self.func(*args)
@tracer
def f(a,b,c):
print a,b,c
>>> f(1,2,3)
'call tracer'
1 2 3
def addcount(cls):
cls.count = 0
return cls
@addcount
class A:pass
@addcount
class B:pass
>>> A.count
0
>>> B.count
0
class Meta(type):
def __new__(meta, classname, supers, classdict):...
class C(metaclass=Meta):...
元类通过重新定义type类的_new_或_init_方法,以实现对一个新的类对象的创建和初始化的控制。
property内置函数,把特定属性访问定位到get和set处理器函数,也叫做特性
常规写法
attribute = property(fget, fset, fdel, doc)
装饰器写法
class Person:
def __init__(self, name):
self._name=name
@property
def name(self):
"name property docs"
print('fetch...')
return self._name
@name.setter
def name(self, value):
print('change...')
self._name=value
@name.deleter
def name(self):
print('remove...')
del self._name
描述符协议,把特定属性访问定位到具有任意get和set处理器方法的类的实例
class Descriptor:
"docstring goes here"
def __get__(self, instanc, ower): ...
def __set__(self, instance, value): ...
def __delete(self, instance): ...
class Subject():
attr=Descriptor()
e.g.
class Descriptor(object):
def ____get____(self, instance, owner):
print(self, instance, owner, sep='\n')
class Subject:
attr=Descriptor()
x=Subject()
x.attr
>>><____main____.Descriptor object at xxx>
>>><____main____.Subject object at xxx>
>>>'____main____'.Subject>
Subject.attr
>>><____main____.Descriptor object at xxx>
>>>None
>>>'____main____.Subject'>
def decorator(F):
#process function F
return F
@decorator
def func():...
def decorator(F):
#save or use function F
return G
@decorator
def func():...
class decorator:
def __init__(self, func):
self.func = func
def __call__(self, *args):
#use self.func and args
@decorator
def func(x, y):...
基于类的装饰器无法用于类方法
e.g.
class decorator:
def __init__(self, func):
self.func = func
def __call__(self, *args):
#self.func(*args) fails! C instance not in args!
class C:
@decorator
def method(self, x, y): ...
try语句分句形式
参考自《Python学习手册》