如何像 JavaScript同樣訪問Json對象|Python 主題月

本文正在參加「Python主題月」,詳情查看 活動連接html

寫在前面

首先咱們看一段 JS 的代碼:python

// 數據爲掘金文章詳情數據,作了部分數據的刪簡
result = '{"err_no":0,"err_msg":"success","data":{"article_id":"6985356541389963300","article_info":{"article_id":"6985356541389963300","user_id":"993614678985085","category_id":"6809637769959178254","tag_ids":[6809640445233070094,6809640468997996558],"visible_level":0,"link_url":"","cover_image":"","is_gfw":0,"title":"如何發佈 Jar 包到私服","brief_content":"事情是這樣的,最近接手一個比較複雜的 Java 項目。項目依賴其餘工具包,工具包更新後須要上傳到私服;今天就看看如何發佈 Jar 包到私服。"},"author_user_info":{"user_id":"993614678985085","user_name":"西紅柿蛋炒飯","job_title":"開發工程師","description":"一個 寫 Python Java JavaScript 的全棧開發","university":{"university_id":"0","name":"","logo":""}},"category":{"category_id":"6809637769959178254","category_name":"後端","category_url":"backend"},"tags":[{"id":2546553,"tag_id":"6809640445233070094","tag_name":"Java"},{"id":2546571,"tag_id":"6809640468997996558","tag_name":"maven"}]}}'

obj = JSON.parse(result)
obj.err_msg    // success
obj.data.article_info.title    // 如何發佈 Jar 包到私服
obj.data.tags[1].tag_name    // maven
複製代碼

在 JavaScript 中能夠使用 JSON.parse 快速序列化 JSON 對象。git

那麼問題來了做爲同類型語言的 Python 是否能夠有相似的功能呢?json

答案明顯是有的,下面看看 Python 的實現:後端

import json

result = '{"err_no":0,"err_msg":"success","data":{"article_id":"6985356541389963300","article_info":{"article_id":"6985356541389963300","user_id":"993614678985085","category_id":"6809637769959178254","tag_ids":[6809640445233070094,6809640468997996558],"visible_level":0,"link_url":"","cover_image":"","is_gfw":0,"title":"如何發佈 Jar 包到私服","brief_content":"事情是這樣的,最近接手一個比較複雜的 Java 項目。項目依賴其餘工具包,工具包更新後須要上傳到私服;今天就看看如何發佈 Jar 包到私服。"},"author_user_info":{"user_id":"993614678985085","user_name":"西紅柿蛋炒飯","job_title":"開發工程師","description":"一個 寫 Python Java JavaScript 的全棧開發","university":{"university_id":"0","name":"","logo":""}},"category":{"category_id":"6809637769959178254","category_name":"後端","category_url":"backend"},"tags":[{"id":2546553,"tag_id":"6809640445233070094","tag_name":"Java"},{"id":2546571,"tag_id":"6809640468997996558","tag_name":"maven"}]}}'

obj = json.loads(result)
obj['data']['tags'][1]['tag_name'] # maven
複製代碼

對比一下寫法:markdown

  • Python:obj['data']['tags'][1]['tag_name']
  • JavaScript:obj.data.tags[1].tag_name

明顯 JavaScript 的寫法更簡潔。因此今天咱們就來在 Python 中實現相似的功能。app

技術背景

Python 魔術方法

  • __init__ 用於初始化實例對象的方法。
  • __new__ 用於建立對象並返回對象的方法。

__new__ 先建立對象 __init__ 再初始化對象,調用有前後順序。maven

下面就是基於__new__方法實現的單例模式:ide

class Singleton(object):
    _instance = None

    def __new__(cls, *args, **kwargs):

        if cls._instance is None:
            cls._instance = object.__new__(cls)
        return cls._instance
複製代碼

tips: object.__new__(cls) 是用於建立任何實例對象的方法。工具

classmethod 裝飾器

class Foo(object):
    bar = "bar"

 @classmethod
    def print_bar(cls):
        print(cls.bar)

Foo.print_bar() # bar
Foo().print_bar() # bar
複製代碼

classmethod 修飾的方法表示類方法,不須要實例化類就能夠被類自己調用。cls 表示沒用被實例化的類對象自己。

功能實現

代碼分析

import json

class FrozenJSON:
    """Read only facade for navigating a JSON like object using attribute notation """

 @classmethod
    def __new__(cls, *args, **kwargs):
        if isinstance(args[1], abc.Mapping):
            return super().__new__(cls)
        elif isinstance(args[1], abc.MutableSequence):
            return [cls(item) for item in args[1]]
        else:
            return args[1]

    def __init__(self, mapping):
        self._data = {}
        for key, value in mapping.items():
            self._data[self.validate_identifier(key)] = value

    def __getattr__(self, name):
        if name in self._data:
            return FrozenJSON(self._data[name])
        raise AttributeError(f"Not found: {name}")

 @classmethod
    def validate_identifier(cls, identifier: str):
        idx = 0

        def validated(__identifier):
            validated_identifier = __identifier
            # handle identifier is a Python keyword
            if keyword.iskeyword(__identifier):
                __identifier += "_"
            # handle identifier starts with an integer
            if __identifier[0].isdigit():
                __identifier = f"{str(chr(idx))}_{validated_identifier[1:]}"
            if not __identifier.isidentifier():
                raise ValueError(f"Could not create valid key from: {__identifier}")
            return __identifier

        return validated(identifier)
        
 @classmethod
    def from_string(cls, json_string):
        if is_valid_file_path(json_string):
            return cls.from_file_path(json_string)
        return cls(json.loads(json_string))

複製代碼

功能演示

result = '{"err_no":0,"err_msg":"success","data":{"article_id":"6985356541389963300","article_info":{"article_id":"6985356541389963300","user_id":"993614678985085","category_id":"6809637769959178254","tag_ids":[6809640445233070094,6809640468997996558],"visible_level":0,"link_url":"","cover_image":"","is_gfw":0,"title":"如何發佈 Jar 包到私服","brief_content":"事情是這樣的,最近接手一個比較複雜的 Java 項目。項目依賴其餘工具包,工具包更新後須要上傳到私服;今天就看看如何發佈 Jar 包到私服。"},"author_user_info":{"user_id":"993614678985085","user_name":"西紅柿蛋炒飯","job_title":"開發工程師","description":"一個 寫 Python Java JavaScript 的全棧開發","university":{"university_id":"0","name":"","logo":""}},"category":{"category_id":"6809637769959178254","category_name":"後端","category_url":"backend"},"tags":[{"id":2546553,"tag_id":"6809640445233070094","tag_name":"Java"},{"id":2546571,"tag_id":"6809640468997996558","tag_name":"maven"}]}}'

FrozenJSON.from_string(result).data.tags[1].tag_name
複製代碼

關鍵點解釋

  • abc.Mapping 此類對象包括 dictcollections.defaultdictcollections.OrderedDict 以及 collections.Counter
  • abc.MutableSequence 可變序列主要對象爲list
  • keyword.iskeyword 用於判斷字符串是否爲 Python 內建關鍵字。

更多關於 ABC 抽象類的能夠查看 collections.abc 容器的抽象基類

最後

更多關於 Python 標準庫的介紹能夠查看 Python 標準庫 。之因此放在最後,是由於 Python 不少標準庫真的很棒,推薦你們多看多用。

相關文章
相關標籤/搜索