一些代码 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