Python'daki eski stil ile yeni stil sınıfları arasındaki fark nedir? Birini ne zaman kullanmalıyım?
Python'daki eski stil ile yeni stil sınıfları arasındaki fark nedir? Birini ne zaman kullanmalıyım?
Yanıtlar:
Gönderen Yeni tarzı ve klasik sınıflar :
Python 2.1'e kadar, eski stil sınıfları kullanıcının kullanabileceği tek lezzetti.
(Eski stil) sınıf kavramı, tip kavramıyla ilişkisizdir: eğer
x
eski stil sınıfının birx.__class__
örneğiyse, sınıfını belirtirx
, ancaktype(x)
her zaman öyle olur<type 'instance'>
.Bu, tüm eski stil örneklerinin, sınıflarından bağımsız olarak, örnek adı verilen tek bir yerleşik türle uygulandığını yansıtır.
Sınıf ve tür kavramlarını birleştirmek için Python 2.2'de yeni stil sınıfları tanıtıldı . Yeni stil sınıfı, yalnızca kullanıcı tanımlı bir türdür, daha fazla, daha az değil.
X, yeni stil sınıfının bir örneğiyse
type(x)
, genellikle aynıdırx.__class__
(bu garanti edilmese de - yeni stil sınıf örneğinin döndürülen değeri geçersiz kılmasına izin verilirx.__class__
).Yeni stil sınıflarını tanıtmak için en büyük motivasyon, tam bir meta model ile birleştirilmiş bir nesne modeli sağlamaktır .
Ayrıca, en yerleşik türlerin alt sınıflandırma yeteneği veya hesaplanan özellikleri etkinleştiren "tanımlayıcıların" tanıtılması gibi bir dizi acil faydası vardır.
Uyumluluk nedeniyle, sınıflar varsayılan olarak hala eski stildir .
Yeni stil sınıfları, üst sınıf olarak başka bir yeni stil sınıfı (yani bir tür) veya başka bir üst öğeye ihtiyaç duyulmadığında "üst düzey tür" nesnesi belirtilerek oluşturulur.
Yeni stil sınıflarının davranışı, eski tip sınıfların davranışından, hangi türün döndüğüne ek olarak bir dizi önemli ayrıntıda farklıdır.
Bu değişikliklerin bazıları, özel yöntemlerin çağrılma şekli gibi yeni nesne modeli için temeldir. Diğerleri, çoklu kalıtım durumunda yöntem çözüm sırası gibi uyumluluk endişeleri için daha önce uygulanamayan "düzeltmelerdir".
Python 3 yalnızca yeni stil sınıflarına sahiptir .
object
Python 3'te alt sınıf olsun ya da olmasın sınıflar yeni bir stildir.
super()
eski stil sınıfları üzerinde çalışmıyor. Bahsetmemek gerekirse, bu makalede belirtildiği gibi, MRO gibi temel düzeltmeler ve bunu kullanmak için iyi bir neden olmaktan çok özel yöntemler vardır.
Beyan-bilge:
Yeni stil sınıfları nesneden veya başka bir yeni stil sınıfından miras alır .
class NewStyleClass(object):
pass
class AnotherNewStyleClass(NewStyleClass):
pass
Eski tarz dersler yoktur.
class OldStyleClass():
pass
Python 3 Not:
Python 3 eski stil sınıflarını desteklemediğinden, yukarıda belirtilen formlardan herhangi biri yeni bir stil sınıfıyla sonuçlanır.
object
.
class AnotherOldStyleClass: pass
class A: pass
ve class A(): pass
kesinlikle eşdeğer. Birincisi "A, hiçbir ana sınıfı miras almaz" ve ikincisi "A hiçbir ana sınıfı olmayan miras" anlamına gelir . Bu oldukça benzer not is
veis not
Eski ve yeni stil sınıfları arasında önemli davranış değişiklikleri
Exception
(aşağıdaki örnek)__slots__
katmaDiğer cevaplarda bahsedildi, ancak burada klasik MRO ve C3 MRO (yeni stil sınıflarında kullanılan) arasındaki farkın somut bir örneği var.
Soru, özniteliklerin (yöntemler ve üye değişkenleri içeren) çoklu kalıtımda aranma sırasıdır.
Klasik sınıflar soldan sağa doğru derinlikte bir arama yapar. İlk maçta dur. Bu __mro__
özelliklere sahip değiller .
class C: i = 0
class C1(C): pass
class C2(C): i = 2
class C12(C1, C2): pass
class C21(C2, C1): pass
assert C12().i == 0
assert C21().i == 2
try:
C12.__mro__
except AttributeError:
pass
else:
assert False
Yeni stil sınıfları MRO, tek bir İngilizce cümlede sentezlemek için daha karmaşıktır. Bu ayrıntılı olarak açıklanmıştır burada . Özelliklerinden biri, temel sınıfın yalnızca türetilmiş tüm sınıflar arandıktan sonra aranmasıdır. Onlar sahip __mro__
arama sırasını gösterir niteliğini.
class C(object): i = 0
class C1(C): pass
class C2(C): i = 2
class C12(C1, C2): pass
class C21(C2, C1): pass
assert C12().i == 2
assert C21().i == 2
assert C12.__mro__ == (C12, C1, C2, C, object)
assert C21.__mro__ == (C21, C2, C1, C, object)
Exception
Python 2.5 civarında birçok sınıf yükseltilebilir ve Python 2.6 civarında bu kaldırıldı. Python 2.7.3'te:
# OK, old:
class Old: pass
try:
raise Old()
except Old:
pass
else:
assert False
# TypeError, new not derived from `Exception`.
class New(object): pass
try:
raise New()
except TypeError:
pass
else:
assert False
# OK, derived from `Exception`.
class New(Exception): pass
try:
raise New()
except New:
pass
else:
assert False
# `'str'` is a new style object, so you can't raise it:
try:
raise 'str'
except TypeError:
pass
else:
assert False
Eski stil sınıfları, özellik araması için hala biraz daha hızlıdır. Bu genellikle önemli değildir, ancak performansa duyarlı Python 2.x kodunda yararlı olabilir:
[3]: sınıf A'da: ...: def __init __ (kendi kendine): ...: self.a = 'merhaba' ...: [4] 'te B sınıfı (nesne): ...: def __init __ (kendi kendine): ...: self.a = 'merhaba' ...: [6] 'da: aobj = A () [7] 'de: bobj = B () [8] 'de:% timeit aobj.a 10000000 döngü, döngü başına en iyi 3: 78,7 ns [10] 'da:% timeit bobj.a 10000000 döngü, döngü başına en iyi 3: 86,9 ns
%timeit aobj.a
10000000 loops, best of 3: 66.1 ns per loop
%timeit bobj.a
10000000 loops, best of 3: 53.9 ns per loop
Guido, Python'daki yeni stil ve eski stil sınıfı hakkında gerçekten harika bir makale olan Yeni Stil Sınıfları'nın İç Hikayesini yazdı .
Python 3 sadece yeni stil sınıfına sahiptir. Bir 'eski stil sınıfı' yazsanız bile, dolaylı olarak türetilir object
.
Yeni stil sınıfları, super
yeni C3 mro , bazı sihirli yöntemler vb.Gibi eski stil sınıflarında eksik olan bazı gelişmiş özelliklere sahiptir .
İşte çok pratik, doğru / yanlış bir fark. Aşağıdaki kodun iki sürümü arasındaki tek fark, ikinci sürümde Kişinin nesneden miras almasıdır . Bunun dışında, iki versiyon aynı, ancak farklı sonuçlarla:
Eski tarz sınıflar
class Person():
_names_cache = {}
def __init__(self,name):
self.name = name
def __new__(cls,name):
return cls._names_cache.setdefault(name,object.__new__(cls,name))
ahmed1 = Person("Ahmed")
ahmed2 = Person("Ahmed")
print ahmed1 is ahmed2
print ahmed1
print ahmed2
>>> False
<__main__.Person instance at 0xb74acf8c>
<__main__.Person instance at 0xb74ac6cc>
>>>
Yeni stil sınıfları
class Person(object):
_names_cache = {}
def __init__(self,name):
self.name = name
def __new__(cls,name):
return cls._names_cache.setdefault(name,object.__new__(cls,name))
ahmed1 = Person("Ahmed")
ahmed2 = Person("Ahmed")
print ahmed2 is ahmed1
print ahmed1
print ahmed2
>>> True
<__main__.Person object at 0xb74ac66c>
<__main__.Person object at 0xb74ac66c>
>>>
_names_cache
ilettiğiniz her adı önbelleğe alan (gelecekteki erişim için depolayan) bir sözlüktür Person.__new__
. Setdefault yöntemi (herhangi bir sözlükte tanımlanır) iki bağımsız değişken alır: bir anahtar ve bir değer. Anahtar dikte ise, değerini döndürür. Dikte değilse, önce ikinci argüman olarak iletilen değere ayarlar ve sonra döndürür.
__new__()
her zaman çağrılır ve her zaman yeni bir nesne oluşturur ve sonra atar. Bu durumda a if
tercih edilir .setdefault()
.
__new__
aslında eski tarz sınıflar için bir şey değildir, örneğin inşaatta kullanılmaz (tanımlamak gibi özel görünen rastgele bir addır __spam__
). Bu nedenle, eski stil sınıfının oluşturulması sadece çağrılırken __init__
, yeni stil konstrüksiyon __new__
, inşa __init__
etmek ve başlatmak için (tekton örneğine göre birleşerek) çağırır .
Yeni stil sınıfları object
Python 2.2'den itibaren miras alınır ve böyle yazılmalıdır (yani class Classname(object):
yerine class Classname:
). Temel değişiklik türleri ve sınıfları birleştirmektir ve bunun güzel yan etkisi, yerleşik türlerden miras almanıza izin vermesidir.
Daha fazla bilgi için descrintro sayfasını okuyun .
Yeni stil sınıfları , bir sınıf ve örnek super(Foo, self)
olduğu yerlerde kullanabilir .Foo
self
super(type[, object-or-type])
Bir üst veya kardeş sınıf sınıfına yöntem çağrılarını devreten bir proxy nesnesi döndürün. Bu, bir sınıfta geçersiz kılınan kalıtsal yöntemlere erişmek için kullanışlıdır. Arama sırası, türün kendisinin atlanması dışında getattr () tarafından kullanılanla aynıdır.
Ve Python 3.x'te super()
herhangi bir parametre olmadan bir sınıfın içinde kullanabilirsiniz .
type(x)
. Yerleşik bir türü alt sınıflara ayırmıyorsam, yeni stil sınıflarından görebildiğim bir avantaj yok gibi görünüyor. Bir dezavantajı var, ki bu da ekstra yazıyor(object)
.