Private Constructor in Python

前端 未结 8 1974
栀梦
栀梦 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:45

    How do I create a private constructor?

    In essence, it's impossible both because python does not use constructors the way you may think it does if you come from other OOP languages and because python does not enforce privacy, it just has a specific syntax to suggest that a given method/property should be considered as private. Let me elaborate...

    First: the closest to a constructor that you can find in python is the __new__ method but this is very very seldom used (you normally use __init__, which modify the just created object (in fact it already has self as first parameter).

    Regardless, python is based on the assumption everybody is a consenting adult, thus private/public is not enforced as some other language do.

    As mentioned by some other responder, methods that are meant to be "private" are normally prepended by either one or two underscores: _private or __private. The difference between the two is that the latter will scramble the name of the method, so you will be unable to call it from outside the object instantiation, while the former doesn't.

    So for example if your class A defines both _private(self) and __private(self):

    >>> a = A()
    >>> a._private()   # will work
    >>> a.__private()  # will raise an exception
    

    You normally want to use the single underscore, as - especially for unit testing - having double underscores can make things very tricky....

    HTH!

    0 讨论(0)
  • 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
    
    0 讨论(0)
提交回复
热议问题