文章目录
oop简介
- OOP:面向对象的编程
>>> class Bear: # 定义类,class是关键字
... pass
...
>>> b1 = Bear() # 创建实例
>>> b1.name = '熊大'
>>> b1.size = 'L'
>>> b1.name
'熊大'
>>>> b1.size
绑定示例
class Role:
def __init__(self, name, wuqi):
'称作构造器方法,创建实例时,自动调用。通常用于将属性绑定到实例。'
self.name = name
self.wuqi = wuqi
def show_me(self):
# 绑定在实例身上的属性,可以在类中的任意位置使用
print('我是%s,擅长使用%s' % (self.name, self.wuqi))
def speak(self, words):
# 没有绑定到实例的属性,就是函数的局部变量,只能在函数内使用
print(words)
if __name__ == '__main__':
lb = Role('吕布', '方天画戟') # 自动调用__init__方法
lb.show_me() # 实例lb自动作为第一个参数传给方法
lb.speak('马中赤兔,人中吕布')
zf = Role('张飞', '丈八蛇矛')
zf.show_me()
zf.speak('我乃燕人张飞张冀德')
组合与派生
什么是组合
class WuQi:
def __init__(self, wname, wtype, liliang):
self.wname = wname
self.wtype = wtype
self.liliang = liliang
class Role:
def __init__(self, name, wuqi):
'称作构造器方法,创建实例时,自动调用。通常用于将属性绑定到实例。'
self.name = name
self.wuqi = wuqi
def show_me(self):
# 绑定在实例身上的属性,可以在类中的任意位置使用
print('我是%s,擅长使用%s' % (self.name, self.wuqi))
if __name__ == '__main__':
ji = WuQi('方天画戟', wtype='物理伤害', liliang=100)
print(ji.wname, ji.wtype, ji.liliang)
lb = Role('吕布', ji) # 自动调用__init__方法
print(lb.wuqi.wname, lb.wuqi.wtype, lb.wuqi.liliang)
创建子类
class Role:
def __init__(self, name, wuqi, guojia):
'称作构造器方法,创建实例时,自动调用。通常用于将属性绑定到实例。'
self.name = name
self.wuqi = wuqi
self.guojia = guojia
def show_me(self):
# 绑定在实例身上的属性,可以在类中的任意位置使用
print('我是%s,擅长使用%s' % (self.name, self.wuqi))
def speak(self, words):
# 没有绑定到实例的属性,就是函数的局部变量,只能在函数内使用
print(words)
class ZhanShi(Role): # 括号中是父类,也叫基类
# 子类将会继承父类的所有方法
def __init__(self, name, wuqi, guojia, zuoji):
# Role.__init__(self, name, wuqi, guojia) # 调用父类方法
super(ZhanShi, self).__init__(name, wuqi, guojia) # 调用父类方法,与上>一行一样
self.zuoji = zuoji
def attack(self, target):
print('正在近身与%s肉搏' % target)
class FaShi(Role):
def attack(self, target):
print('远程打击%s' % target)
if __name__ == '__main__':
lb = ZhanShi('吕布', '方天画戟', '群雄', '赤兔马')
lb.show_me()
lb.speak('马中赤兔,人中吕布')
lb.attack('张飞')
特殊方法
- 在class中,为了实现其内部功能,它们拥有很多以双下划线开头和结尾的特殊方法
# dir可以查看对象属性
>>> type(10) # 10是int的实例
<class 'int'>
>>> dir(10) # 查看10的属性
>>> dir([]) # 查看列表实例的属性
__init__ 方法
__str方法
- 实现book出版商脚本
class Book:
def __init__(self, title, author):
'创建实例时,自动调用的方法'
self.title = title
self.author = author
def __str__(self):
'在打印、显示实例时,自动调用'
return '《%s》' % self.title
def __call__(self):
'使实例可以像函数一样调用'
print('《%s》是%s编写的' % (self.title, self.author))
if __name__ == '__main__':
py_book = Book('Python基础教程(第3版)', 'Magnus Lie Hetland') # 调用__init__
print(py_book) # 调用__str__方法
py_book() # 调用__call__方法
re模块
正则表达式
- 匹配单个字符
- 匹配一组字符
- 其他元字符
给mac码加冒号
192.168.1.1 000C29123456
192.168.1.2 525400A3B8C1
:%s/\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)$/\1:\2:\3:\4:\5:\6/
re核心函数及方法
match函数
search函数
group方法
findall函数
finditer函数
compile函数
split方法
sub方法
>>> import re
# match只能从字符串开头匹配
>>> re.match('f..', 'food') # 在food中匹配f..,匹配到返回匹配对象
<_sre.SRE_Match object; span=(0, 3), match='foo'>
>>> re.match('f..', 'seafood') # 匹配不到,返回None
>>> print(re.match('f..', 'seafood'))
None
# search应用更多,可以在字符串任意位置匹配
>>> m = re.search('f..', 'seafood')
>>> m.group() # 通过group方法取出匹配内容
'foo'
# search只匹配到第一个满足条件的字符串,findall匹配到全部,返回列表
>>> re.findall('f..', 'seafood is food')
['foo', 'foo']
# finditer返回所有匹配对象的生成器
>>> re.finditer('f..', 'seafood is food')
<callable_iterator object at 0x7f5764824828>
>>> list(re.finditer('f..', 'seafood is food'))
[<_sre.SRE_Match object; span=(3, 6), match='foo'>, <_sre.SRE_Match object; span=(11, 14), match='foo'>]
>>> for m in re.finditer('f..', 'seafood is food'):
... m.group()
...
'foo'
'foo'
# 字符串的切割方法,只能指定一个分隔符
>>> s = 'hello-world-ni-hao.tar.gz'
>>> s.split('-')
['hello', 'world', 'ni', 'hao.tar.gz']
>>> s.split('.')
['hello-world-ni-hao', 'tar', 'gz']
# 正则的切割符,可以指定多个
>>> re.split('-|\.', s)
['hello', 'world', 'ni', 'hao', 'tar', 'gz']
# 字符串的替换方法
>>> s.replace('-', '/')
'hello/world/ni/hao.tar.gz'
# 正则表达式的替换
>>> re.sub('-|\.', '/', s)
'hello/world/ni/hao/tar/gz'
# 当有大量匹配时,为了有更好的效率,可以将正则的模式先进行编译
>>> patt = re.compile('f..')
>>> m = patt.search('seafood')
>>> m.group()
'foo'
>>> patt.findall('seafood is food')
['foo', 'foo']
编写apach.py脚本,实现日志分析:
1.统计每个客户端访问apache服务器的次数
2.将统计信息通过字典的方式显示出来
3.分别统计客户端是Firefox和MSIE的访问次数
4.分别使用函数式编程和面向对象编程的方式实现
- 脚本实现生ip访问降序排列
– 列表的sort方法,接受一个名为key的参数
– key需要是一个函数
– key函数处理列表的每一项,将处理结果作为排序依据。
– key函数不改变列表
>>> result = {'172.40.58.150': 10, '172.40.58.124': 6, '172.40.58.101': 10, '127.0.0.1': 121, '192.168.4.254': 103, '192.168.2.254': 110, '201.1.1.254': 173, '201.1.2.254': 119, '172.40.0.54': 391, '172.40.50.116': 244}
>>> list(result.items())
[('172.40.58.150', 10), ('172.40.58.124', 6), ('172.40.58.101', 10), ('127.0.0.1', 121), ('192.168.4.254', 103), ('192.168.2.254', 110), ('201.1.1.254', 173), ('201.1.2.254', 119), ('172.40.0.54', 391), ('172.40.50.116', 244)]
>>> l = list(result.items())
>>> def get_last(seq): # 接受一个序列对象
... return seq[-1] # 返回序列中的最后一项
...
>>> l.sort(key=get_last)
>>> l
[('172.40.58.124', 6), ('172.40.58.150', 10), ('172.40.58.101', 10), ('192.168.4.254', 103), ('192.168.2.254', 110), ('201.1.2.254', 119), ('127.0.0.1', 121), ('201.1.1.254', 173), ('172.40.50.116', 244), ('172.40.0.54', 391)]
# 因为get_last函数非常简单,所以可以不定义它,直接使用匿名函数
>>> l.sort(key=lambda seq: seq[-1], reverse=True) # 使作匿名函数,并降序排列
import re
def count_patt(fname, patt):
'用于在文件中统计每个模式字符串出现的次数'
result = {} # 定义用于保存结果的变量
cpatt = re.compile(patt) # 为了有更高的匹配效率,编译模式
# 遍历文件,在每一行中匹配模式,匹配到了就更新到字典中
with open(fname) as fobj:
for line in fobj:
m = cpatt.search(line)
if m: # 如果匹配到了内容
k = m.group()
result[k] = result.get(k, 0) + 1
# if k not in result:
# result[k] = 1
# else:
# result[k] += 1
return result
if __name__ == '__main__':
fname = 'access_log'
ip = '^(\d+\.){3}\d+' # 1234.56789.10.2 192.168.10.5
br = 'Firefox|MSIE'
result1 = count_patt(fname, ip)
result2 = count_patt(fname, br)
# print(result1)
l = list(result1.items())
l.sort(key=lambda seq: seq[-1], reverse=True)
print(l)
print(result2)
- 使用oop
import re
class CountPatt:
def count_patt(self, fname, patt):
'用于在文件中统计每个模式字符串出现的次数'
result = {} # 定义用于保存结果的变量
cpatt = re.compile(patt) # 为了有更高的匹配效率,编译模式
# 遍历文件,在每一行中匹配模式,匹配到了就更新到字典中
with open(fname) as fobj:
for line in fobj:
m = cpatt.search(line)
if m: # 如果匹配到了内容
k = m.group()
result[k] = result.get(k, 0) + 1
return result
if __name__ == '__main__':
fname = 'access_log'
ip = '^(\d+\.){3}\d+' # 1234.56789.10.2 192.168.10.5
cp1 = CountPatt() # 创建实例
result1 = cp1.count_patt(fname, ip)
print(result1)
- 使用__init__
import re
class CountPatt:
def __init__(self, fname):
self.fname = fname
def count_patt(self, patt):
'用于在文件中统计每个模式字符串出现的次数'
result = {} # 定义用于保存结果的变量
cpatt = re.compile(patt) # 为了有更高的匹配效率,编译模式
# 遍历文件,在每一行中匹配模式,匹配到了就更新到字典中
with open(self.fname) as fobj:
for line in fobj:
m = cpatt.search(line)
if m: # 如果匹配到了内容
k = m.group()
result[k] = result.get(k, 0) + 1
return result
if __name__ == '__main__':
fname = 'access_log'
ip = '^(\d+\.){3}\d+' # 1234.56789.10.2 192.168.10.5
br = 'Firefox|MSIE|Chrome'
cp1 = CountPatt(fname) # 创建实例
result1 = cp1.count_patt(ip)
print(result1)
result2 = cp1.count_patt(br)
print(result2)