Private Constructor in Python

前端 未结 8 1996
栀梦
栀梦 2020-12-13 23:19

How do I create a private constructor which should be called only by the static function of the class and not from else where?

8条回答
  •  醉酒成梦
    2020-12-13 23:50

    Though strictly private attributes do not exist in Python, you can use a metaclass to prevent the use of the MyClass() syntax to create a MyClass object.

    Here is an example adapted from the Trio project:

    from typing import Type, Any, TypeVar
    
    
    T = TypeVar("T")
    
    
    class NoPublicConstructor(type):
        """Metaclass that ensures a private constructor
    
        If a class uses this metaclass like this:
    
            class SomeClass(metaclass=NoPublicConstructor):
                pass
    
        If you try to instantiate your class (`SomeClass()`),
        a `TypeError` will be thrown.
        """
    
        def __call__(cls, *args, **kwargs):
            raise TypeError(
                f"{cls.__module__}.{cls.__qualname__} has no public constructor"
            )
    
        def _create(cls: Type[T], *args: Any, **kwargs: Any) -> T:
            return super().__call__(*args, **kwargs)  # type: ignore
    

    Here is an example of use:

    from math import cos, sin
    
    
    class Point(metaclass=NoPublicConstructor):
         def __init__(self, x, y):
             self.x = x
             self.y = y
    
         @classmethod
         def from_cartesian(cls, x, y):
             return cls._create(x, y)
         
         @classmethod
         def from_polar(cls, rho, phi):
             return cls._create(rho * cos(phi), rho * sin(phi))
    
    Point(1, 2) # raises a type error
    Point.from_cartesian(1, 2) # OK
    Point.from_polar(1, 2) # OK
    

提交回复
热议问题