2013-04-17 13 views
7

natknąłem następujące w python docs:W jaki sposób Python zapobiega podklasie klasy?

BOOL ([x])

Konwersja wartości do logiczną, przy użyciu standardowej procedury badania prawdy. Jeśli x jest fałszywe lub pominięte, to zwraca False; w przeciwnym razie zwraca True. bool jest również klasą, która jest podklasą int. Klasa bool nie może być dalej podklasowana. Jego jedynymi przypadkami są Fałsz i Prawda.

Nigdy w moim życiu nie chciałem podklasy bool, ale oczywiście od razu próbował, i na pewno wystarczy:

>>> class Bool(bool): 
    pass 

Traceback (most recent call last): 
    File "<pyshell#2>", line 1, in <module> 
    class Bool(bool): 
TypeError: Error when calling the metaclass bases 
    type 'bool' is not an acceptable base type 

Więc pytanie: Jak to jest zrobione? Czy mogę zastosować tę samą technikę (lub inną), aby oznaczyć własne klasy jako final, czyli uniemożliwić ich subklasę?

+1

Dlaczego nie chcesz do podklasy 'bool'? Można utworzyć podklasy "10", aby przedstawić każdy możliwy stan boolowski. – jamylak

+0

Dzięki @Martijn, to wygląda jak ściśle powiązane pytanie. Nie pojawił się on podczas mojego wyszukiwania SO (powinienem był pomyśleć o dodaniu "ostatecznego" do wyszukiwanych słów). – alexis

Odpowiedz

13

Typ bool jest zdefiniowany w C, a jego tp_flags celowo nie obejmuje Py_TPFLAGS_BASETYPE flag.

Typy C muszą oznaczać siebie jako jawnie jako podklasę.

Aby to zrobić dla niestandardowych klas Pythona, użyj metaklasa:

class Final(type): 
    def __new__(cls, name, bases, classdict): 
     for b in bases: 
      if isinstance(b, Final): 
       raise TypeError("type '{0}' is not an acceptable base type".format(b.__name__)) 
     return type.__new__(cls, name, bases, dict(classdict)) 

class Foo: 
    __metaclass__ = Final 

class Bar(Foo): 
    pass 

daje:

>>> class Bar(Foo): 
...  pass 
... 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 5, in __new__ 
TypeError: type 'Foo' is not an acceptable base type 
+0

Dzięki, że to obejmuje! – alexis

+0

W dalszej refleksji, mam pytanie: Czy istnieje jakiś cel do sprawdzenia 'isinstance (b, Final)'? Mam na myśli, że ten "__new__" będzie kiedykolwiek wywołany tylko przez klasę, która dziedziczy po 'Final', więc dlaczego nie podbijać natychmiast, jeśli' cls! = 'Final''? – alexis

+0

@alexis: Tak, ponieważ musisz podać nazwę klasy bazowej, z której próbowałeś dziedziczyć. 'Bar' nie ma podklasy' Final', podklasy 'Foo', dlatego test' isinstance (b, Final) 'zwraca' True' dla tej klasy. Jeśli używanych jest więcej klas bazowych, chcesz poinformować użytkownika końcowego, z której z tych zasad nie jest dziedziczony. –

Powiązane problemy