inheritance from str or int

Why I have problem creating a class inheriting from str (or also from 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)

tha same happens if I try to use int вместо str, but it works with custom classes. Мне нужно использовать __new__ вместо __init__? Зачем?

6 ответов

Решение
>>> 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)

вы можете отложить любые методы, которые вы хотите работать на основе strself.s вручную или автоматически с помощью __getattr__,

Это, как говорится, необходимость вашего собственного строкового типа является то, что должно дать вам паузу. Есть много классов, которые должны хранить строку в качестве своих основных данных, но вы обычно хотите использовать str или же unicode (последний, если вы представляете текст) для общего представления строк. (Одно распространенное исключение - если вам нужно использовать строковый тип инструментария пользовательского интерфейса.) Если вы хотите добавить функциональность в ваши строки, попробуйте, если вы можете использовать функции, которые работают со строками, а не новые объекты в качестве строк, что сохраняет Ваш код проще и более совместим со всеми остальными программами.

Когда вы создаете экземпляр класса, аргументы, которые вы передаете, передаются как __new__ (конструктор), а затем к __init__ (инициализатор) методы класса. Поэтому, если вы наследуете от класса, который имеет ограничения на число аргументов, которые могут быть предоставлены во время создания экземпляра, вы должны гарантировать, что ни один из его __new__ни его __init__ получит больше аргументов, чем они ожидают. Так что это проблема, которая у вас есть. Вы создаете экземпляр своего класса с C("a", "B"), Переводчик ищет __new__ метод в C, 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, Питон__new__ Функция в основном существует, чтобы разрешить наследование от неизменяемых типов.

Внимательно прочитав это, вот еще одна попытка подклассов ул. По сравнению с другими ответами создается экземпляр в правильном классе с использованием 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

Вот и все.

Другие вопросы по тегам