簡體   English   中英

優先使用Python中的對象字典

[英]Preferring dictionaries over objects in Python

當您所做的只是描述某些屬性時,使用字典而不是Python中的對象(反之亦然)是否有好處?

我正在處理的項目目前有許多地方使用字典,我通常會創建對象。 在我看來,對象提供了更多的結構,並允許通過諸如pylint之類的程序進行更好的程序員錯誤檢查,但是很難解釋為什么我會使用對象而不是dict。

對於模擬示例,一個模塊創建Widgets並包含如下方法:

def create(self, propertyA, propertyB=55, propertyC="default", 
           propertyD=None, propertyE=None, propertyF=None, propertyG=None,
           propertyH=None, propertyI=None):

通過創建一個字典並將其傳遞給它來調用該方法:

widget_client = WidgetClient()
widget = {
    "propertyA": "my_widget",
    "propertyB": 10,
    ...
}
widget_client.create(**widget)

當我看到這個時,我發現這些屬性中的每一個都描述了一個“Widget”,並且想要執行以下操作:

class Widget(object):
    """Represents a widget."""

    def __init__(self, propertyA, **kwargs):
        """Initialize a Widget.

        :param propertyA: The name of the widget.
        :param kwargs: Additional properties may be specified (see below).
        :returns: None

        """
        self.propertyA = propertyA
        self.propertyB = kwargs.get("propertyB", 55)
        self.propertyC = kwargs.get("propertyC", "default")
        self.propertyD = kwargs.get("propertyD", None)
        self.propertyE = kwargs.get("propertyE", None)
        self.propertyF = kwargs.get("propertyF", None)

然后更新create()方法,看起來像這樣:

def create(self, widget):

最終被稱為這樣:

widget_client = WidgetClient()
widget = Widget(propertyA="my_widget")
widget.propertyB = 10
...
widget_client.create(widget)

在我看來,這顯然更好,但過去我錯了,我想不出如何解釋自己。 當然我還在使用** kwargs可以通過將Widget分解為更小的組件/相關部件並創建更多對象等來避免,但我覺得這是一個很好的“第一步”。 這有什么意義嗎?

字典優點

  1. 更快和/或更高的內存效率

字典缺點

  1. 無法通過靜態代碼檢查程序捕獲一些錯誤
  2. 可能永遠不會顯示或知道所有窗口小部件屬性的完整列表

對象的好處

  1. 確切地知道'Widget'是由什么組成的
  2. 使用靜態代碼檢查器可能會捕獲錯誤(盡管使用** magic會阻止其中的一些)

對象缺點

  1. 較慢和/或較低的內存效率

這似乎是一個愚蠢的問題,但為什么用可以用字典完成的對象做些什么呢?

不,使用字典而不是對象沒有任何好處 - 對象中的數據通常存儲在字典中。

使用對象而不是字典可能會有好處。 請參閱: http//docs.python.org/reference/datamodel.html#slots

使用任何內置數據類型總能為您提供某些功能的優勢,而且其行為為其他程序員所熟知。 一本字典為你提供了一個完整的內置方法,沒有人不知道它是否可以迭代。

這只是一個優點。 並不是說我應該總是使用字典而不是聲明自己的對象。 (當然,您的新對象可以繼承類似字典的行為)但是,當更簡單的存儲機制可能時,您不一定總是選擇創建新對象。 使用理解作為指導,它將取決於Widget是否有任何特殊行為或屬性。

你可以用namedtuple很好地實現它。 例如,您可以創建一個名為widget的Widget,其默認值為:

>>> from collections import namedtuple
>>> _Widget = namedtuple("Widget", "propertyA propertyB propertyC propertyD propertyE propertyF propertyG propertyH propertyI")
>>> DefaultWidget = _Widget(None, 55, "Default", None, None, None, None, None, None)
>>> DefaultWidget
Widget(propertyA=None, propertyB=55, propertyC='Default', propertyD=None, propertyE=None, propertyF=None, propertyG=None, propertyH=None, propertyI=None)

然后,您可以使用一個名為Widget的函數來初始化屬性:

def Widget(propertyA, **kwargs):
   return DefaultWidget._replace(propertyA=propertyA, **kwargs)

然后你可以像這樣使用它:

>>> Widget("test", propertyE=17)
Widget(propertyA='test', propertyB=55, propertyC='Default', propertyD=None, propertyE=17, propertyF=None, propertyG=None, propertyH=None, propertyI=None)

請注意,如果您嘗試省略所需的propertyA:

>>> Widget()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Widget() takes exactly 1 argument (0 given)

或者如果您提供不存在的財產:

>>> Widget("test", propertyZ="test2")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in Widget
  File "<string>", line 32, in _replace
ValueError: Got unexpected field names: ['propertyZ']

它以一種很好的方式處理它。 我認為使用namedtuple可以擺脫使用字典的缺點。

我傾向於使用對象。 我的理由是它們更容易擴展。 如果人們通過字段訪問對象,則如果需要其他功能,則這些字段可以成為屬性。 如果他們正在訪問密鑰,則很難在不更改接口的情況下添加其他邏輯。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM