当前位置: 首页 > 工具软件 > magic8bot > 使用案例 >

Python从基础到精通day8

邹举
2023-12-01

OOP基础 、 OOP进阶 、 re模块

OOP

  • 面向对象的编程
  • 在python中,一切皆对象
  • 对象有属性和方法,通过句点表示
  • 对象通过class生成
  • 类(class)用来描述具有相同属性和方法的对象的蓝图。
  • 对象(实例):通过class生成的具体的数据结构。
  • 方法:定义在class中的函数。
  • 绑定在实例上的属性,可以在class中的任何地方使用。没有绑定的数据就是函数的局部变量,只能在函数内使用。
class Role:
    def __init__(self,name,weapon):

        self.name = name
        self.weapon = weapon

    def show_me(self):
            print('我是%s,善用%s' %(self.name,self.weapon))

if __name__ == '__main__':
    lb = Role('鲁班','炮')
    zf = Role('张飞','丈八蛇矛')
    print(lb.name,lb.weapon)
    print(zf.name,zf.weapon)
    lb.show_me()
    zf.show_me()

测试运行
[root@python day8]# python3 lianxi.py
鲁班 炮
张飞 丈八蛇矛
我是鲁班,善用炮
我是张飞,善用丈八蛇矛

组合和继承

  • 两个类明显不同,其中一个类是另一个类的组件,使用组合
  • 如果两个类有很多相似之处,但是仍有不同,可以使用继承
    • 子类可以有多个父类,子类继承所有父类的方法
    • 如果父子类有重名的方法,查找顺序是自下向上,自左向右
class Role:
    def __init__(self,name,weapon):
        #构造器方法,用于将属性绑定到实例
        self.name=name
        self.weapon=weapon

class Weapon:
    def __init__(self,wname,type,strength):
        self.wname = wname
        self.type = type
        self.strength = strength

if __name__ == '__main__':
    ji = Weapon('方天画戟','物理攻击','1000')
    print(ji.wname,ji.type,ji.strength)
    lb = Role('吕布',ji)
    print(lb.weapon.wname,lb.weapon.type,lb.weapon.strength)

一个子类可以有多个父类

当字类里有和父类里一样的函数,先调用子类在调用父类

class A:
    def func1(self):
        print('A func1')
class B:
    def func2(self):
        print('B func2')
class C(A,B):
    def func3(self):
        print('C func3')

if __name__ == '__main__':
    c1 = C()
    c1.func3()
    c1.func2()
    c1.func1()

子类和父类有同样的方法,如何执行子类

class User:
    def __init__(self,name,brith,sex,email,phone):
        self.name= name
        self.brith = brith
        self.sex = sex
        self.email = email
        self.phone = phone

class Student(User):
    def __init__(self,name,brith,sex,email,phone,qq):
        User.__init__(self,name,brith,sex,email,phone) #使用父类定义的属性
        self.qq = qq

if __name__ == '__main__':
    tom = Student('Tom','1999-1-2','bot','12352@qq.com','12345242','42135902402')
    print(tom.name,tom.qq)

特殊方法

  • 在oop中,以双下划线开头和结尾的方法被称作magic魔法方法。
  • 可以通过dir()函数查询对象属性
  • 大部分的魔法方法是为了实现对象自身的功能,用户编程时很少使用。
  • 常用的三种magic是:
    • __init__:构造函数
    • __str__ :显示、打印实例时自动调用
    • __call__:可以让实例像函数一样调用
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__':
    # 实例化,自动调用__init__
    pybook = Book('A Byte Of Python', 'Swaroop, C. H.')
    print(pybook)  # 自动调用__str__方法
    pybook()   # 自动调用__call__方法

vim设置

>
> ```shell
> # vim ~/.vimrc
syntax on
 filetype plugin on
 set ai
>set et
 set ts=4
 set cursorline
 set scrolloff=7
 nnoremap <C-a> <Home>
 nnoremap <C-e> <End>
 nnoremap <F2> :set nu! nu?<CR>
 nnoremap ; :
 autocmd FileType yaml setlocal sw=2 ts=2 et ai

正则表达式:

. 匹配单个任意字符
[x-y] 匹配字符组里的任意字符
[ ^x-y] 取反
\d 匹配任意数字,与[0-9]同义,大写为取反,digest单词缩写
\w 匹配数字字母下划线,大写为取反
\s 配置空白字符,大写为取反 ,space单词缩写

re1|re2 匹配re1或者re2,管道需要用 \ 转译
‘*’ 匹配前面的正则表达式出现0次或多次
‘+’ 匹配前面的正则表达式出现1次以上的,需要用 \ 转译
‘?’ 匹配前面出现的正则表达式零次或一次的,需要用 \ 转译
{M,N} 配置前面出现的正则表达式至少M次到N次之间的

‘^’ 匹配字符串的开头
‘$’ 匹配字符串的结尾
‘\b’ 匹配单词的边界
() 对正则表达式分组
\nn 匹配已保存的子组

## 正则表达式

- 为MAC地址加冒号

```shell
192.168.1.1     000C29123456
192.168.1.2     525400AB32C8

:%s/\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)$/\1:\2:\3:\4:\5:\6/
% 表示全文	s表示替换	\1表示调用第一组()	在每组之间加上冒号
先找到十二位以$结尾的字符

re模块

>>> import re
# 在food开头匹配f..,匹配到返回匹配对象,匹配不到返回None
>>> m = re.match('f..', 'food')
>>> print(m)
<_sre.SRE_Match object; span=(0, 3), match='foo'>
>>> m1 = re.match('f..', 'seafood')
>>> print(m1)
None

# 从seafood中匹配f..
>>> m2 = re.search('f..', 'seafood')
>>> print(m2)
<_sre.SRE_Match object; span=(3, 6), match='foo'>
>>> m2.group()  # 匹配对象的group方法返回匹配值
'foo'

# 匹配所有的f..,返回列表
>>> re.findall('f..', 'seafood is food')
['foo', 'foo']

# finditer与findall类似,只不过它返回的是匹配对象的生成器
>>> for m in re.finditer('f..', 'seafood is food'):
...   print(m.group())

# 把字符串中的X换成zzg
>>> re.sub('X', 'zzg', 'Hi X, ni hao X')
'Hi zzg, ni hao zzg'

# 以-和.作为分隔符切分字符串
>>> re.split('-|\.', 'hello-world-ni-hao.teu.com.cn')
['hello', 'world', 'ni', 'hao', 'teu', 'com', 'cn']

# 如果有大量匹配,那么把正则表达式模式先编译,会有更好的执行效率
>>> patt = re.compile('f..')
>>> m = patt.search('seafood')
>>> m.group()
'foo'
>>> patt.findall('seafood is food')
['foo', 'foo']

案例:
匹配日志文件,将IP地址和客户使用的浏览器统计出来

import re

def count_patt(fname,patt):
    result = {}  #定义保存数据的变量
    cpatt = re.compile(patt)  #将模式先编译好,提高效率

    #打开文件利用for循环遍历文件
    with open(fname) as fobj:
        for line in fobj:
            m = cpatt.search(line)
            if m: #匹配到内容为真,匹配不到返回None
                key = m.group() #将匹配到的字符串传给变量key
                result[key] = result.get(key,0) + 1 #匹配到一样的字符串就加一

    return result

if __name__ == '__main__':
    fname = 'access_log'
    ip = '^(\d+\.){3}\d+' #\d表示匹配数字,{3}匹配三次,+表示匹配前面字符串出现1次或以上
    br = 'Firefox | MSIE| Chrome' #匹配浏览器
    result1 = count_patt(fname,ip)
    result2 = count_patt(fname,br)
    print(result1)
    print(result2)

将程序改写为OOP的格式:

import re

class CountPatt:
    def count_patt(self,fname,patt):
        result = {}  #定义保存数据的变量
        cpatt = re.compile(patt)  #将模式先编译好,提高效率

        #打开文件利用for循环遍历文件
        with open(fname) as fobj:
            for line in fobj:
                m = cpatt.search(line)
                if m: #匹配到内容为真,匹配不到返回None
                    key = m.group() #将匹配到的字符串传给变量key
                    result[key] = result.get(key,0) + 1 #匹配到一样的字符串就加一

        return result

if __name__ == '__main__':
    fname = 'access_log'
    ip = '^(\d+\.){3}\d+' #\d表示匹配数字,{3}匹配三次,+表示匹配前面字符串出现1次或以上
    br = 'Firefox | MSIE| Chrome' #匹配浏览器
    cp = CountPatt() #创建对象(实例),由于构造器没有_init_所以就写()不加东西
    result1 = cp.count_patt(fname,ip)   #创建实例调用方法,并将返回值赋给result
    result2 = cp.count_patt(fname,br)
    print(result1)
    print(result2)

代码优化三:

import re

class CountPatt:
    def __init__(self,fname):  #将属性绑定
        self.fname = fname

    def count_patt(self,patt):
        result = {}  #定义保存数据的变量
        cpatt = re.compile(patt)  #将模式先编译好,提高效率

        #打开文件利用for循环遍历文件
        with open(self.fname) as fobj:
            for line in fobj:
                m = cpatt.search(line)
                if m: #匹配到内容为真,匹配不到返回None
                    key = m.group() #将匹配到的字符串传给变量key
                    result[key] = result.get(key,0) + 1 #匹配到一样的字符串就加一

        return result

if __name__ == '__main__':
    fname = 'access_log'
    ip = '^(\d+\.){3}\d+' #\d表示匹配数字,{3}匹配三次,+表示匹配前面字符串出现1次或以上
    br = 'Firefox | MSIE| Chrome' #匹配浏览器
    cp = CountPatt(fname) #创建对象,
    result1 = cp.count_patt(ip)
    result2 = cp.count_patt(br)
    print(result1)
    print(result2)
    
    cp2 = CountPatt('/etc/passwd')  #创建实例2
    sh = 'bash$|nologin$'  #过滤以bash结尾或者以nologin结尾的行
    result3 = cp2.count_patt(sh)
    print(result3)

案例3,测试运行如下:

[root@python python]# python3 wenhao.py 
{'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}
{' Chrome': 24, ' MSIE': 391}
{'bash': 7, 'nologin': 38}

复杂列表的排序

  • 字典不能排序,如果需要对字典排序,先将它转换成列表
  • 列表的sort()方法,接受一个名为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}
>>> l1 = list(result.items())
>>> l1
[('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)]

>>> def func1(seq):
...   return seq[-1]
... 
>>> l1.sort(key=func1)
>>> l1
[('172.40.58.124', 6), ('172.40.58.101', 10), ('172.40.58.150', 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)]

 **使用匿名函数,并且降序排列**
>>> l1.sort(key=lambda seq: seq[-1], reverse=True)
>>> l1
[('172.40.0.54', 391), ('172.40.50.116', 244), ('201.1.1.254', 173), ('127.0.0.1', 121), ('201.1.2.254', 119), ('192.168.2.254', 110), ('192.168.4.254', 103), ('172.40.58.101', 10), ('172.40.58.150', 10), ('172.40.58.124', 6)]
 类似资料: