9月22日学习内容整理:内置函数补充,反射,类的内置方法,常用模块
补充:软件开发规范,bin,conf,core,db,lib,log
内置函数补充:isinstance(obj,Foo) 判断obj是否是Foo的对象
issubclass(a,b) 判断a是否是b的子类
一、反射
1、概念:
(1)通过字符串的形式操作对象相关的属性
(2)把一个字符串变量变成一个程序中存在的变量名,并去使用它
2、四种实现函数
(1)getattr() 字符串形式的程序中的名字就可以直接执行
(2)hasattr() 判断程序中是否有字符串形式的的对象属性和方法
a)注意两者要结合起来用,先判断再再执行
b)应用场景:
① getattr(对象名,字符串)对象名去调用,字符串是方法名就得到一个方法名,加括号直接调用;字符串是属性名就直接得到属性的内容
② getattr(类名,字符串) 用类名调用,但是字符串形式的名字必须是静态方法或是类方法,不能是普通方法,因为必须加self参数
③ getattr(模块名,字符串) 用导入的模块名调用,字符串形式的名字必须是模块里的名字
④ getattr(自己模块名,字符串)把自己写的程序当作模块去调用,这种方法可以应用在字符串让用户输入,就可以直接执行用户输入名字对应的程序了
xiaoxuanxuan = 2222 import sys print(sys.modules[__name__]) print(getattr(sys.modules[__name__],'xiaoxuanxuan'))
(3)setattr(对象名,字符串1,字符串2) 字符串1为属性名,字符串2为修改的值,若属性存在就修改,若属性不存在就添加,一般不用这个方法去改变方法
(4)delattr(对象名,字符串) 删除字符串形式的属性名
二、类的内置方法
(1)_ _format_ _ 自制字符串格式化
(2)_ _str_ _ _ _repr_ _ 改变对象的字符串显示,1)打印对象时就会显示两个方法的返回值,这两个方法没有本质区别 2)最大的区别就是外部执行str(对象)时如果没有__str__方法就还是打印内存地址不会去执行__repr__方法,repr(对象)时有哪个就执行哪个,所以推荐用__repr__方法
(3)_ _del_ _ del 对象名时就触发(这是我们主动触发),析构方法,当对象在内存中被释放时自动触发执行,也就是被删除了或者被回收了,回收是解释器触发
(4)_ _call_ _ 当对象名()时就触发
(5)_ _len_ _ len(对象名)时触发,这样就会触发对象所在类的__len__方法,我们常见的len内置函数其实本质上也是调用内部的__len__方法,所以我们说内置函数和类的内置方法有着千丝万缕的关系
(6)_ _eq_ _ 对象名1 == 对象名2时触发,self.kind == other.kind 代表的是比较不同对象的相同属性值,因为没法写self.kind==self.kind
(7)_ _hash_ _ 当hash(对象名)触发
(8)item系列
① _ _getitem_ _(self,参数)对象名[参数]就触发
② _ _setitem_ _(self,key,value)key是属性名,value是属性值,修改或添加
③_ _delitem_ _ 删除
(9)_ _new_ _
a)执行_ _init_ _前触发
b)创建一个对象,相当于一个裸着的对象,没有赋予它任何属性,所以也不能说它属于哪个类
c)必须传一个参数cls
d)应用:单例模式:怎么实例化都是一个对象,也就是实例始终只有一个,只不过属性会随着传入的参数不同而改变
#单例模式 实例始终只有一个 他的属性可以随着你的改变而改变 class Teacher: #创建一个老师类 __isinstance = None #创建一个私有静态变量来装裸着的对象 def __new__(cls, *args, **kwargs): #创建一个裸着的对象 if not cls.__isinstance: #如果__isinstance属性为None cls.__isinstance = object.__new__(cls) #用object.__new__创建一个裸着的对象 return cls.__isinstance #返回一个对象 def __init__(self,name,cloth): #self就是cls.__isinstance返回的对象 self.name = name #给self的name属性赋值 self.cloth = cloth #给self的cloth属性赋值 l = Teacher('刘永熹','白色') print(l.name) w = Teacher('王庆帅','黑色') w2 = Teacher('王庆帅','黑色') w3 = Teacher('王庆帅','黑色') w4 = Teacher('王庆帅','黑色') print(l.name) print(w) print(w2) print(w3) print(w4)
三、常用模块
1、hashlib模块:摘要算法
(1)作用:检验文件一致性;存储密文密码
》》》检验文件一致性;
(2)算法:md5算法(所有语言通用的) 速度很快,生成固定的128字节,还有一种SHA1算法,这种算法比md5更安全,但是慢,越安全的越慢
obj=hashlib.md5()创建一个md5对象
obj.update(字节类型)对数据进行加密,必须是字节类型
obj.hexdigest() 显示加密的结果
》》》》》》》注意::::
a) 与hash的区别:hash值是程序每一次执行的结果都会不一样,而md5加密的结果无论程序执行多少次都是一样的
b) 支持一部分一部分的做摘要,对于一个文本文件来说,一整段做摘要和分段做摘要md5的结果是一样的
c) md5结果是不可逆的,不能根据md5加密的结果反推出被加密的数据,只能正向
d) 对于文本文件来说,按行读;对于视频图片这类没有行的文件来说,按字节数读(read(1024))
》》》存储密文密码:
先将密码摘要到文件中,再让用户输入密码进行摘要,两者进行比较
》》》暴力破解(撞库):md5算法存在着不安全性,太简单的密码md5值很容易就被破解
这就需要用到《加盐》操作
加盐:::创建md5对象时,hashlib.md5(字节类型),这个字节类型就是盐,这样加密出来的结果因为别人不知道你的盐是什么,所以破解起来有难度
2、configparser 模块:对配置文件的操作
(1)作用:对配置文件进行读写删增的操作
(2)适用范围:只针对特定格式的文件,文件中有字段值(就是section),每个字段中也有参数键(option)=值(value)这种类型,其实可以理解为一个大字典,里面还嵌套着字典
类似于这样的文件:::
[DEFAULT] #字段值 section ServerAliveInterval = 45 #option = value 相当于键值对 Compression = yes CompressionLevel = 9 ForwardX11 = yes [bitbucket.org] User = hg [topsecret.server.com] Port = 50022 ForwardX11 = no
(3)实际应用中很难说正好碰见这样一种文件,大多时候是需要我们自己去构造的,整体思路就是创建一个大字典
import configparser config = configparser.ConfigParser() config["DEFAULT"] = {'ServerAliveInterval': '45', 'Compression': 'yes', 'CompressionLevel': '9', 'ForwardX11':'yes' } config['bitbucket.org'] = {'User':'hg'} config['topsecret.server.com'] = {'Host Port':'50022','ForwardX11':'no'} with open('example.ini', 'w') as configfile: config.write(configfile) #将创建好的配置文件内容写到文件中去
(4)对文件进行读写操作
import configparser config = configparser.ConfigParser() #创建一个对象 #---------------------------查找文件内容,基于字典的形式 print(config.sections()) # 什么都打印不出来,因为创建出的对象和文件这时还没有任何关系 config.read('example.ini') # 将文件和config对象绑定,这样就可以对配置文件进行操作了 print(config.sections()) # 打印配置文件中的字段值,没有DEFAULT ['bitbucket.org', 'topsecret.server.com'] print('bytebong.com' in config) # False,在取值之前可以先判断字段是否在配置文件中 print('bitbucket.org' in config) # True print(config['bitbucket.org']["user"]) # hg 取值,类似于字典根据key取value print(config['DEFAULT']['Compression']) #yes print(config['topsecret.server.com']['ForwardX11']) #no print(config['bitbucket.org']) #<Section: bitbucket.org> 取字段下(section)的值,这是个迭代器,可for循环取值 for key in config['bitbucket.org']: # 注意,有default会默认default的键 能够打印出包括default中的值 print(key) print(config.options('bitbucket.org')) # 同for循环,找到'bitbucket.org'字段(section)下所有键 print(config.items('bitbucket.org')) #找到'bitbucket.org'下所有键值 print(config.get('bitbucket.org','compression')) # yes get方法Section下的key对应的value,没有会报错
(5)对文件进行删除增加操作
import configparser config = configparser.ConfigParser() #创建对象 config.read('example.ini') #和配置文件绑定 config.add_section('yuan') #添加一个节 config.remove_section('bitbucket.org') #删除掉一个节 config.remove_option('topsecret.server.com',"forwardx11") #删除掉节(section)下的一个键值对(option=value) config.set('topsecret.server.com','k1','11111') #创建一个节,分别对应section(字段值),option(字段中的key),value(key下的值) config.set('yuan','k2','22222') #也是创建一个节 config.write(open('new2.ini', "w")) #将创建好的节写到一个新配置文件中,也就相当于对原配置文件的修改
》》》注意::
(1)DEFAULT不能随意修改,它是默认值,是其余section字段的公共信息,默认是不打印的
3、logging 模块:对日志进行操作
(1)作用:对日志进行操作
(2)用法:
》》》写功能(相当于笔,把信息写下来):默认打印到屏幕上,从warning开始打印,优先级从低到高如下
debug(具体的信息)
info (具体的信息)
warning(具体的信息)
error(具体的信息)
critical(具体的信息)
》》》配置函数和配置参数:是为了解决能够直接打印到文件中,并且可以设置我们想要的格式和打印的优先级
配置函数::basicconfig()
相关参数:
设置打印的优先级(默认从哪一级开始打印):level=logging.DEBUG, 设置打印的格式(必须按照要求的关键字这么写):format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', 设置时间格式:datefmt='%a, %d %b %Y %H:%M:%S', 设置文件名:filename='/tmp/test.log', 设置文件模式:filemode='w')
具体的参数含义:
logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有: filename:用指定的文件名创建FiledHandler,这样日志会被存储在指定的文件中。 filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。 format:指定handler使用的日志显示格式。 datefmt:指定日期时间格式。 level:设置rootlogger(后边会讲解具体概念)的日志级别 stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件(f=open(‘test.log’,’w’)),默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。 format参数中可能用到的格式化串: %(name)s Logger的名字 %(levelno)s 数字形式的日志级别 %(levelname)s 文本形式的日志级别 %(pathname)s 调用日志输出函数的模块的完整路径名,可能没有 %(filename)s 调用日志输出函数的模块的文件名 %(module)s 调用日志输出函数的模块名 %(funcName)s 调用日志输出函数的函数名 %(lineno)d 调用日志输出函数的语句所在的代码行 %(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示 %(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数 %(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒 %(thread)d 线程ID。可能没有 %(threadName)s 线程名。可能没有 %(process)d 进程ID。可能没有 %(message)s用户输出的消息
》》》logger对象:为了解决能够同时对文件和屏幕输出
代码步骤:
(1)创建logger对象
(2)设置打印级别
(3)创建文件输出或者屏幕输出操作符
(4)设置打印信息的输出格式
(5)设置文件或屏幕的输出格式
(6)将文件输出操作符或者屏幕输出操作符和logger对象绑定
举例:
import logging logger = logging.getLogger() #创建一个logger对象 logger.setLevel(logging.DEBUG) #设置打印级别 fh = logging.FileHandler('test.log')# 创建一个handler,也就是文件输出操作符,用于写入日志文件 ch = logging.StreamHandler()# 再创建一个handler,也就是屏幕(或者自带的输出平台)输出操作符用于输出到控制台 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') #设置输出格式 fh.setFormatter(formatter) #设置文件输出的格式,也就是将文件输出操作符和信息输出格式绑定 ch.setFormatter(formatter) #设置屏幕输出格式 logger.addHandler(fh) #绑定logger对象和文件输出操作符 logger.addHandler(ch)#绑定logger对象和屏幕输出操作符 logger.debug('logger debug message') #具体的打印信息 logger.info('logger info message') logger.warning('logger warning message') logger.error('logger error message') logger.critical('logger critical message')
》》》》注意:::
(1)logger对象可操作性强,可输出到多个文件,每种输出格式也可以不一样,可满足多种需求
(2)具体的错误信息要自己去输或者指定,没法自动打印
(3)若需要打印的错误信息中包含中文,写到文件中可能会有乱码,在创建文件输出操作符加入编码设置即可
fh=FileHandler('a.txt','encoding='utf-8')
(4)logging模块只针对字符串进行操作
(5)配置函数其实相对配置起来比较简单,若需求只是打印到文件中就用basicconfig函数就行