簡體   English   中英

從 str 或 int 繼承

[英]inheritance from str or int

為什么我在創建一個繼承自 str(或也來自 int)的類時遇到問題

class C(str):
   def __init__(self, a, b):
     str.__init__(self,a)
     self.b = b

C("a", "B")

TypeError: str() takes at most 1 argument (2 given)

如果我嘗試使用int而不是str ,也會發生同樣的情況,但它適用於自定義類。 我需要使用__new__而不是__init__嗎? 為什么?

>>> class C(str):
...     def __new__(cls, *args, **kw):
...         return str.__new__(cls, *args, **kw)
... 
>>> c = C("hello world")
>>> type(c)
<class '__main__.C'>

>>> c.__class__.__mro__
(<class '__main__.C'>, <type 'str'>, <type 'basestring'>, <type 'object'>)

由於__init__是在對象被構造之后調用的,所以修改不可變類型的值已經來不及了。 注意__new__是一個類方法,所以我調用了第一個參數cls

請參閱此處了解更多信息

>>> class C(str):
...     def __new__(cls, value, meta):
...         obj = str.__new__(cls, value)
...         obj.meta = meta
...         return obj
... 
>>> c = C("hello world", "meta")
>>> c
'hello world'
>>> c.meta
'meta'

繼承內置類型很少值得。 您必須處理幾個問題,而您並沒有真正獲得多少好處。

使用組合幾乎總是更好。 您將保留一個str對象作為屬性,而不是繼承str

class EnhancedString(object):
     def __init__(self, *args, **kwargs):
         self.s = str(*args, **kwargs)

您可以使用__getattr__手動或自動推遲要在底層str self.s上工作的任何方法。

話雖如此,需要您自己的字符串類型應該讓您停下來。 有許多類應該將字符串存儲為它們的主要數據,但您通常希望使用strunicode (如果您表示文本,則為后者)作為字符串的一般表示。 (一個常見的例外是如果您需要使用 UI 工具包的字符串類型。)如果您想為字符串添加功能,請嘗試使用操作字符串的函數而不是新對象作為字符串,這樣可以保持您的代碼更簡單,與其他人的程序更兼容。

當您實例化一個類時,您傳入的參數將傳遞給__new__ (構造函數)和__init__ (初始化程序)方法。 因此,如果您從一個對實例化期間可能提供的參數數量有限制的類繼承,則必須保證其__new____init__都不會獲得比預期更多的參數。 所以這就是你的問題。 你用C("a", "B")實例化你的類。 解釋器在C尋找__new__方法。 C沒有它,所以 python 窺視它的基類str 因為它有一個,所以使用並提供了兩個參數。 但是str.__new__期望只得到一個參數(除了它的類對象作為第一個參數)。 因此TypeError 這就是為什么你必須在你的子類中擴展它,就像你對__init__所做的一樣。 但請記住,它必須返回類實例,並且它是一個靜態方法(無論它是否使用@staticmethod裝飾器定義),如果您使用super函數,它很重要。

在不可變類型的情況下使用__new__

class C(str):
    def __new__(cls, content, b):
        return str.__new__(cls, content)

    def __str__(self):
        return str.__str__(self)

a=C("hello", "world")
print a

打印返回hello

Python 字符串是不可變類型。 調用函數__new__來創建對象C的新實例。 python __new__函數基本上存在以允許__new__類型繼承。

仔細閱讀this后,這是對str進行子類化的另一種嘗試。 其他答案的變化是使用super(TitleText, cls).__new__在正確的類中創建實例。 無論何時使用,這個似乎都像 str 一樣,但允許我覆蓋一個方法:

class TitleText(str):
    title_text=""
    def __new__(cls,content,title_text):
        o=super(TitleText, cls).__new__(cls,content)
        o.title_text = title_text
        return o

    def title(self):
        return self.title_text

>>> a=TitleText('name','A nice name')
>>> a
'name'
>>> a[0]
'n'
>>> a[0:2]
'na'
>>> a.title()
'A nice name'

這使您可以正確地進行切片和下標。 這是用來干嘛的? 用於在管理索引頁面中重命名 Django 應用程序。

上面已經回答了這個問題,這只是一個可能對某人有用的切線觀察。

當我試圖找出一種在引用的字典被刪除后刪除臨時文件的方法時遇到了這個問題。

上下文是一個 Flask 會話:用戶可以上傳一些文件,但在有效提交將他/她的數據傳輸到最終目的地所必須經歷的整個工作流程之前就放棄了。 在那之前,我將文件保存在一個臨時目錄中。 假設用戶放棄並關閉瀏覽器窗口,我不希望這些文件揮之不去。

由於我將臨時路徑保留在 Flask 會話中——它只是一個最終會被刪除的字典(例如,超時),我可以自定義一個str類來保存臨時目錄地址/路徑,並讓它的__del__方法處理臨時目錄刪除。

它是這樣的:

class Tempdir(str):
    def __new__(cls, *args, **kwargs):
        from tempfile import mkdtemp
        _dir = mkdtemp()
        return super().__new__(cls, _dir)
    def __del__(self):
        from shutil import rmtree
        rmtree(str(self))

在你的 python 解釋器/應用程序中實例化它:

> d = Tempfile()
> d
'/var/folders/b1/frq3gywj3ljfqrf1yc7zk06r0000gn/T/tmptwa_g5fw'
> 
> import os
> os.path.exists(d)
True

當您退出解釋器時:

$ ls /var/folders/b1/frq3gywj3ljfqrf1yc7zk06r0000gn/T/tmptwa_g5fw
ls: /var/folders/b1/frq3gywj3ljfqrf1yc7zk06r0000gn/T/tmptwa_g5fw: No such file or directory

你去吧。

暫無
暫無

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

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