Должны ли все классы Python расширять объект?

129

Я обнаружил, что работают оба следующих варианта:

class Foo():
    def a(self):
        print "hello"

class Foo(object):
    def a(self):
        print "hello"

Должны ли все классы Python расширять объект? Есть ли потенциальные проблемы с невыдвижением объекта?

Кара
источник
2
Есть ли разница между class Foo():и class Foo:? Насколько я понимаю, оба работают на Python 3.
Wolf
В этом вопросе есть хороший ответ: stackoverflow.com/questions/4015417/…
nngeek

Ответы:

117

В Python 2 отказ от наследования от objectсоздаст класс в старом стиле, который, помимо других эффектов, typeдает разные результаты:

>>> class Foo: pass
... 
>>> type(Foo())
<type 'instance'>

против

>>> class Bar(object): pass
... 
>>> type(Bar())
<class '__main__.Bar'>

Кроме того, правила множественного наследования отличаются друг от друга, и я даже не буду пытаться здесь резюмировать. Вся хорошая документация по MI, которую я видел, описывает классы нового стиля.

Наконец, классы старого стиля исчезли в Python 3, и наследование от objectстало неявным. Поэтому всегда отдавайте предпочтение новым классам стилей, если вам не нужна обратная совместимость со старым программным обеспечением.

Фред Фу
источник
68

В Python 3 классы расширяются objectнеявно, независимо от того, говорите вы об этом или нет.

В Python 2 есть классы старого и нового стиля . Чтобы указать, что класс является новым стилем, вы должны явно наследовать от object. В противном случае используется реализация в старом стиле.

Обычно вам нужен класс нового стиля. objectЯвное наследование от . Обратите внимание, что это также относится к коду Python 3, который стремится быть совместимым с Python 2.

slezica
источник
Да, разница, на которую указал Free Foo , исчезла, BTW: необязательны ли пустые скобки?
Wolf
4
Существует много кода Python 3, который использует foo (object) :. Значит, это просто конвенция?
RFV5s
2
@RFVenter Это может быть код, который должен работать как под Python 2, так и под Python 3, и в этом случае вам нужно явно создать подкласс объекта, чтобы класс вел себя в основном так же, как и под Python 2.
blubberdiblub
@blubberdiblub Это то, что я подозревал, НО наш проект работает исключительно на python 3.5 virtualenv. Я думаю, что код должен быть скопирован из проекта python 2.
RFV5s
@RFVenter Ага, это может быть другое объяснение. И, конечно, если это Python 3.x только сейчас, можно избавиться от ссылок на объекты.
blubberdiblub
17

В python 3 вы можете создать класс тремя разными способами, и внутренне они все равны (см. Примеры). Неважно, как вы создаете класс, все классы в Python 3 наследуются от специального класса, называемого объектом . Класс объект является фундаментальным классом в Python и предоставляет много функциональных возможности, как методы двойного подчеркивания, дескрипторы, супер метод (метод), свойство () и т.д.

Пример 1.

class MyClass:
 pass

Пример 2.

class MyClass():
 pass

Пример 3.

class MyClass(object):
  pass
N Randhawa
источник
1
Это не совсем так ... stackoverflow.com/questions/1238606/…
Филип Адлер,
Я не уверен, что понимаю тебя. И да, вероятно, не имеет отношения к большинству людей, пока не станет актуальным.
Филип Адлер,
@PhilipAdler Принято считать, что objectэто ссылка на встроенный object. Если мы должны принять во внимание, что любой встроенный идентификатор CPython может быть заменен, мы едва ли сможем сделать какое-то утверждение о модели данных. Можно ли всерьез возразить, что strне всегда строка является аргументом, потому что ее можно присвоить builtins.str = None?
Нуно Андре
Я продолжаю видеть это утверждение, что это «широко предполагается», и я согласен с тем, что это предположение, которое делает каждая текущая реализация (это не требование языка), по моему опыту, большинство программистов на Python, которых я встречались, предполагали это, знали об этом или даже думали об этом. Независимо от этого, утверждение, что это обычно предполагается, даже если оно истинно, не отменяет моего утверждения о том, что эквивалентность не является строго истинной.
Филип Адлер
1

Да, все классы Python должны расширять (или, скорее, подкласс, здесь Python) объект. Хотя обычно серьезных проблем не возникает, в некоторых случаях (например, с множественными деревьями наследования) это будет важно. Это также обеспечивает лучшую совместимость с Python 3.

pydsigner
источник
1
точно, технически, если вы этого не сделаете, вы получите классический класс, но в этом нет реальных преимуществ, и он все равно не поддерживается python 3
max k.
Мне любопытно, почему он улучшает совместимость с python3. Насколько я понимаю, python3 автоматически расширяет объект, даже если вы его не указываете, верно?
Пол Ло
2
@PaulLo Верно, но если вы явно наследуете от объекта, вы получите такое же (в новом стиле) поведение как на Python 2, так и на Python 3. Дело не в изменении того, как работает Python 3, а в использовании переадресации -Совместимость с Python 2.
pydsigner
Это предложение выглядит не очень элегантно, но если вы обращаетесь к Python2 и Python3, оно кажется эффективным. Но насколько это актуально на практике?
Wolf
@Wolf Это зависит от того, что вы делаете. Если у вас сложные деревья наследования, это имеет большое значение. Если вы хотите, чтобы ваш класс был дескриптором, вы должны использовать новый стиль. Вы можете перейти по ссылкам на stackoverflow.com/questions/54867/…, если вам нужна более подробная информация.
pydsigner
1

Как уже говорилось в других ответах, наследование Python 3 от объекта является неявным. Но они не говорят, что вам следует делать и что является условностью.

Все примеры документации Python 3 используют следующий стиль, который является соглашением, поэтому я предлагаю вам следовать ему для любого будущего кода на Python 3.

class Foo:
    pass

Источник: https://docs.python.org/3/tutorial/classes.html#class-objects

Пример цитаты:

Объекты класса поддерживают два типа операций: ссылки на атрибуты и создание экземпляров.

В ссылках на атрибуты используется стандартный синтаксис, используемый для всех ссылок на атрибуты в Python: obj.name. Допустимые имена атрибутов - это все имена, которые были в пространстве имен класса при создании объекта класса. Итак, если определение класса выглядело так:

class MyClass:
    """A simple example class"""
    i = 12345

    def f(self):
        return 'hello world'

Еще одна цитата:

Вообще говоря, переменные экземпляра предназначены для данных, уникальных для каждого экземпляра, а переменные класса - для атрибутов и методов, общих для всех экземпляров класса:

class Dog:

    kind = 'canine'         # class variable shared by all instances

    def __init__(self, name):
        self.name = name    # instance variable unique to each instance
jmoz
источник
0

в python3 нет различий, но в python2 без расширения objectвы получаете классы в старом стиле; вы хотите использовать класс нового стиля вместо класса старого стиля.

thkang
источник
2
Это разумный ответ, но другие респонденты получили его быстрее и / или более подробно; этот ответ не добавляет ценности странице в ее нынешнем виде.
Марк Эмери