Чи повинні всі класи 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'>

vs.

>>> 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.



4
Існує дуже багато коду python 3, який використовує foo (object):. Це тоді лише умовність?
RFV5s

2
@RFVenter Це може бути код, який повинен працювати під Python 2 та 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

1
Це не зовсім вірно ... stackoverflow.com/questions/1238606/…
Філіп Адлер

Я не впевнений, що йду за тобою. І так, мабуть, не стосується більшості людей, поки це не актуально.
Філіп Адлер

@PhilipAdler Зазвичай прийнято вважати, що objectце посилання на вбудований object. Якщо ми маємо врахувати, що будь-який вбудований ідентифікатор CPython можна замінити, ми ледве можемо зробити певне твердження щодо моделі даних. Чи можна серйозно стверджувати, що strне завжди приймається рядок як аргумент, тому що можна призначити builtins.str = None?
Нуно Андре

Я продовжую бачити це твердження, що це "широко припускається", і я приймаю, що це припущення, яке робить кожна поточна реалізація (це не вимога мови), не було мого досвіду, що більшість програмістів python я зустрічалися, припускають це, знають про це або навіть розглядали це. Незалежно від цього, твердження про те, що зазвичай прийнято вважати, навіть якщо це правда, не скасовує моє твердження про те, що еквівалентність не є суто істинною.
Філіп Адлер

1

Так, всі класи Python повинні поширювати (а точніше підклас, це Python тут) об'єктом. Хоча зазвичай ніяких серйозних проблем не виникне, в деяких випадках (як і з кількома деревами спадкування) це буде важливо. Це також забезпечує кращу сумісність з Python 3.


1
Власне, якщо ви цього не зробите, то ви отримаєте класичний клас, але реальних переваг для цього немає, і його не підтримує python 3
max k.

Мені цікаво, чому це покращує сумісність з python3. Наскільки я розумію, python3 змусить автоматично розширювати об'єкт, навіть якщо ви не вказали його, правда?
Пол Ло

2
@PaulLo Правильно, але якщо ви явно наслідуєте об'єкт, ви отримаєте однакове (новий стиль) поведінку як на Python 2, так і на Python 3. Це не питання про те, як змінювати, як працює Python 3, це питання використовувати вперед -сумісність на Python 2.
pydsigner

Ця пропозиція виглядає не дуже елегантно, але якщо ви звертаєтесь до Python2 та Python3, вона здається ефективною. Але наскільки це актуально на практиці?
Вовк

@Wolf Це залежить від того, що ти робиш. Якщо у вас є складні дерева спадкування, це має велике значення. Якщо ви хочете, щоб ваш клас був дескриптором, вам доведеться використовувати новий стиль. Ви можете перейти за посиланнями з stackoverflow.com/questions/54867/…, якщо хочете отримати більш глибоку інформацію.
підсігнер

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

0

у python3 немає різниці, але в python2 нерозширення objectдає класи старого стилю; ви хочете використовувати клас нового стилю над класом старого стилю.


2
Ця відповідь є обґрунтованою, але інші відповіді потрапили туди швидше та / або детальніше; ця відповідь не додає жодних значень сторінки, як вона є.
Марк Амері
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.