Az előző két bejegyzésben egy egyéni igényekre szabott Range osztályt készítettünk mint kompozíciót a beépített range típust felhasználva. Azért nem a range alosztályaként hoztuk létre a Range osztályt, mert a beépített range típusból nem lehet örökölni. Egyben jeleztük azt is, hogy nem csak a range az egyetlen ilyen beépített típus. A kérdés, hogy milyen más osztályok azok, amelyekből nem lehet örökölni.
Erre a kérdésre nem fogunk általános választ kapni a Python hivatalos dokumentációjában. Ezért vagy egyenként vizsgáljuk meg a kiszemelt osztályokat az örökölhetőség szempontjából, vagy általánosabb megoldást keresünk, amely a beépített típusokból, illetve tetszőleges modulban szereplő típusokból kiválogatja azokat, amelyekből nem lehet alosztályt létrehozni. Ez utóbbi megközelítést követjük és ebben a bejegyzésben egy erre alkalmas függvény hozunk létre, amely argumentumai a beimportált vizsgálandó modulok.
A függvény egy lehetséges definícióját láthatjuk alább. A részletes kommentek magyarázzák a működést.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
import builtins, types, typing, collections.abc, abc def non_subclassable_types(*modules): """Az argumentumban felsorolt nevű modulokban megkeresi azon nyilvános használatra szánt típusokat, amelyek nem lehetnek alaposztályok, vagyis amelyekből nem lehet altípust létehozni. """ # A visszatérési értékként átadott szótár, amelynek kulcsai a modulnevek. Minden egyes modulnévhez # egy lista tartozik, amelyben azon típusok neve van felsorolva, amelyekből nem lehet alosztályt létrehozni. non_subclassables:dict = {} for module in modules: # Az adott modulban megkeressük azokat az objektumokat és neveiket, amelyek nyilvános használatra szánt típusok. # Nyilvános használatra szánt a típus, ha a név nem privát, és szerepel a modul __all__ attribútumának # listájában, amennyiben a modul definiálja ezt. types_in_module = {name: obj for name, obj in vars(module).items() if isinstance(obj, type) if not name.startswith('_') if (name in module.__all__ if hasattr(module,'__all__') else True) } # A kigyűjtött típusokból megpróbálunk altípust létrehozni. Ha ez nem sikerül, akkor ezt a típust # az adott modulnévhez rendelt listába felvesszük, és eltároljuk az eredményszótárban, amennyiben a # modul nyilvános használatra szánt. for type_name, type_obj in types_in_module.items(): try: class A(type_obj):pass except TypeError: if not module.__name__.startswith('_'): non_subclassables.setdefault(module.__name__, []).append(type_name) return non_subclassables |
A beépített objektumokat és neveiket a szabványos könyvtár builtins modulja tartalmazza. Általánosan használt egyéb típusokat a types, a typing és például a collections.abc modulokban találunk még. Ezekkel meghívva a következő eredményt kapjuk:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# Az alaposztályként nem használható típusnevek kiírása. for module_name, list_of_type_names in non_subclassable_types(builtins, types, typing, collections.abc, abc).items(): print('\n{}:\n {}'.format(module_name,', '.join(list_of_type_names))) # Eredmény: # builtins: # bool, memoryview, range, slice # # types: # FunctionType, LambdaType, CodeType, MappingProxyType, CellType, GeneratorType, CoroutineType, # AsyncGeneratorType, MethodType, BuiltinFunctionType, BuiltinMethodType, WrapperDescriptorType, # MethodWrapperType, MethodDescriptorType, ClassMethodDescriptorType, TracebackType, FrameType, # GetSetDescriptorType, MemberDescriptorType, UnionType, EllipsisType, NoneType, NotImplementedType # # typing: # ForwardRef, TypeVar, ParamSpecArgs, ParamSpecKwargs, ParamSpec, Generic, Annotated |
Látható, hogy a legtöbb olyan típus, amely alaposztályként nem használható a types modulban található. Ehhez képest a builtins beépített típusai közül viszonylag legkevesebb ilyen van, amelyek között természetesen ott szerepel a range.
A fenti függvénnyel az előbb említett modulokon felül más modulokat is vizsgálhatunk, ha azokat beimportáljuk és felvesszük a függvény argumentumaként.
E bejegyzés témájához a Python tudásépítés lépésről lépésre című e-könyv következő részei kapcsolódnak különösen: a „Készétel fogyasztás – a szabványos könyvtár moduljainak használata” fejezet, illetve abban a „Típusutalások és statikus típusellenőrzés támogatása” alfejezet, amelyben a typing modullal ismerkedünk, továbbá a „Típusutalások generikus típusokkal” alfejezet, ahol a types modulról van szó, valamint az „Absztrakt osztályok” alfejezet „Készen kapható absztrakt osztályok” alcíme, amely a collections.abc modult tárgyalja, amelyben az absztrakt konténereket reprezentáló osztályok találhatók. Ezen felül a „Ne nyúlj hozzá, ha jót akarsz! – attribútumok priváttá minősítése” fejezet foglalkozik a privát attribútumokkal. Az __all__ attribútumról pedig a „Panelprogram – modulok” fejezetben a „Modul programként történő futtatása” alfejezetben van szó,