Pythonのソースコードの解釈サードパーティ製のライブラリ偽物

ソース背景

偽物Pythonのサードパーティのライブラリで、主にデータのダミーデータを作成するために使用さgithubのオープンソースプロジェクトは、地理情報クラスが含まれて作成した、個人のアカウント情報などの基本情報、ブラウザの種類情報などのネットワーキング、基本的な情報、ファイルの種類の情報、デジタルなど他のカテゴリーとしてクラステキストの暗号化タイプ、時間タイプ情報、。

送信元アドレス:https://github.com/joke2k/faker
機能クイック収集:https://blog.csdn.net/qq_41545431/article/details/105006681

ソースを読みます

メインソースの解釈

クラスの初期化モジュールのクラスの初期化に直接クリックすることで

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、ランダム、他の6つの外側クラッド内に導入。
パッケージの外に対応するキーの次の説明:

1、collections.OrderedDictはPythonの辞書がそのようにハッシュ値、辞書をもたらす障害に応じて格納されているので、辞書OrderedDictの要素をソート目的を達成するため、要素をソート辞書目的を達成し
図2は、6名はPython2コード互換性とのpython3を解決するために主に生産6 = 2×3、から来ています

特定のルールジェネレータgenerator_attrsに格納されているクラス属性、後続の呼び出し方法によれば、初期化を開始します。初期化初期化パラメータにクラスを指定しますか?同時に、名目上の定義は、2つのプライベート変数、外部コールを防止するためのクラスメソッドは、彼が本当の民営化が存在しないため、Pythonでプライベート変数は、関係なく、メソッドやプロパティの、プログラムするためには、契約が追加され、名目上と言いましたアンダースコア_プロパティとメソッドは*、APIに属していないクラス外部からアクセスしてはならない、Mのインポートから導入されることはありません。注意、しかし、あなたも呼び出すことができ呼びたいです。オブジェクトをインスタンス化する)self._factory_map OrderedDict(格納されている。self._weightsクラスが呼び出されることを保証するため、所与なしの初期値。次のパラメータは、以下のように、概略図は、基本的に決意条件のロケールです。

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

なぜ、上院にこのロケールで初期化がロケール非常に重要なことをやっているので、非常に多くのチェックそれを行うが、それはソース表示のロケール特定のポイントに非常に高い要求であるします:

proxy.py文件
for locale in locales:
        self._factory_map[locale] = Factory.create(locale, providers, generator, includes, **config)

ここでの主な源は、工場出荷時のモードで作成方法を含む各言語辞書、上院への現在のクラスのための基本的なパラメータのマップを作成するために作られました。参照チェック行って外にロケールに非常に偽物のほか、他の検証、それを行うにはありませんか?答えは、キーがself._weights、self._factories、self._factory_map.itemsを()、属性上でイエスで作られた読み取り専用オブジェクトで外部@propertyデコレータで変更、確認してください。

魔法の方法を読みます

必要例インスタンス化クラスのない特性を、その後ために、その拡張性を高めるために添加GetItem関数我々は、次に偽()「pujen」]操作、偽で偽物()「pujenできるように魔法の方法を「]理由は、もちろん何のpujen偽物、この言語パックが存在しない、KeyError例外ソース内の演算結果、シェーンを返します。

proxy.py文件
def __getitem__(self, locale):
    return self._factory_map[locale.replace('-', '_')]
fake = Faker(locale='zh_CN')
print(fake['zh_CN'])

>>>    <faker.generator.Generator object at 0x0000021AEE18FDD8>

次に、より良い何が起こっているかを理解するための例を見ての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}

次に見防止シード()メソッドを直接呼び出すが、フォームFaker.seed()このような呼び出し、種子の偽物源(にされているので、このクラスに表示されgetattribute__方法は、主に)実際Generator.seed()関数は、確率的な種子です。メソッド呼び出しクラスはシード()が、このような他の非方法ではないと仮定すると、次に__getattr実行その内部偽物で行われるもの主である、方法。

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工場パターンからのものであることを見つけます。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()方法
偽物はクラスのmainメソッドを隠します

工場出荷時のモデルの上に()も一時的な内部クラスの他の方法に比べて、実質的に導入された主な機能の方法が、より多くの研究を作成します。次に、作成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パラメータのインスタンスである、またはそれが(間接的、直接的または仮想)サブクラスの例であれば、真を返します。オブジェクトは、指定された型のオブジェクトでない場合、関数は常にFalseを返します。CLASSINFOタプル場合、オブジェクトは、任意の型のインスタンスである場合(または再帰的に、同様のタプル)オブジェクトのタイプは、それがTrueを返します。ないCLASSINFO型やタプルの種類、およびこれらのタプルのタプルのタイプでない場合は、エラー例外の種類がスローされます。

for method_name in dir(provider):

DIRの取扱説明書、プロバイダクラスやモジュールが定義されていない場合はdirのモジュールクラスまたは属性を処理する方法のリターンを

次に、これらの2つの方法を見ては、主に動的オブジェクトの実行関数リターンを呼び出すために使用します

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

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

これまでのところ、Generatorクラスは、完全にコアメソッドを紹介します!

内部ロジックを実行する方法では偽物

我々は方法がpycharmクラスの関数の内部を見てみるつもり書くときに、Ctrlキーを押しながら左クリックします。奇妙なことが起こったと同時に、私たちのスマートヒントをpycharmする方法を対応し、それに入力されていません。

fake = Faker(locale='zh_CN')
fake.random_digit_not_null()


私たちは、常に同じクラスで、次のクラスを書かれても、偽物のメソッドとプロパティ、上記のソースコードを解析することにより、非常に明確な知見ことができ、基本的な分析メソッドとプロパティの全文は直接ダミーデータを作成して表示されませんでした。その後、実装の方法の内部ロジックの次の基本的な操作を見てみましょう。

 

図に示すように、内部動作ロジックは、実際に文書のgenerator.pyコンテンツの下Generator.add_providerメソッドを呼び出し、に特に注意を払う必要がある法則です、我々はまた、上述したように、add_provider方法がある特別な注意が必要です

for method_name in dir(provider):

この基本的なサイクルに対応する言語パックにロードされたすべてのメソッドとプロパティを通じて、それは偽物のプロパティとメソッドは、そうするの偽物、引き継ぐに使用した場合、保存するために別の場所に実際にあると述べましたクラス自体はシンプルに見えます。だから、それを格納するために外部のものを形成?


これは、プロバイダパケット、パケット分類方法の数に対応するパケットの外側に見ることができ、この方法は、各言語パックに対応する内部レベルを低下させることです。の方法を具体的な方法の内部表現を見てください

 


基本的には先祖の方法で保存された生データに基づいて見つけることができ、我々は結果は、このから実行する方法、関数法、最終的にどのようにそれを実行することです終わり?実際には、解析するソースコードの先頭は既に述べたように、の使用であるinitは()で

 

return getattr(factory, attr)

原因が多すぎるこれの大規模な範囲を列挙しないようにする方法や関数の各実装に固有では達成するために、ランダムな基本的なライブラリを使用することです。

オリジナルの記事は、最初のマイクロ教室をテストするソフトウェアの公開マイクロチャンネル番号に登場しました

おすすめ

転載: www.cnblogs.com/pujenyuan/p/12615835.html