一些代码 II (ConfigParser、创建大文件的技巧、__getattr__和__getattribute__、docstring和装饰器、抽象方法)

1. ConfigParser

format.conf

 1 [DEFAULT]
 2 conn_str = %(dbn)s://%(user)s:%(pw)s@%(host)s:%(port)s/%(db)s
 3 dbn = mysql
 4 user = root
 5 host = localhost
 6 port = 3306
 7 
 8 [db1]
 9 user = aaa
10 pw = ppp
11 db = example
12 
13 [db2]
14 host = 172.16.88.1
15 pw = www
16 db = example

readformatini.py

1 import ConfigParser
2 
3 conf = ConfigParser.ConfigParser()
4 conf.read('format.conf')
5 print conf.get('db1', 'conn_str')    # mysql://aaa.ppp@localhost:3306/example
6 print conf.get('db2', 'conn_str')    # mysql://root:www@172.16.88.1:3306/example

get(section, option[, raw[, vars]]) 的查找规则如下:

1)如果找不到节点名,就抛出 NoSectionError。

2)如果给定的配置项出现在 get() 方法的 vars 参数中,则返回 vars 参数中的值。

3)如果在指定的节点总含有给定的配置项,则返回其值。

4)如果在 [DEFAULT] 中有指定的配置项,则返回其值。

5)如果在构造函数的 default 参数中有指定的配置项,则返回其值。

6)抛出 NoOptionError。

2. 创建大文件的技巧

1 f = open('large.csv', 'wb')
2 f.seek(1073741824-1)    # 创建大文件的技巧
3 f.write('\0')
4 f.close()
5 
6 import os
7 os.stat('large.csv').st_size # 输出文件的大小 1073741824L

大数据的 csv 文件请使用 Pandas 来处理。

3. __getattr__和__getattribute__

 1 # -*- coding:utf-8 -*-
 2 class A(object):
 3     _c = 'test'
 4     def __init__(self):
 5         self.x = None
 6         
 7     @property
 8     def a(self):
 9         print 'using property to acess attribute'
10         if self.x is None:
11             print 'return value'
12             return 'a'
13         else:
14             print 'error occured'
15             raise AttributeError
16         
17     @a.setter
18     def a(self, value):
19         self.x = value
20         
21     def __getattr__(self, name):
22         print 'using __getattr__ to access attribute'
23         print 'attribute name:', name
24         return 'b'
25     
26     def __getattribute__(self, name):
27         print 'using __getattribute__ to access attribute'
28         return object.__getattribute__(self, name)
29 
30 a1 = A()
31 print a1.a
32 print '--------------'
33 a1.a = 1
34 print a1.a
35 print '--------------'
36 print A._c

输出如下:

using __getattribute__ to access attribute
using property to acess attribute
using __getattribute__ to access attribute
return value
a
--------------
using __getattribute__ to access attribute
using property to acess attribute
using __getattribute__ to access attribute
error occured
using __getattr__ to access attribute
attribute name: a
b
--------------
test

当实例化 a1 时由于其默认的属性 x 为 None,当我们发你问 a1.a 时,最先搜索的是 __getattribute__() 方法,由于 a 是一个 property 对象,并不存在于 a1 的 dict 中,因此不能返回该方法,此时会搜索 property 中定义的 get() 方法,所以返回的结果是 ‘a’。当用 property 中的 set() 方法对 x 进行修改并再次访问 property 的 get() 方法时会抛出异常,这种情况下回触发对 __getattr__() 方法的调用并返回结果 ‘b’。程序最后访问类变量输出 ‘test’ 是为了说明对类变量的方位不会涉及 __getattribute__() 和 __getattr__() 方法:

注意:__getattribute__() 总会被调用,而__getattr__() 方法仅在如下情况才会被调用:

1)属性不在实例的 __dict__ 中;

2)属性不在其基类以及祖先类的 __dict__ 中;

3)触发 AttributeError 异常时(不仅仅是 __getattribute__() 引发的 AttributeError 异常,property 中定义的 get() 方法抛出异常的时候也会调用该方法)。

4. docstring和装饰器

 1 import inspect  2 def is_admin(f):     
 3     def wrapper(*args, **kwargs):
 4         func_args = inspect.getcallargs(f, *args, **kwargs)    # func_args = {'username': '***', 'type': '***'}
 5         if func_args.get('username') != 'admin':
 6             raise Exception('This user is not allowed to get food')
 7         return f(*args, **kwargs)
 8     return wrapper
 9  
10 def foobar(username='someone', type="chocolate"):
11     """do crazy stuff"""
12     pass
13  
14 print foobar.func_doc    # do crazy stuff
15 print foobar.__name__    # foobar
16 
17 @is_admin
18 def foobar1(username='anyone', type="chocolate"):
19     """ do another crazy stuff"""
20     pass
21  
22 print foobar1.__doc__    # None,此时的__doc__应该是wrapper的
23 print foobar1.__name__    # wrapper

有装饰器的函数会丢失自己的 docstring,使用 functools 中的 wraps 可保留自己的 docstring。将 is_admin() 更改如下即可:

 1 # -*- coding:utf-8 -*-
 2 import functools
 3 import inspect
 4  
 5 def check_is_admin(f):
 6     @functools.wraps(f)    # 注意这行~~~~
 7     def wrapper(*args, **kwargs):
 8         func_args = inspect.getcallargs(f, *args, **kwargs)
 9         print func_args
10         if func_args.get('username') != 'admin':
11             raise Exception('This user is not allowed to get food')
12         return f(*args, **kwargs)
13     return wrapper

另:inspect 模块允许提取函数签名并对其进行操作。

      inspect.getcallargs() 返回一个将参数名字和值作为键值的字典。以上面例子调用 foobar('admin',"rice"),则 func_args 的值为 {'username': 'admin', 'type': 'rice'}

5. 抽象方法

简单的抽象方法:

 

1 # -*- coding:utf-8 -*-
2 class Pizza(object):
3     @staticmethod
4     def get_radius():
5         raise NotImplementedError
6     
7 p = Pizza()        # 不报错
8 p.get_radius()    # 报错

 

实例化时不报错,在真正调用时才报错,报错如下:

Traceback (most recent call last):
  File "tt.py", line 8, in <module>
    p.get_radius()
  File "tt.py", line 5, in get_radius
    raise NotImplementedError
NotImplementedError

使用abc实现抽象方法:

 1 # -*- coding:utf-8 -*-
 2 import abc
 3 
 4 class BasePizza(object):
 5     __metaclass__ = abc.ABCMeta    # python2的元类声明方式
 6     
 7     @abc.abstractmethod
 8     def get_radius():
 9         """Method that should do something."""
10         pass
11     
12 p = BasePizza()    # 报错
13 p.get_radius()      # 不执行

类在实例化时就报错,报错如下:

Traceback (most recent call last):
  File "tt.py", line 12, in <module>
    p = BasePizza()
TypeError: Can't instantiate abstract class BasePizza with abstract methods get_radius

 

posted on 2016-05-26 16:48  刘[小]倩  阅读(191)  评论(0编辑  收藏  举报

导航