属性を動的に追加し、Python クラスでオブジェクトを生成する

高洛峰
リリース: 2017-02-22 17:06:20
オリジナル
1066 人が閲覧しました

この記事では以下のような観点から一つ一つ解決していきます

1. プログラムの主な機能

2. 実装プロセス

3. クラス定義

4. ジェネレータージェネレーターによる動的更新 それぞれオブジェクトを取得し、オブジェクトを返します

5. ストリップを使用して不要な文字を削除します

6. 一致する文字列を再照合します 7. timestrptime を使用して文字列を抽出し、時刻オブジェクトに変換します 8. 完全なコード


Mainプログラムの関数


これで、ユーザー情報を格納するテーブルのようなドキュメントができました。最初の行は属性で、各属性はカンマ (,) で区切られ、2 行目以降、各行は以下に対応します。各属性の値、各行はユーザーを表します。このドキュメントを読んで、1 行に 1 つのユーザー オブジェクトを出力するにはどうすればよいですか? さらに 4 つの小さな要件があります: すべての行によって生成された多数のオブジェクトがリストに格納され、一度に返されると、メモリが崩壊します。プログラムに一度に保存できる行生成オブジェクトは 1 つだけです。

コンマで区切られた各文字列の前後に二重引用符 (") または一重引用符 (') を付けることができます。たとえば、「Zhang San」の場合は引用符を削除する必要があります。+000000001.24 などの数値の場合は、引用符を削除する必要があります。先頭の + と 0 を削除して 1.24 を抽出します


文書内に 2013-10-29 の形式である可能性がある、または 2013/ の形式である可能性があります。 10/29 2:23:56. このような文字列を取得するには、時刻型に変換します

このようなドキュメントは多数あり、それぞれ異なる属性があります。たとえば、これはユーザー情報であり、これは通話記録です。クラス内の属性は、ドキュメントの最初の行に基づいて動的に生成される必要があります

1. クラス定義

属性は動的に追加されるため、属性と値のペアも動的に追加されます。 、クラスには updateAttributes()updatePairs() が含まれている必要があります。さらに、リスト attributes を使用して属性を保存します。辞書 attrilist はマッピングを保存するために使用されます。 ) 関数は、__attributes の前のアンダースコアはプライベート変数を示し、外部から直接呼び出すことはできません。パラメータを指定せずに、 a=UserInfo() だけをインスタンス化に使用できます。

2. ジェネレーターを使用して各オブジェクトを動的に更新します

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 &#39;done&#39;
ログイン後にコピー

我们计算数列的前6个数:

>>> fib(6)
1
1
2
3
5
8
&#39;done&#39;
ログイン後にコピー

如果用生成器的话,只要把 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=&#39;/home/thinkit/Documents/usr_info/USER.csv&#39;
 attributes=[]
 linenum=1
 a=UserInfo()
 file=open(filename)
 while linenum < maxlinenum:
  values=[]
  line=str.decode(file.readline(),&#39;gb2312&#39;)#linecache.getline(filename, linenum,&#39;gb2312&#39;)
  if line==&#39;&#39;:
   print&#39;reading fail! Please check filename!&#39;
   break
  str_list=line.split(&#39;,&#39;)
  for item in str_list:
   item=item.strip()
   item=item.strip(&#39;\"&#39;)
   item=item.strip(&#39;\&#39;&#39;)
   item=item.strip(&#39;+0*&#39;)
   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 &#39; a &#39; to use
  linenum = linenum +1
ログイン後にコピー

其中,a=UserInfo()为类UserInfo的实例化.因为文档是gb2312编码的,上面使用了对应的解码方法。由于第一行是属性,有个函数将属性列表存入UserInfo中,即updateAttributes();后面的行则要将 属性-值 对读入一个字典中存储。p.s.python中的字典相当于映射(map).

3.使用strip 去除不必要的字符

从上面代码中,可以看到使用str.strip(somechar)即可去除str前后的somechar字符。somecharこのジェネレーターは、一度初期化するだけで済み、自動的に複数回実行できるジェネレーターと同等ですが、この関数は結果を返すために return を使用します。 、ジェネレーターは実行されるたびに yield を使用して結果を返し、次の実行は yield の後に開始されます。たとえば、フィボナッチ数列を実装します。関数とジェネレーターをそれぞれ使用します:

item=item.strip()#除去字符串前后的所有转义字符,如\t,\n等
item=item.strip(&#39;\"&#39;)#除去前后的"
item=item.strip(&#39;\&#39;&#39;)
item=item.strip(&#39;+0*&#39;)#除去前后的+00...00,*表示0的个数可以任意多,也可以没有
ログイン後にコピー

シーケンスの最初の 6 を計算します。数値:

re.match(pattern, string, flags=0)
ログイン後にコピー

ジェネレーターを使用する場合は、print を < に変更するだけです。 code>yield は次のようになります:

import time
import re

def catchTime(item):
 # check if it&#39;s time
 matchObj=re.match(r&#39;\d{4}-\d{2}-\d{2}&#39;,item, flags= 0)
 if matchObj!= None :
  item =time.strptime(item,&#39;%Y-%m-%d&#39;)
  #print "returned time: %s " %item
  return item
 else:
  matchObj=re.match(r&#39;\d{4}/\d{2}/\d{2}\s\d+:\d+:\d+&#39;,item,flags=0 )
  if matchObj!= None :
   item =time.strptime(item,&#39;%Y/%m/%d %H:%M:%S&#39;)
   #print "returned time: %s " %item
  return item
ログイン後にコピー
ログイン後にコピー

Use Method:


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=&#39;/home/thinkit/Documents/usr_info/USER.csv&#39;
 attributes=[]
 linenum=1
 a=UserInfo()
 file=open(filename)
 while linenum < maxlinenum:
  values=[]
  line=str.decode(file.readline(),&#39;gb2312&#39;)#linecache.getline(filename, linenum,&#39;gb2312&#39;)
  if line==&#39;&#39;:
   print&#39;reading fail! Please check filename!&#39;
   break
  str_list=line.split(&#39;,&#39;)
  for item in str_list:
   item=item.strip()
   item=item.strip(&#39;\"&#39;)
   item=item.strip(&#39;\&#39;&#39;)
   item=item.strip(&#39;+0*&#39;)
   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 &#39; a &#39; to use
  linenum = linenum +1

if __name__ == '__main__':
 for n in ObjectGenerator(10):
  print n  #输出字典,看是否正确
ログイン後にコピー
ログイン後にコピー


ジェネレータ fib 自体が、yield のために実行されるたびにオブジェクトであることがわかります。次回は、 yield の次のコード行から実行を継続します。 generator.next() を使用してジェネレーターを実行することもできます。

私のプログラムでは、ジェネレーター部分のコードは次のとおりです:

rrreee

🎜 ここで、 a=UserInfo( ) はクラス UserInfo のインスタンス化です。ドキュメントは gb2312 でエンコードされているため、対応するデコード方法が上記で使用されています。最初の行は属性であるため、UserInfo に属性リストを格納する関数、つまり updateAttributes(); があり、次の行は属性を読み取る必要があります。値のペアを辞書に格納します。 p.s.python の辞書はマップに相当します🎜🎜🎜🎜3. 不要な文字を削除するには、strip を使用します🎜🎜🎜🎜🎜 上記のコードから、 str を使用していることがわかります。 strip(somechar) は、str の前後の somechar 文字を削除できます。 somechar は、上記のように、シンボルまたは正規表現にすることができます: 🎜🎜🎜rrreee🎜🎜🎜🎜🎜4.re.match 一致する文字列 🎜🎜🎜🎜🎜関数の構文: 🎜🎜🎜rrreee明関数パラメーターの説明: 🎜🎜🎜 パラメーターの説明 🎜🎜🎜パターン マッチング正規表現 🎜🎜🎜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&#39;s time
 matchObj=re.match(r&#39;\d{4}-\d{2}-\d{2}&#39;,item, flags= 0)
 if matchObj!= None :
  item =time.strptime(item,&#39;%Y-%m-%d&#39;)
  #print "returned time: %s " %item
  return item
 else:
  matchObj=re.match(r&#39;\d{4}/\d{2}/\d{2}\s\d+:\d+:\d+&#39;,item,flags=0 )
  if matchObj!= None :
   item =time.strptime(item,&#39;%Y/%m/%d %H:%M:%S&#39;)
   #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=&#39;/home/thinkit/Documents/usr_info/USER.csv&#39;
 attributes=[]
 linenum=1
 a=UserInfo()
 file=open(filename)
 while linenum < maxlinenum:
  values=[]
  line=str.decode(file.readline(),&#39;gb2312&#39;)#linecache.getline(filename, linenum,&#39;gb2312&#39;)
  if line==&#39;&#39;:
   print&#39;reading fail! Please check filename!&#39;
   break
  str_list=line.split(&#39;,&#39;)
  for item in str_list:
   item=item.strip()
   item=item.strip(&#39;\"&#39;)
   item=item.strip(&#39;\&#39;&#39;)
   item=item.strip(&#39;+0*&#39;)
   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 &#39; a &#39; to use
  linenum = linenum +1

if __name__ == '__main__':
 for n in ObjectGenerator(10):
  print n  #输出字典,看是否正确
ログイン後にコピー
ログイン後にコピー

总结

以上就是这篇文章的全部内容,希望能对大家的学习或者工作带来一定帮助,如果有疑问大家可以留言交流,谢谢大家对PHP中文网的支持。

更多在python的类中动态添加属性与生成对象相关文章请关注PHP中文网!


関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート