python 的一些知识点(列表解析、打包、装饰器、type、slots)

来源:互联网 发布:手机数据分析 编辑:程序博客网 时间:2024/05/16 07:51

8进制:在数字前加数码0,16进制:加0x(数码0与字符x,大小写均可)

>>> a=011
>>> a
9
>>> a=0x11
>>> a
17

由22/-10 =-3 和  -22/10 =-3  和 22/10  =2可以看出,python的取整是类似于地板函数的。


Python 的列表解析(list comprehension)和生成器表达式(generator expression

以下很多转载自http://www.cnblogs.com/moinmoin/archive/2011/03/10/lsit-comprehensions-generators.html

列表解析

在需要改变列表而不是需要新建某列表时,可以使用列表解析。列表解析表达式为:

[expr for iter_varin iterable]
[expr
for iter_varin iterable if cond_expr]

第一种语法:首先迭代iterable里所有内容,每一次迭代,都把iterable里相应内容放到iter_var中,再在表达式中应用该iter_var的内容,最后用表达式的计算值生成一个列表。
第二种语法:加入了判断语句,只有满足条件的内容才把iterable里相应内容放到iter_var中,再在表达式中应用该iter_var的内容,最后用表达式的计算值生成一个列表。

>>> num = [j for i in range(2, 8) for j in range(i*2, 50, i)]>>> num[4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 10, 15, 20, 25, 30, 35, 40, 45, 12, 18, 24, 30, 36, 42, 48, 14, 21, 28, 35, 42, 49]
 

生成器表达式

生成器表达式是在python2.4中引入的,当序列过长, 而每次只需要获取一个元素时,应当考虑使用生成器表达式而不是列表解析。生成器表达式的语法和列表解析一样,只不过生成器表达式是被()括起来的,而不是[],如下:

(exprfor iter_varin iterable)
(expr
for iter_varin iterableif cond_expr)

例:

>>> L= (i +1for i in range(10) if i %2)>>> L<generator object <genexpr> at 0xb749a52c>>>> L1=[]>>>for i in L:... L1.append(i)...>>> L1[2, 4, 6, 8, 10]
可以用L.next()来迭代这个生成器表达式。如果L.next()到边界了会产生一个StopIteration异常。

生成器表达式并不真正创建数字列表, 而是返回一个生成器,这个生成器在每次计算出一个条目后,把这个条目“产生”(yield)出来。 生成器表达式使用了“惰性计算”(lazy evaluation,也有翻译为“延迟求值”,我以为这种按需调用call by need的方式翻译为惰性更好一些),只有在检索时才被赋值(evaluated),所以在列表比较长的情况下使用内存上更有效。A generator object in python is something like a lazy list. The elements are only evaluated as soon as you iterate over them. 

一些说明:

3. 当序列过长, 而每次只需要获取一个元素时,使用生成器表达式。

4. 列表解析的性能相比要比map要好,实现相同功能的for循环效率最差(和列表解析相比差两倍)。

5. 列表解析可以转换为 for循环或者使用map(其中可能会用到filter、lambda函数)表达式,但是列表解析更为简单明了,后者会带来更复杂和深层的嵌套。


作用域

>>> d={'a':1,'b':2}>>> def f():print ddef innerf():print dd['a']+=1print dreturn innerf>>> f(){'a': 1, 'b': 2}<function innerf at 0xb58351b4>>>> f()(){'a': 1, 'b': 2}{'a': 1, 'b': 2}{'a': 2, 'b': 2}        可以看出字典d在内层函数是可以用的,这是因为字典是可变对象。如果是数值型或者字符串,那就会引发异常,UnboundLocalError: local variable 'd' referenced before assignment

python 的面向对象

1.类属性__bases__

类属性__bases__是包含子类的所有父类的一个元组,这里的父类的概念不同与基类。比如。类A,B继承于A,C继承于B,D继承于A与B,则C.__bases__是B, D.__bases__是 A、B。


hasattr(object,name)      # boolean

getattr(object,name)#   相当于object.name  属性调用 ,这里的object也可以是mudules。比如getattr(sys,'path')  <==> sys.path


打包

         “打包”描述的是对某个现有对象进行包装的过程,不管这个对象是一个数据类型还是一段代码。包装过程包括添加新内容、删除无用内容、对现有功能进行改进等。

        在python中,对一个标准类型进行子类分离或者推导是不允许的。但是我们可以对某个类型打包为类的核心成员,这样新对象的操作行为就模仿所想要保留的原数据类型的操作行为,那些不想要的操作行为可以不要,而且还可以额外新增功能。这个过程叫做“对类型进行打包”

        要进行打包,就要定义新的类,让他的实例具有某个标准类型的核心操作行为。“对类型进行打包”又叫做“代表”,“代表”是打包操作的一种形式,它利用已经存在的功能最大限度地重复使用过去编写的代码。

        实现代表的一个很关键的地方就是:必须要用一段包含了getattr()内置函数的代码去覆盖掉__getattr__()方法。更确切地说,调用getattr()的目的是获取对象的缺省属性(数据属性或方法)并返回它们以作进一步访问或调用。__getattr__()特殊方法的工作原理是这样的:当需要检索某个属性的时候,系统先在局部属性中着,也就是先从定制属性中开始找;如果找不到,就会调用__getattr__(),再由它调用getattr()获取一个对象的缺省属性。

举个例子。用open打开一个文件,向其中写入字符(a-z)。数据会自动转储为大写的A-Z。

>>> import string>>> string.upper('s')'S'>>> class capOpen():def __init__(self,fn,model='r',buf=-1):self.file=open(fn,model,buf)def __str__(self):return str(self.file)def __repr__(self):return 'self.file'def write(self,line):return self.file.write(string.upper(line))def __getattr__(self,attr):return getattr(self.file,attr)>>> f=capOpen('/home/gauss/test','w')>>> fself.file>>> print f<open file '/home/gauss/test', mode 'w' at 0xb5733650>>>> f.write('adsf')>>> f.close()>>> f.closedTrue>>> f=capOpen('/home/gauss/test','r')>>> print f.read()ADSF


file对象

f.tell()#返回打开的文件中的当前位置。

f.seek()#移动文件指针的位置。第二个参数指出第一个参数是什么意思:0表示的移动到一个绝对位置。1表示移动到一个相对位置(从当前位置算起),还有2表示对于文件尾的一个相对位置。

read()#从打开的文件中读取指定个数的字节,并且返回含有读取数据的字符串。如果没有参数某认将从起始位置开始的全部读完。



轻松实现代理访问

>>> import urllib>>> proxies = {'http': 'http://proxy.example.com:8080/'}>>> opener = urllib.FancyURLopener(proxies)>>> f = opener.open("http://www.python.org")>>> f.read()
也可以给opener添加请求头部信息

在多线程下载的时候,需要用的opener.addheader("Range","bytes=%d-%d"%(startpoint, stoppoint))


装饰器

涉及到装饰器,感谢http://www.cnblogs.com/huxi/archive/2011/03/01/1967600.html

import time def timeit(func):    def wrapper():        start = time.clock()        func()        end =time.clock()        print 'used:', end - start    return wrapper @timeitdef foo():    print 'in foo()' foo()

python提供了语法糖来精简装饰器的代码,上面的@timeit即是.

        内置的装饰器有三个,分别是staticmethod、classmethod和property,作用分别是把类中定义的实例方法变成静态方法、类方法和类属性。由于模块里可以定义函数,所以静态方法和类方法的用处并不是太多,除非你想要完全的面向对象编程。

class Rabbit(object):         def __init__(self, name):        self._name = name         @staticmethod    def newRabbit(name):        return Rabbit(name)         @classmethod    def newRabbit2(cls):        return Rabbit('')         @property    def name(self):        return self._nam


这里定义的属性是一个只读属性,如果需要可写,则需要再定义一个setter:

@name.setterdef name(self, name):    self._name = name


 functools模块

2.3.1. wraps(wrapped[, assigned][, updated]):
这是一个很  有用的装饰器。看过前一篇反射的朋友应该知道,函数是有几个特殊属性比如函数名,在被装饰后,上例中的函数名foo会变成包装函数的名字wrapper,如果你希望使用反射,可能会导致意外的结果。这个装饰器可以解决这个问题,它能将装饰过的函数的特殊属性保留。

import timeimport functools def timeit(func):    @functools.wraps(func)    def wrapper():        start = time.clock()        func()        end =time.clock()        print 'used:', end - start    return wrapper @timeitdef foo():    print 'in foo()' foo()print foo.__name__


首先注意第5行,如果注释这一行,foo.__name__将是'wrapper'。另外相信你也注意到了,这个装饰器竟然带有一个参数。实际上,他还有另外两个可选的参数,assigned中的属性名将使用赋值的方式替换,而updated中的属性名将使用update的方式合并,你可以通过查看functools的源代码获得它们的默认值。对于这个装饰器,相当于wrapper = functools.wraps(func)(wrapper)。

2.3.2. total_ordering(cls):
这个装饰器在特定的场合有一定用处,但是它是在Python 2.7后新增的。它的作用是为实现了至少__lt__、__le__、__gt__、__ge__其中一个的类加上其他的比较方法,这是一个类装饰器。如果觉得不好理解,不妨仔细看看这个装饰器的源代码:

53  def total_ordering(cls):54      """Class decorator that fills in missing ordering methods"""55      convert = {56          '__lt__': [('__gt__', lambda self, other: other < self),57                     ('__le__', lambda self, other: not other < self),58                     ('__ge__', lambda self, other: not self < other)],59          '__le__': [('__ge__', lambda self, other: other <= self),60                     ('__lt__', lambda self, other: not other <= self),61                     ('__gt__', lambda self, other: not self <= other)],62          '__gt__': [('__lt__', lambda self, other: other > self),63                     ('__ge__', lambda self, other: not other > self),64                     ('__le__', lambda self, other: not self > other)],65          '__ge__': [('__le__', lambda self, other: other >= self),66                     ('__gt__', lambda self, other: not other >= self),67                     ('__lt__', lambda self, other: not self >= other)]68      }69      roots = set(dir(cls)) & set(convert)70      if not roots:71          raise ValueError('must define at least one ordering operation: < > <= >=')72      root = max(roots)       # prefer __lt__ to __le__ to __gt__ to __ge__73      for opname, opfunc in convert[root]:74          if opname not in roots:75              opfunc.__name__ = opname76              opfunc.__doc__ = getattr(int, opname).__doc__77              setattr(cls, opname, opfunc)78      return cls

python中的类定义完之后还是可以修改的。比如
>>> class M():name='gauss'def say(self):print self.__class__.name>>> M().say()gauss
然后。。
>>> def f(self,b):print b>>> M.say=f       #这里也可以M.say=lambda self,b:。。。。。>>> m=M()>>> m.say(4)4

类中的__call__相当于重载了括号运算符
>>> class M():def __call__(self,b):print b>>> m=M()>>> m(3)3>>> 

type它也能动态的创建类。type可以接受一个类的描述作为参数,然后返回一个类。(我知道,根据传入参数的不同,同一个函数拥有两种完全不同的用法是一件很傻的事情,但这在Python中是为了保持向后兼容性)
type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))
>>> def f(self,b):print b

Foo=type('Foo',(),{'say':f})
>>> Foo().say(4)
4


metaclass。元类。元类是用来创建类的东西,再由这个创建类就是我们平常所说的类。关于元类。这篇博文介绍得极其详细,内容易懂。居家旅行必备啊。


__slots__

限制了类中能访问的属性

>>> class T(object):__slots__=('info')def __init__(self,info):self.info=info>>> t=T('gauss')>>> t.info'gauss'>>> t.a=3Traceback (most recent call last):  File "<pyshell#32>", line 1, in <module>    t.a=3AttributeError: 'T' object has no attribute 'a'>>> 
__slots__是一个元组,只有元组里的属性才能被访问,一定要继承object。其实我们知道,python相当之动态,即使一个已经定义了的类还是能修改的,通过type我们还知道python能动态定义类。

原创粉丝点击