在python的类中动态添加属性与生成对象

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

在python的类中动态添加属性与⽣成对象
本⽂将通过⼀下⼏个⽅⾯来⼀⼀进⾏解决
1、程序的主要功能
2、实现过程
3、类的定义
4、⽤⽣成器generator动态更新每个对象并返回对象
5、使⽤strip 去除不必要的字符
6、rematch匹配字符串
7、使⽤timestrptime提取字符串转化为时间对象
8、完整代码
程序的主要功能
现在有个存储⽤户信息的像表格⼀样的⽂档:第⼀⾏是属性,各个属性⽤逗号(,)分隔,从第⼆⾏开始每⾏是各个属性对应的值,每⾏代表⼀个⽤户。

如何实现读⼊这个⽂档,每⾏输出⼀个⽤户对象呢?
另外还有4个⼩要求:
每个⽂档都很⼤,如果⼀次性把所有⾏⽣成的那么多对象存成列表返回,内存会崩溃。

程序中每次只能存⼀个⾏⽣成的对象。

⽤逗号隔开的每个字符串,前后可能有双引号(”)或者单引号('),例如”张三“,要把引号去掉;如果是数字,有
+000000001.24这样的,要把前⾯的+和0都去掉,提取出1.24
⽂档中有时间,形式可能是2013-10-29,也可能是2013/10/29 2:23:56 这样的形式,要把这样的字符串转成时间类型
这样的⽂档有好多个,每个的属性都不⼀样,例如这个是⽤户的信息,那个是通话纪录。

所以类中的具体属性有哪些要根据⽂档的第⼀⾏动态⽣成
实现过程
1.类的定义
由于属性是动态添加的,属性-值对也是动态添加的,类中要含有updateAttributes()和updatePairs()两个成员函数即可,此外⽤列表attributes存储属性,词典attrilist存储映射。

其中init()函数为构造函数。

__attributes前有下划线表⽰私有变量,不能在外⾯直接调⽤。

实例化时只需a=UserInfo()即可,⽆需任何参数。

class UserInfo(object):
'Class to restore UserInformation'
def __init__ (self):
self.attrilist={}
self.__attributes=[]
def updateAttributes(self,attributes):
self.__attributes=attributes
def updatePairs(self,values):
for i in range(len(values)):
self.attrilist[self.__attributes[i]]=values[i]
2.⽤⽣成器(generator)动态更新每个对象并返回对象
⽣成器相当于⼀个只需要初始化⼀次,就可⾃动运⾏多次的函数,每次循环返回⼀个结果。

不过函数⽤return 返回结果,⽽⽣成器⽤yield 返回结果。

每次运⾏都在yield返回,下⼀次运⾏从yield之后开始。

例如,我们实现斐波拉契数列,分别⽤函数和⽣成器实现:
def fib(max):
n, a, b = 0, 0, 1
while n < max:
print(b)
a, b = b, a + b
n = n + 1
return 'done'
我们计算数列的前6个数:
>>> fib(6)
1
1
2
3
5
8
'done'
如果⽤⽣成器的话,只要把print 改成yield 就可以了。

如下:
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
使⽤⽅法:
>>> f = fib(6)
>>> f
<generator object fib at 0x104feaaa0>
>>> for i in f:
... print(i)
...
1
1
2
3
5
8
>>>
可以看到,⽣成器fib本⾝是个对象,每次执⾏到yield会中断返回⼀个结果,下次⼜继续从yield的下⼀⾏代码继续执⾏。

⽣成器还可以⽤generator.next()执⾏。

在我的程序中,⽣成器部分代码如下:
def ObjectGenerator(maxlinenum):
filename='/home/thinkit/Documents/usr_info/USER.csv'
attributes=[]
linenum=1
a=UserInfo()
file=open(filename)
while linenum < maxlinenum:
values=[]
line=str.decode(file.readline(),'gb2312')#linecache.getline(filename, linenum,'gb2312')
if line=='':
print'reading fail! Please check filename!'
break
str_list=line.split(',')
for item in str_list:
item=item.strip()
item=item.strip('\"')
item=item.strip('\'')
item=item.strip('+0*')
item=catchTime(item)
if linenum==1:
attributes.append(item)
else:
values.append(item)
if linenum==1:
a.updateAttributes(attributes)
else:
a.updatePairs(values)
yield a.attrilist #change to ' a ' to use
linenum = linenum +1
其中,a=UserInfo()为类UserInfo的实例化.因为⽂档是gb2312编码的,上⾯使⽤了对应的解码⽅法。

由于第⼀⾏是属性,有个函数将属性列表存⼊UserInfo中,即updateAttributes();后⾯的⾏则要将属性-值对读⼊⼀个字典中存储。

p.s.python中的字典相当于映射(map).
3.使⽤strip 去除不必要的字符
从上⾯代码中,可以看到使⽤str.strip(somechar)即可去除str前后的somechar字符。

somechar可以是符号,也可以是正则表达式,如上:
item=item.strip()#除去字符串前后的所有转义字符,如\t,\n等
item=item.strip('\"')#除去前后的"
item=item.strip('\'')
item=item.strip('+0*')#除去前后的+00...00,*表⽰0的个数可以任意多,也可以没有
4.re.match匹配字符串
函数语法:
re.match(pattern, string, flags=0)
函数参数说明:
参数描述
pattern 匹配的正则表达式
string 要匹配的字符串。

flags 标志位,⽤于控制正则表达式的匹配⽅式,如:是否区分⼤⼩写,多⾏匹配等等。

若匹配成功re.match⽅法返回⼀个匹配的对象,否则返回None。

`
>>> s='2015-09-18'
>>> matchObj=re.match(r'\d{4}-\d{2}-\d{2}',s, flags= 0)
>>> print matchObj
<_sre.SRE_Match object at 0x7f3525480f38>
1
2
3
4
5
5.使⽤time.strptime提取字符串转化为时间对象
在time模块中,time.strptime(str,format)可以把str按照format格式转化为时间对象,format中的常⽤格式有:
%y 两位数的年份表⽰(00-99)
%Y 四位数的年份表⽰(000-9999)
%m ⽉份(01-12)
%d ⽉内中的⼀天(0-31)
%H 24⼩时制⼩时数(0-23)
%I 12⼩时制⼩时数(01-12)
%M 分钟数(00=59)
%S 秒(00-59)
此外,还需要使⽤re模块,⽤正则表达式,对字符串进⾏匹配,看是否是⼀般时间的格式,如YYYY/MM/DD H:M:S, YYYY-MM-DD等
在上⾯的代码中,函数catchTime就是判断item是否为时间对象,是的话转化为时间对象。

代码如下:
import time
import re
def catchTime(item):
# check if it's time
matchObj=re.match(r'\d{4}-\d{2}-\d{2}',item, flags= 0)
if matchObj!= None :
item =time.strptime(item,'%Y-%m-%d')
#print "returned time: %s " %item
return item
else:
matchObj=re.match(r'\d{4}/\d{2}/\d{2}\s\d+:\d+:\d+',item,flags=0 )
if matchObj!= None :
item =time.strptime(item,'%Y/%m/%d %H:%M:%S')
#print "returned time: %s " %item
return item
完整代码:
import collections
import time
import re
class UserInfo(object):
'Class to restore UserInformation'
def __init__ (self):
self.attrilist=collections.OrderedDict()# ordered
self.__attributes=[]
def updateAttributes(self,attributes):
self.__attributes=attributes
def updatePairs(self,values):
for i in range(len(values)):
self.attrilist[self.__attributes[i]]=values[i]
def catchTime(item):
# check if it's time
matchObj=re.match(r'\d{4}-\d{2}-\d{2}',item, flags= 0)
if matchObj!= None :
item =time.strptime(item,'%Y-%m-%d')
#print "returned time: %s " %item
return item
else:
matchObj=re.match(r'\d{4}/\d{2}/\d{2}\s\d+:\d+:\d+',item,flags=0 )
if matchObj!= None :
item =time.strptime(item,'%Y/%m/%d %H:%M:%S')
#print "returned time: %s " %item
return item
def ObjectGenerator(maxlinenum):
filename='/home/thinkit/Documents/usr_info/USER.csv'
attributes=[]
linenum=1
a=UserInfo()
file=open(filename)
while linenum < maxlinenum:
values=[]
line=str.decode(file.readline(),'gb2312')#linecache.getline(filename, linenum,'gb2312') if line=='':
print'reading fail! Please check filename!'
break
str_list=line.split(',')
for item in str_list:
item=item.strip()
item=item.strip('\"')
item=item.strip('\'')
item=item.strip('+0*')
item=catchTime(item)
if linenum==1:
attributes.append(item)
else:
values.append(item)
if linenum==1:
a.updateAttributes(attributes)
else:
a.updatePairs(values)
yield a.attrilist #change to ' a ' to use
linenum = linenum +1
if __name__ == '__main__':
for n in ObjectGenerator(10):
print n #输出字典,看是否正确
总结
以上就是这篇⽂章的全部内容,希望能对⼤家的学习或者⼯作带来⼀定帮助,如果有疑问⼤家可以留⾔交流,谢谢⼤家对的⽀持。

相关文档
最新文档