Here's a suggestion that's a slight tweak on @LondonRob's answer: if possible, use an Enum instead of magic strings to specify a Person's profession.
from enum import Enum, auto
from typing import TypeVar
class Profession(Enum):
TEACHER = auto()
SURGEON = auto()
P = TypeVar('P')
class Person:
def __init__(self, name: str, profession: Profession) -> None:
self.name = name
self.profession = profession
@classmethod
def create_teacher(cls: type[P], name: str) -> P:
return cls(name=name, profession=Profession.TEACHER)
This has the advantage that you can test the person's profession much more cleanly:
>>> Bob = Person.create_teacher('Bob')
>>> Bob.profession is Profession.TEACHER
True
In fact, you could even generalise your alternative constructor by making it an instance method of your Profession class, rather than a classmethod on your Person class:
from __future__ import annotations
from enum import Enum, auto
class Person:
def __init__(self, name: str, profession: Profession) -> None:
self.name = name
self.profession = profession
class Profession(Enum):
TEACHER = auto()
SURGEON = auto()
def create(self, name: str) -> Person:
return Person(name=name, profession=self)
In usage:
>>> Bob = Profession.TEACHER.create(name='Bob')
>>> Suzie = Profession.SURGEON.create(name='Suzie')
As an aside, if your class is essentially a wrapper around structured data, then you could also consider using dataclasses (whether or not you go the Enum route):
from enum import Enum, auto
from dataclasses import dataclass
from typing import TypeVar
class Profession(Enum):
TEACHER = auto()
SURGEON = auto()
P = TypeVar('P')
@dataclass
class Person:
name: str
profession: Profession
@classmethod
def create_teacher(cls: type[P], name: str) -> P:
return cls(name=name, profession=Profession.TEACHER)