源码背景

Faker是一个Python第三方库,GITHUB开源项目,主要用于创建伪数据创建的数据包含地理信息类、基础信息类、个人账户信息类、网络基础信息类、浏览器信息类、文件信息类、数字类 文本加密类、时间信息类、其他类别等。

源码解读

主源码解读

通过直接点击初始化的类进入类初始化模块

fake = Faker(locale='zh_CN')

核心的源码搬运如下:

proxy.py文件

from __future__ import absolute_import, unicode_literals

from collections import OrderedDict

import random

import re

import six

from faker.config import DEFAULT_LOCALE

from faker.factory import Factory

from faker.generator import Generator

from faker.utils.distribution import choices_distribution

class Faker(object):

"""Proxy class capable of supporting multiple locales"""

cache_pattern = re.compile(r'^_cached_\w*_mapping$')

generator_attrs = [

attr for attr in dir(Generator)

if not attr.startswith('__')

and attr not in ['seed', 'seed_instance', 'random']

]

def __init__(self, locale=None, providers=None,

generator=None, includes=None, **config):

self._factory_map = OrderedDict()

self._weights = None

if isinstance(locale, six.string_types):

locales = [locale.replace('-', '_')]

# This guarantees a FIFO ordering of elements in `locales` based on the final

# locale string while discarding duplicates after processing

elif isinstance(locale, (list, tuple, set)):

assert all(isinstance(l, six.string_types) for l in locale)

locales = []

for l in locale:

final_locale = l.replace('-', '_')

if final_locale not in locales:

locales.append(final_locale)

elif isinstance(locale, OrderedDict):

assert all(isinstance(v, (int, float)) for v in locale.values())

odict = OrderedDict()

for k, v in locale.items():

key = k.replace('-', '_')

odict[key] = v

locales = list(odict.keys())

self._weights = list(odict.values())

else:

locales = [DEFAULT_LOCALE]

for locale in locales:

self._factory_map[locale] = Factory.create(locale, providers, generator, includes, **config)

self._locales = locales

self.AQ_factories = list(self._factory_map.values())

文件主要引入了内部类以及collections.OrderedDict,random,six等外部包。

以下对相应的关键外部包做个说明:

1、collections.OrderedDict实现了对字典对象中元素的排序,由于python的字典是按照hash值进行存储的所以,导致字典是无序状态,OrderedDict实现了对字典对象中元素的排序

2、six这个名字来源于 6 = 2 x 3,其产生主要是为了解决Python2 和 Python3 代码兼容性

初始化的开头按一定规则将Generator类下的属性保存在generator_attrs中,以备后续方法调用。在init的初始化中规定了类的入参有哪些?同时定义了两个名义上的私有变量,来防止外部调用类方法,说他是名义上的私有变量是因为python中没有真正的私有化,不管是方法还是属性,为了编程的需要,约定加了下划线 _的属性和方法不属于API,不应该在类的外面访问,也不会被from M import * 导入。但是注意你想调用也可以调用。self._factory_map中保存的是OrderedDict()的实例化对象;self._weights为了保证其在类中被调用,赋予初始化的None值。接下来的是对入参locale的条件判断,示意图基本如下:

proxy.py文件

if isinstance(locale, six.string_types):

如果入参的locale是字符串,则替换-线为_线,保存在locales中

elif isinstance(locale, (list, tuple, set)):

如果入参的locale是列表,元祖,集合,则遍历入参判断元素为字符串后将元素替换-线为_线保存在locales中

elif isinstance(locale, OrderedDict):

如果入参的locale是有序字典,则遍历入参判断键为字符串后将键替换-线为_线保存在locales中,将键的值保存在之前定义的self._weights中

locales = list(odict.keys())

self._weights = list(odict.values())

else:

以上条件都不满足时,将配置文件中自定义的locale保存到列表中赋值给locales

为什么在locale这个入参要做那么多的校验呢,是因为在初始化是locale做了一件很重要的事,而这件事对locale的要求很高,具体来看源码:

proxy.py文件

for locale in locales:

self._factory_map[locale] = Factory.create(locale, providers, generator, includes, **config)

源码在这里主要做了对每种语言创建了一个map字典,里面涉及到了Factory工厂模式下的创建方法,入参基本为当前类的入参。那么Faker除了对locale入参进行了校验外,有没有做其他的校验呢?答案是肯定的在对关键属性self._weights、self._factories、self._factory_map.items(),通过object下的@property装饰器进行了只读的校验,外部修改。

魔法方法解读

对类的实例化后需要使用实例里面的属性,那么为了增加其扩展性加了getitem的魔法方法使的我们可以对Fake()['pujen']操作,那么在Faker中Fake()['pujen']会返回啥呢,源码中运算结果为KeyError,当然了因为Faker中没有pujen这个语言包。

proxy.py文件

def __getitem__(self, locale):

return self._factory_map[locale.replace('-', '_')]

fake = Faker(locale='zh_CN')

print(fake['zh_CN'])

>>>

接下来看一个实例来更好的去理解什么是getitem魔法方法

class Fake(object):

def __init__(self):

self.name = 'jack'

def __getitem__(self,item):

if item in self.__dict__: # item = key,判断该key是否存在对象的 __dict__ 里,

return self.__dict__[item] # 返回该对象 __dict__ 里key对应的value

def __setitem__(self, key, value):

self.__dict__[key] = value # 在对象 __dict__ 为指定的key设置value

def __delitem__(self, key):

del self.__dict__[key] # 在对象 __dict__ 里删除指定的key

f1 = Fake()

print(f1['name']) # jack

f1['age'] =10

print(f1['age']) # 10

del f1['name']

print(f1.__dict__) # {'age': 10}

接下来看一下getattribute__方法,这个方法出现在这个类中主要是因为防止seed()方法的直接调用而是要形如Faker.seed()这样的调用,在Faker的源码中seed()实际是Generator.seed()一种随机种子函数。假设调用类的方法中不是seed()而是其他非此类方法,那么会执行__getattr方法,这个方法在Faker里面主要是干了什么呢:

proxy.py文件

def __getattr__(self, attr):

"""

Handles cache access and proxying behavior

:param attr: attribute name

:return: the appropriate attribute

"""

条件语句判断异常情况,最后走如下代码

factory = self._select_factory(attr)

return getattr(factory, attr)

工厂模式

在初始化中我们会发现核心的内容最后都是由工厂模式的Factory.create()创建接下来看一下此工厂函数。在Factory中create()是以静态类方法来体现

factory.py文件

@classmethod

def create(

cls,

locale=None,

providers=None,

generator=None,

includes=None,

**config):

if includes is None:

includes = []

# fix locale to package name

locale = locale.replace('-', '_') if locale else DEFAULT_LOCALE

locale = pylocale.normalize(locale).split('.')[0]#返回规范化的语言环境代码

if locale not in AVAILABLE_LOCALES:

msg = 'Invalid configuration for faker locale `{0}`'.format(locale)

raise AttributeError(msg)

config['locale'] = locale

providers = providers or PROVIDERS#排序的集合

providers += includes

faker = generator or Generator(**config)

for prov_name in providers:

if prov_name == 'faker.providers':

continue

prov_cls, lang_found = cls._get_provider_class(prov_name, locale)#prov_cls=faker.providers,lang_found语言包名称

provider = prov_cls(faker)#继承在Generator类中

provider.__provider__ = prov_name

provider.__lang__ = lang_found

faker.add_provider(provider)#增加类的方法和属性

return faker

从上面的源码可以梳理出来,基本就是给类增加方法和规范一下语言包。我们对里面的一些细节代码梳理一下:

factory.py文件

1、

providers += includes

providers是一个空列表

includes是一个集合数据

那么假设providers=[],includes={1,2,3,4}

则providers += includes运行结果,会使的providers=[1,2,3,4],实际这段代码就是将集合的数据放到空列表中。

2、

faker = generator or Generator(**config)

provider = prov_cls(faker)

这里faker是generator类,prov_cls实际上是一个类,那么prov_cls(faker)实际就是继承了Generator类

3、

provider.__provider__ = prov_name

provider.__lang__ = lang_found

faker.add_provider(provider)#增加类的方法和属性

给这些类赋予方法名和语言包,同时通过魔法方法增加类的方法和属性,这里面涉及到Generator.add_provider()方法

Faker隐藏主方法类

以上工厂模式中create()主函数方法基本也介绍完了,类内部的其他方法暂时不过多的研究。接下来看一下在create()中涉及到的Generator.add_provider()方法,方法的源码如下:

generator.py文件

def add_provider(self, provider):

if isinstance(provider, type):

provider = provider(self)

self.providers.insert(0, provider)#将provider插入到0索引位置

for method_name in dir(provider):

# skip 'private' method

if method_name.startswith('_'):

continue

faker_function = getattr(provider, method_name)#动态运行函数

if callable(faker_function):#函数用于检查一个对象是否是可调用的

# add all faker method to generator

self.set_formatter(method_name, faker_function)

针对如下的这个用法做一下基本的说明,后续我们写代码的时候可以作为借鉴

if isinstance(provider, type):

说明:如果对象参数是classinfo参数的实例,或者是它的一个(直接、间接或虚拟)子类的实例,则返回True。如果对象不是给定类型的对象,则该函数始终返回False。如果classinfo是类型对象的元组(或者递归地,其他类似的元组),如果对象是任何类型的实例,则返回True。如果classinfo不是类型的类型或元组,而这些元组又不是类型的元组,则会引发类型错误异常。

for method_name in dir(provider):

dir的用法说明,如果provider类或者模块没有定义dir方法则返回类或者模块的方法属性

接下来看一下这两个方法,主要是用于动态调用函数返回运行对象

faker_function = getattr(provider, method_name)#动态运行函数

if callable(faker_function):#函数用于检查一个对象是否是可调用的

至此,Generator类中的核心方法介绍完成!

Faker里方法运行内部逻辑

当我们在pycharm里面写好方法打算去看一下类函数时,Ctrl+鼠标左击。奇怪的事情发生了,并没有进入到对应的方法里面去,同时pycharm智能提示我们:

fake = Faker(locale='zh_CN')

fake.random_digit_not_null()

通过上面的源码解析也可以很清晰的发现,Faker的方法和属性不像我们往常写的类一样在类的下面,全文解析基本没看到创建伪数据的直接方法和属性。那么下面来看一下方法的基本运行内部逻辑实现方式。

如图,在内部运行逻辑中实际上调用的是generator.py文件内容下的Generator.add_provider方法中有一个需要特别注意就是法,上面我们也提到了,在add_provider方法中有一个需要特别注意就是

for method_name in dir(provider):

通过这个基本的循环将所有的方法和属性加载到对应的语言包中,也就说Faker的属性和方法实际是在另外一个地方存放着,在使用的时候在拿过来,这样做使的Faker的本身类看起来简洁。那么外部是以什么形式来存放的呢?

可以看出在外部有一个provider包,包里面对应很多个方法归类包,在往内部层级就是对应每个语言包下的方法。来看一下具体方法的内部表现形式是如何的

可以发现基本是以元祖的方式存放的原始数据,我们方法运行后最终的结果都是来自于此,那么函数最后是如何运行方法的呢?其实最上面的源码解析已经提及到了,就是使用了init()下的

return getattr(factory, attr)

具体到每个方法或者函数上的实现方式由于太多了就不一一解读了,大范围的是使用random这个基本库来实现的。

文章原创首发于微信公众号 软件测试微课堂

python库源码分析_python第三方库Faker源码解读相关推荐

  1. 用于安装python第三方库的工具是_Python第三方库安装

    Python有一个全球社区:在这里,我们可以搜索Python第三方库的任何话题.PyPI的全称是Python包指数指Python包的指数.它是由PSF (Python软件基金会)和显示全球Python ...

  2. python扩展库xlwt支持对_python第三方库——xlrd和xlwt操作Excel文件学习

    一.xlrd和xlwt的安装 xlrd和xlwt是python的第三方库,所以是需要自己安装的,可以在python的官网https://pypi.python.org/pypi下载该模块来安装,也可以 ...

  3. 20个必不可少的Python库也是基本的第三方库(转载)

    20个必不可少的Python库也是基本的第三方库 读者您好.今天我将介绍20个属于我常用工具的Python库,我相信你看完之后也会觉得离不开它们.他们是: Requests.Kenneth Reitz ...

  4. qpython3h第三方库安装_Python第三方库安装

    Python有一个全球社区:https://pypi.org/,在这里我们可以搜索任何主题的Python第三方库.PyPI全称是Python Package Index,指的是Python包的索引,它 ...

  5. 不是python中用于开发用户界面的第三方库-模拟试卷C

    原标题:模拟试卷C 一.单项选择题 1. 按照"后进先出"原则组织数据的数据结构是____ 队列 栈 双向链表 二叉树 2. 以下选项的叙述中,正确的是 循环队列有队头和队尾两个指 ...

  6. 不是python中用于开发用户界面的第三方库-python界面 | Tkinter图形界面开发库

    0 写在前面 未经允许,不得转载,谢谢~~ 毕设要在现有的基础上做一个可视化的界面,所以趁机也学习一波如何用python实现图形界面的开发. 本文主要学习并整理了: 简要介绍用于python图形界面开 ...

  7. Python在指定环境下安装第三方库的报错解决办法

    Python在指定环境下安装第三方库的报错解决办法 在python安装第三方库时,如果直接打开cmd命令提示符,并输入下列安装命令,则会默认安装在base环境下 但base环境下的包新建的虚拟环境是无 ...

  8. Android源码分析(十一)-----Android源码中如何引用aar文件

    一:aar文件如何引用 系统Settings中引用bidehelper-1.1.12.aar 文件为例 源码地址:packages/apps/Settings/Android.mk LOCAL_PAT ...

  9. 十年老架构师神级推荐,MyBatis源码分析,再也不用为源码担忧了

    十年老架构师神级推荐,MyBatis源码分析,再也不用为源码担忧了 前言 MyBatis是一个优秀的持久层ORM框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注SQL 本身,而不需要花 ...

最新文章

  1. 制作欧比旺·克诺比逼真的CG角色学习教程
  2. select2 4.0.8 + , 动态搜索数据
  3. html head 全局变量,Javascript全局变量的使用方法
  4. 怎么样自己动手写OS
  5. Spring Boot-------JPA——EntityManager构建通用DAO
  6. DB and RAC(11.2.0.3 ) Patch Set Update(11.2.0.3.6 )
  7. hack (浏览器兼容css hack)
  8. 软件成分分析(SCA)完全指南
  9. rep的软件用什么打开_rep文件用什么软件打开
  10. 调度工具之Azkaban 介绍
  11. Behavior tree 编程实战
  12. 烤箱做披萨的做法 教你做火腿肠披萨
  13. 全球首只AIGC动画短片发行,日漫风格超治愈!
  14. 我的世界java蜜蜂_在最新的《我的世界》Java版更新中 蜜蜂是所有的热点
  15. libcurl smtp发送邮件附件大小限制问题
  16. Excel中文本换行
  17. 灌篮高手怎么找回原来的服务器,灌篮高手手游异常登陆、封号补偿及领取方式介绍...
  18. UE4:按键按下触发声音事件,离开位置声音停止
  19. 大道至简(读后感)第二章 是懒人造就了方法
  20. Cisco PT最新版下载路径

热门文章

  1. java basefont_itext 文本域 字体样式设置
  2. 什么是迭代(die dai)
  3. 敏捷迭代是什么意思_我认为“敏捷”的方向是第4部分:“敏捷”是什么意思?...
  4. ExpandableListView 添加分割线
  5. [转] 宝宝出生第一年妈妈最应关心的问题
  6. 强大且超实用的论文阅读工具——ReadPaper
  7. 小程序人脸核验功能实现-边读边录(一)
  8. 渗透测试php过程,利用骑士cms的一次纠结的渗透测试过程(两个潜在
  9. 文件服务器查询重复文件,DupScout – 重复文件扫描、删除或移动的免费工具
  10. Excel操作-多条件筛选