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函数就行

 

posted @ 2017-09-22 19:57  九二零  阅读(150)  评论(0编辑  收藏  举报