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

Faker 新版本Faker类的用法

祁辰阳
2023-12-01

大家好,我是练习时长两年半的大数据练习生,喜欢数学,AI,大数据。
写博客是为了总结,分享,自娱自乐。希望写出的东西会对自己,对别人都有价值!
废话不多说,现在是个终身学习的时代,开始学习了!奥力给!干了兄弟们!
是时候展现真正的技术了:

本文是一篇学习笔记,外加百度上搜刮来的知识,外加自己总结的知识:
原文链接:https://faker.readthedocs.io/en/master/fakerclass.html#proxy-class-implementation-details

创建Faker对象

第一种 2.0.4版本及以下常用写法

from faker import Factory
fake = Factory.create()

第二种 新版本创建Faker代理类而不是Factory.create()

from faker import Faker
fake = Faker()

第一种是老版本的,第二种是新版本的,两种都可以使用,但是在seed()上有一点区别

新版本Faker的seed()

在新版本Faker类的基础上,你不能调用类的实例.seed()方法了,会报类型错误,取而代之的是Faker.seed()

在新版本Faker类基础上用旧版本写法会抛出异常:

from faker import Faker
fake = Faker()
fake.seed(0)  # 抛出异常TypeError

现在你得用新版本的写法:

from faker import Faker
fake = Faker()
Faker.seed(0)

如果你一定要用老版本的写法,那你创建Faker对象的时候要用老版本Factory.create()的创建方法。

Faker代理类实现细节

新的Faker实例只是引用了Generator对象的代理对象,它用于实例化时指定使用的语种,这些Generator对象们只是旧Faker对象的不同的实例而已。

如果只有一个内部的Generator对象,那新的Faker实例就只支持一种语言,如果有多个内部Generator对象,那么Faker实例就会支持多种语言。

在单语种模式下,新的Faker实例可以简单的被迫表现为像是用旧Faker创建出来的实例一样,因为类似的接口可以在新的Faker实例上公开,然后1:1地调用代理方法、properties和attributes到唯一的生成器对象。事实上,这就是实现它的方式,也是保持向后兼容性的方式(除了Faker.seed())。

然而,在多语种模式下,这种1:1映射不再存在了,调用的代理方式取决于属性是一个provider的方法或者是存在于生成器对象中的某个属性。有可能提供健全的默认实现,像我们为seed_instance所做的那样巧妙地映射,但是其他的像add_provider和随机的gettersetter更依赖于特定的用例,或者有潜在的危险。

在这些情况下,对使用者来说更好的情况是用它们的实现或者直接调用这些来自于内部Generator对象自己的方法来创建它们自己的子类
(这一段翻译过来我也没看懂是啥意思,等我后边懂了再回来注解或者修改把)

代理类的属性名解析

这个代理类指新版本Faker类。

代理类有一个属性名称解析行为,运行顺序如下:

  1. 如果属性名是seed,那就抛出TypeError异常,这样可以防止实例调用seed方法(与上文呼应,新版Faker类的实例不能调用seed()方法而是Faker.seed()
  2. 如果属性名不是seed,那就检查属性名称是否与代理类实例中的属性匹配。如果匹配就返回匹配的属性。
  3. 如果属性名称与代理类实例中的属性不匹配,那就判断实例是否为单语种模式,如果是的话,那就代理调用唯一的Generator对象,并尝试返回一个匹配的属性。
  4. 如果是在多语种模式下,就判断属性名是否和Generator的属性匹配,如果匹配,就抛出NotImplementedError.
  5. 如果不匹配,就判断属性名是否匹配缓存模式正则表达式,如果不匹配,抛出AttributeError,因为如果匹配的话,第二步就应该处理完了。
  6. 如果不满足上面所有情况,假设属性名可能引用了一个provider的方法,并且进行Generator/Factory模式的选择,并且代理调用被选中的Generator对象

Factory/generator 的选择将会在后边讨论

语种设定

一个新的Faker实例会在单语种或多语种环境下工作,取决于你传递的locale值,这个值可以是下面的几种:(下划线是_连字符是-

  • 空值,啥也不传,None(默认设置为en_US)
  • 一个有效的地点字符串,带下划线或连字符的
  • 一个列表,元组,或者集合里边放着有效地点字符串,带下划线或连字符的
  • 一个key-valuue键值对(key是地点字符串,value是权重)的有序字典

前两个老Faker支持,所以新Faker也支持,所以调用前两个总会生成一个单语种模式的新Faker实例,在这个模式下,实际上不需要检索对内部Generator对象的引用
,因为前面讨论过的1:1行为。

潜在的缺陷存在于多语种模式下和需要单独访问内部生成器对象时。由于语言环境字符串可以用(en_US)或者(en-US)编写,这可能导致混乱或错误,所以语言环境字符串必须被规范化处理,以提供一致的没有重复的结果。

在实例化过程中,新Faker会将语言环境字符串规范为下划线的形式,它也会按照原样存储它们,换句话说,en_US和en-US都被指定时,将会被视为相同的。最后被处理的将会被看作副本,重复的,然后被清除。通过索引访问内部Generator对象时也会执行对应的正则。

例如,下面的代码将会创建一个新Faker实例,即使你制定了4个地区,这个新Faker实例也是单语种模式下的。

"""
即使你指定了4个语种,它也是单语种模式下的
"""

from faker import Faker
fake = Faker(['en-US', 'en_US', 'en_US', 'en-US'])

# 将会打印 ['en_US']
print(fake.locales)

# 获得 en-US generator 的引用
us1 = fake['en_US']

# 获得 en-US generator 的引用
us2 = fake['en-US']

# 将会打印 True
print(us1 == us2)

多语种模式

为了启动多语种模式,参数local的值必须是由不止一个有效的语言环境字符串组成的列表,元组,集合或OrderedDict
例如:

from collections import OrderedDict
from faker import Faker

locale_list = ['en-US', 'ja-JP', 'en_US']
fake1 = Faker(locale_list)

# 将会打印 ['en_US', 'ja_JP']
print(fake1.locales)

locale_odict = OrderedDict([
    ('en-US', 1),
    ('ja-JP', 2),
    ('en_US', 2),
])

fake2 = Faker(locale_odict)

# 将会打印 ['en_US', 'ja_JP']
print(fake1.locales)

在多语种模式下,从新Faker实例中调用预期的provider方法将会运行Factory/Selection逻辑。

Factory/Selection逻辑如下:

  1. 判断缓存映射是否已经存在于provider的方法中,如果存在那就使用这个映射,
    然后判断有没有generator支持provider的方法,如果没有,那将会像使用旧Faker一样抛出AttributeError
  2. 如果缓存映射不存在于provider的方法中,那就判断哪个Generator对象支持provider方法,如果在实例化期间提供了相应的权重,那就缓存映射结果以及相应的权重。
  3. 如果这里只有一个generator支持provider方法,那就返回这唯一的一个generator。
  4. 如果这里可以使用的generator不止一个,并且提供权重了,那就使用提供的权重定义的分布随机选择一个generator。

除了能够提供给每个语种对应的生成概率,并且最小化性能损失之外,factory selection逻辑保证了只要至少有一个generator对象支持provider的方法,那调用provider方法就不会失败。

实例

如果你能看懂下面这些代码,那说明你理解了上面的内容,恭喜。

from collections import OrderedDict
from faker import Faker

locales = OrderedDict([
    ('en-US', 1),
    ('en-PH', 2),
    ('ja_JP', 3),
])
fake = Faker(locales)

# 获取实例化期间指定的地区列表
print(fake.locales)

# 获取这个Faker对象的内部生成器列表
print(fake.factories)

# 获取'en_US' locale的内部生成器
print(fake['en_US'])

# 获取“en_PH”语言环境的内部生成器
print(fake['en_PH'])

# 获取“ja_JP”语言环境的内部生成器
print(fake['ja_JP'])

# 瞎写地区将会抛出 KeyError 并提示 'en_GB' was not included
print(fake['en_GB'])

# 设置共享的`random.Random` 对象的seed
# 跨越所有将被创建的内部生成器
Faker.seed(0)

# 设置唯一的`random.Random` 对象的seed
# each internal generator of this `Faker` instance
fake.seed_instance(0)

# 为这个Faker实例的 en_US内部 generator创建并seed一个独一无二的 `random.Random` 对象
fake.seed_locale('en_US', 0)

# 在提供权重的基础上创建一个随机的name
# 生成特定语言的概率 = 每种语言的权重/所有语言加起来总权重
# en_US - 16.67% of the time (1 / (1 + 2 + 3))
# en_PH - 33.33% of the time (2 / (1 + 2 + 3))
# ja_JP - 50.00% of the time (3 / (1 + 2 + 3))
fake.name()

# 生成一个en_US语种下的name
fake['en-US'].name()

# 生成一个建立在提供的权重的基础上的 zipcode
# 注意: en_PH 并不支持 zipcode provider 方法
# en_US - 25% of the time (1 / (1 + 3))
# ja_JP - 75% of the time (3 / (1 + 3))
fake.zipcode()

# 生成一个在 ja_JP 语种下的zipcode
fake['ja_JP'].zipcode()

# 将会抛出 AttributeError
fake['en_PH'].zipcode()

# 生成一个 Luzon province 的名字
# 注意: 创建时提供的三种语种之中只有 en_PH 支持这个 provider 方法
fake.luzon_province()

# 生成一个 Luzon province name
fake['en_PH'].luzon_province()

# 抛出一个 AttributeError
fake['ja_JP'].luzon_province()

小伙伴们!相信看到这里的你一定有所收获!
如果我哪里写错欢迎评论区来喷
如果觉得对你有帮助请给个赞哦亲!爛爛爛爛爛爛
爛爛爛最后引用名言一句我们无论遇到什么困难,都不要怕,微笑着面对它!消除恐惧的最好办法就是面对恐惧!加油!奥力给!

 类似资料: