中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Python程序員需要會用庫是什么

發布時間:2021-12-09 13:49:49 來源:億速云 閱讀:138 作者:小新 欄目:編程語言

這篇文章主要為大家展示了“Python程序員需要會用庫是什么”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“Python程序員需要會用庫是什么”這篇文章吧。

這就提出了一個問題:在 Python 中使用類是否是麻煩?我們來看一個簡單的數據結構:一個三維直角坐標。從最簡單的開始:

class Point3D(object):

到現在為止還挺好。我們已經有了一個三維點。 接下來呢?

class Point3D(object):     def __init__(self, x, y, z):

其實,這是有點可惜。我只想對數據的打包,但卻不得不覆蓋一個 Python 運行時中的特殊方法,而且命名還是約定俗成的。但還不算太壞;畢竟所有的編程語言都是按照某種形式組成的怪異符號而已。

至少可以看到屬性名了,還能說得通。

class Point3D(object):     def __init__(self, x, y, z):         self.x

我已經說過,我想一個 x,但現在必須把它指定為一個屬性...

class Point3D(object):     def __init__(self, x, y, z):         self.x = x

綁定到 x ?呃,很明顯...

class Point3D(object):     def __init__(self, x, y, z):         self.x = x         self.y = y         self.z = z

每個屬性都得這么做一次,所以這相當糟糕?每個屬性名都得敲 3 次?!?

好吧。至少定義完了。

class Point3D(object):     def __init__(self, x, y, z):         self.x = x         self.y = y         self.z = z     def __repr__(self):

什么,難道還沒結束嗎?

class Point3D(object):     def __init__(self, x, y, z):         self.x = x         self.y = y         self.z = z     def __repr__(self):         return (self.__class__.__name__ +                 ("(x={}, y={}, z={})".format(self.x, self.y, self.z)))

拜托。現在我得每個屬性名敲 5 次了,如果我想在調試時知道屬性到底指的是什么的話。如果定義元組的話,就不用這一步了?!?!?

class Point3D(object):     def __init__(self, x, y, z):         self.x = x         self.y = y         self.z = z     def __repr__(self):         return (self.__class__.__name__ +                 ("(x={}, y={}, z={})".format(self.x, self.y, self.z)))     def __eq__(self, other):         if not isinstance(other, self.__class__):             return NotImplemented         return (self.x, self.y, self.z) == (other.x, other.y, other.z)

敲 7 次?!?!?!?

class Point3D(object):     def __init__(self, x, y, z):         self.x = x         self.y = y         self.z = z     def __repr__(self):         return (self.__class__.__name__ +                 ("(x={}, y={}, z={})".format(self.x, self.y, self.z)))     def __eq__(self, other):         if not isinstance(other, self.__class__):             return NotImplemented         return (self.x, self.y, self.z) == (other.x, other.y, other.z)     def __lt__(self, other):         if not isinstance(other, self.__class__):             return NotImplemented         return (self.x, self.y, self.z) < (other.x, other.y, other.z)

敲 9 次?!?!?!?!?

from functools import total_ordering @total_ordering class Point3D(object):     def __init__(self, x, y, z):         self.x = x         self.y = y         self.z = z     def __repr__(self):         return (self.__class__.__name__ +                 ("(x={}, y={}, z={})".format(self.x, self.y, self.z)))     def __eq__(self, other):         if not isinstance(other, self.__class__):             return NotImplemented         return (self.x, self.y, self.z) == (other.x, other.y, other.z)     def __lt__(self, other):         if not isinstance(other, self.__class__):             return NotImplemented         return (self.x, self.y, self.z) < (other.x, other.y, other.z)

好了,擦汗 - 盡管多了 2 行代碼不是很好,但至少現在我們不用定義其他比較方法了。現在一切搞定了,對吧?

from unittest import TestCase class Point3DTests(TestCase):

你知道嗎? 我受夠了。一個類碼了 20 行,卻還什么事都沒做;我們這樣做是想解四元方程,而不是定義“可以打印和比較的數據結構”。我陷入了大量無用的垃圾元組、列表和字典中;用 Python 定義合適的數據結構是非常麻煩的

命名元組 namedtuple

為解決這個難題,標準庫給出的解決方案是使用 namedtuple 。然而不幸的是初稿(在許多方面與我自己的處理方式有相似的尷尬的和過時之處)namedtuple 仍然無法挽救這個現象。它引入了大量沒有必要的公共函數,這對于兼容性維護來說簡直就是一場噩夢,并且它連問題的一半都沒有解決。這種做法的缺陷太多了,這里只列一些重點:

  • 不管你是否希望如此,它的字段都可以通過數字索引的方式訪問。這意味你不能有私有屬性,因為所有屬性通過公開的 __getitem__ 接口暴露出來。

  • 它等同于有相同值的原始元組,因此很容易發生類型混亂,特別是如果你想避免使用元組和列表。

  • 這是一個元組,所以它總是不可變的。

至于***一點,你可以像這樣使用:

Point3D = namedtuple('Point3D', ['x', 'y', 'z'])

在這種情況下它看起來并不像一種類;無特殊情況下,簡單的語法分析工具將不能識別它為類。但是這樣你不能給它添加任何其他方法,因為沒有地方放任何的方法。更別提你必須輸入類的名字兩次。

或者你可以使用繼承:

class Point3D(namedtuple('_Point3DBase', 'x y z'.split())):     pass

盡管這樣可以添加方法和文檔字符串,看起來也像一個類,但是內部名稱(在 repr 中顯示的內容,并不是類的真實名稱)變的很怪了。同時,你還不知不覺中把沒列出的屬性變成了可變的,這是添加 class 聲明的一個奇怪的副作用;除非你在類主體中添加 __slots__='X Y z'.split(),但這樣又回到了每個屬性名必須敲兩次的情況。

而且,我們還沒提科學已經證明不應該使用繼承呢。

因此,如果你只能選命名元組,那就選命名元組吧,也算是改進,雖然只是在部分情況下如此。

使用 attrs

這時該我最喜歡的 Python 庫出場了。

pip install attrs

我們重新審視一下上述問題。如何使用 attrs 庫編寫 Point3D

import attr @attr.s

由于它還沒有內置到 Python 中,所以必須用以上 2 行開始:導入包然后使用類裝飾器。

import attr @attr.s class Point3D(object):

你看,沒有繼承!通過使用類裝飾器,Point3D 仍然是一個普通的 Python 類(盡管我們一會會看到一些雙下劃線方法)。

import attr @attr.s class Point3D(object):     x = attr.ib()

添加屬性 x

import attr @attr.s class Point3D(object):     x = attr.ib()     y = attr.ib()     z = attr.ib()

再分別添加屬性 yz。這樣就完成了。

這就 OK 了? 等等。不用定義字符串表示嗎?

>>> Point3D(1, 2, 3) Point3D(x=1, y=2, z=3)

怎么進行比較?

>>> Point3D(1, 2, 3) == Point3D(1, 2, 3) True >>> Point3D(3, 2, 1) == Point3D(1, 2, 3) False >>> Point3D(3, 2, 3) > Point3D(1, 2, 3) True

好的。但如果我想將有明確屬性定義的數據提取為適合 JSON 序列化的格式呢?

>>> attr.asdict(Point3D(1, 2, 3)) {'y': 2, 'x': 1, 'z': 3}

也許上邊有一點點準確。即使如此,因為使用了 attrs 后,很多事情都變得更簡單了,它允許你在類上聲明字段,以及相關的元數據。

pprint >>> pprint.pprint(attr.fields(Point3D)) (Attribute(name='x', default=NOTHING, validator=None, repr=True, cmp=True, hash=True, init=True, convert=None),  Attribute(name='y', default=NOTHING, validator=None, repr=True, cmp=True, hash=True, init=True, convert=None),  Attribute(name='z', default=NOTHING, validator=None, repr=True, cmp=True, hash=True, init=True, convert=None))

我不打算在這里深入介紹 attrs 的每一個有趣的功能;你可以閱讀它的文檔。另外,項目會經常更新,每隔一段時間都會有新的東西出現,因此我也可能會漏掉一些重要的功能。但是用上 attrs 之后 ,你會發現它所做的正式此前 Python 所缺乏的:

  1. 它讓你簡潔地定義類型,而不是通過手動鍵入 def __init __ 的方式來定義。

  2. 它讓你直接地說出你聲明的意思,而不是拐彎抹角的表達它。與其這樣說:“我有一個類型,它被稱為 MyType ,它有一個構造函數,在構造函數中用參數 'A' 給屬性 'A' 賦值”,而是應該這樣說:“我有一個類型,它被稱為 MyType ,它有一個屬性叫做 a,以及跟它相關的方法“,而不必通過逆向工程猜測它的方法(例如,在一個實例中運行 dir ,或查看 self.__ class__. __dict__)。

  3. 它提供了有用的默認方法,而不像 Python 中的默認行為有時有用,大部分時候沒用。

  4. 它從簡單的開始,但是提供了后續添加更嚴謹實現的空間。

我們詳細說明***一點。

逐步改善

雖然我不打算談及每一個功能,但如果我沒有提到以下幾個特點,那我就太不負責任了。你可以從上面這些特別長的 Attributerepr() 中看到一些有趣的東西。

例如:你通過用 @attr.s 修飾類來驗證屬性。比如:Point3D 這個類,應該包含數字。為簡單起見,我們可以說這些數字為 float 類型,像這樣:

import attr from attr.validators import instance_of @attr.s class Point3D(object):     x = attr.ib(validator=instance_of(float))     y = attr.ib(validator=instance_of(float))     z = attr.ib(validator=instance_of(float))

因為我們使用了 attrs ,這意味著之后有機會進行驗證:可以只給每個需要的屬性添加類型信息。其中的一些功能,可以讓我們避免常見的錯誤。例如,這是一個很常見的“找 Bug” 面試題:

class Bag:     def __init__(self, contents=[]):         self._contents = contents     def add(self, something):         self._contents.append(something)     def get(self):         return self._contents[:]

修正它,正確的代碼應該是這個樣子:

class Bag:     def __init__(self, contents=None):         if contents is None:             contents = []         self._contents = contents

額外添加了 2 行代碼。

這樣,contents 無意間就成了全局變量,這使得所有沒有提供列表的 Bag 對象都共享一個列表。使用 attrs 的話,就變成這樣:

@attr.s class Bag:     _contents = attr.ib(default=attr.Factory(list))     def add(self, something):         self._contents.append(something)     def get(self):         return self._contents[:]

attrs 還提供一些其他的特性,讓你在構建類時更方便更正確。另一個很好的例子?如果你嚴格的管控對象的屬性(或在內存使用上更有效率的 CPython ),你可以在類層級上使用 slots=True  - 例如 @attr.s(slots=True) - 自動與 attrs 聲明的 __slots__屬性匹配。所有這些功能會讓通過 attr.ib() 聲明的屬性更好更強大。

未來的 Python

有人為以后能普遍使用 Python 3 編程而感到高興。而我期待的是,能夠在 Python 編程時一直用attrs。就我所知,它對每個使用了的代碼庫都產生了積極、微妙的影響。

試試看:你可能會驚訝地發現,以前用不方便寫文檔的元組、列表或字典的地方,現在可以使用具備清晰解釋的類了。既然編寫結構清晰的類型如此簡單方便,以后應該會經常使用 attrs 的。

以上是“Python程序員需要會用庫是什么”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

长垣县| 重庆市| 惠州市| 卢湾区| 连云港市| 福州市| 高平市| 皋兰县| 沙坪坝区| 海城市| 大宁县| 白银市| 霞浦县| 大方县| 乌鲁木齐县| 开远市| 东丽区| 乐清市| 清原| 客服| 延庆县| 海城市| 阿拉善左旗| 福清市| 大安市| 闵行区| 繁峙县| 府谷县| 连平县| 东丰县| 都安| 韶山市| 土默特右旗| 和林格尔县| 静海县| 昂仁县| 亳州市| 车致| 通许县| 民丰县| 新沂市|