Python中的私有构造函数

112 投票
14 回答
53822 浏览
提问于 2025-04-17 06:45

我该如何创建一个私有构造函数,让它只能被类中的静态函数调用,而不能从其他地方调用呢?

14 个回答

18

你可以对在不同范围内可见的名称有很大的控制权——而且可用的范围有很多。下面是两种 三种其他方法,可以限制一个类只能通过工厂方法来创建:

#Define the class within the factory method
def factory():
  class Foo:
    pass
  return Foo()

或者

#Assign the class as an attribute of the factory method
def factory():
  return factory.Foo()
class Foo:
  pass
factory.Foo = Foo
del Foo

(注意:这仍然允许从外部引用这个类(比如用于isinstance检查),但很明显你不应该直接实例化它。)

或者

#Assign the class to a local variable of an outer function
class Foo:
  pass
def factory_maker():
  inner_Foo=Foo
  def factory():
    return inner_Foo()
  return factory
factory = factory_maker()
del Foo
del factory_maker

这样做会让访问Foo类变得不可能(至少,除非使用至少一个魔法(双下划线)属性),但仍然允许多个函数使用它(通过在删除全局Foo名称之前定义它们)。

40

如何创建一个私有构造函数?

简单来说,这是不可能的。因为 Python 的构造函数和你在其他面向对象编程语言中理解的方式不一样,而且 Python 并不严格限制私有性,它只是有一种特定的语法来表示某个方法或属性应该被视为私有的。让我详细解释一下……

首先,Python 中最接近构造函数的东西是__new__ 方法,但这个方法非常少用(你通常会使用__init__,它用于修改刚创建的对象,实际上它的第一个参数已经是self了)。

无论如何,Python 的设计理念是大家都是成年人,因此私有和公共的概念并不像其他语言那样严格。

正如其他回答者提到的,通常被认为是“私有”的方法会在前面加一个或两个下划线:_private__private。这两者的区别在于,后者会对方法的名称进行混淆,这样你就无法从对象外部调用它,而前者则不会。

举个例子,如果你的类A定义了_private(self)__private(self)

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

通常你会想使用单个下划线,特别是在单元测试中,使用双下划线可能会让事情变得非常复杂……

希望这对你有帮助!

76

在Python中,前面加一个下划线(_)或两个下划线(__)并不能限制对象只能通过特定的“工厂”来创建。不过,Python是个强大的工具箱,我们可以用多种方法实现想要的效果(正如@Jesse W在Z上展示的那样)。

这里有一个可能的解决方案,它让类仍然可以被公开访问(这样可以使用isinstance等功能),但确保对象只能通过类方法来创建:

class OnlyCreatable(object):

    __create_key = object()

    @classmethod
    def create(cls, value):
        return OnlyCreatable(cls.__create_key, value)

    def __init__(self, create_key, value):
        assert(create_key == OnlyCreatable.__create_key), \
            "OnlyCreatable objects must be created using OnlyCreatable.create"
        self.value = value

通过create这个类方法来构造对象:

>>> OnlyCreatable.create("I'm a test") 
<__main__.OnlyCreatable object at 0x1023a6f60>

如果试图不使用create这个类方法来构造对象,就会因为断言失败而无法创建:

>>> OnlyCreatable(0, "I'm a test")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 11, in __init__
AssertionError: OnlyCreatable objects can only be created using OnlyCreatable.create

如果试图模仿create这个类方法来创建对象,也会因为编译器对OnlyCreatable.__createKey的处理而失败。

>>> OnlyCreatable(OnlyCreatable.__createKey, "I'm a test")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'OnlyCreatable' has no attribute '__createKey'

在类方法之外构造OnlyCreatable的唯一方法是知道OnlyCreatable.__create_key的值。由于这个类属性的值是在运行时生成的,并且它的名字前面有两个下划线,标记为不可访问,因此实际上几乎“无法”获取这个值和/或构造这个对象。

撰写回答