mac*_*mac 30
如何创建私有构造函数?
从本质上讲,这是不可能的,因为如果你来自其他OOP语言并且因为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
Run Code Online (Sandbox Code Playgroud)
您通常希望使用单个下划线,因为 - 特别是对于单元测试 - 具有双下划线可能会使事情变得非常棘手....
HTH!
小智 25
的_和__前缀不提供解决方案限制的对象到特定的"工厂"的实例化,然而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
Run Code Online (Sandbox Code Playgroud)
使用create类方法构造对象:
>>> OnlyCreatable.create("I'm a test")
<__main__.OnlyCreatable object at 0x1023a6f60>
Run Code Online (Sandbox Code Playgroud)
在尝试构造对象而不使用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
Run Code Online (Sandbox Code Playgroud)
如果尝试通过模仿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'
Run Code Online (Sandbox Code Playgroud)
在OnlyCreatable类方法之外构造的唯一方法是知道它的值OnlyCreatable.__create_key.由于此类属性的值是在运行时生成的,并且其名称前缀为__标记为无法访问,因此实际上"不可能"获取此值和/或构造对象.
Jes*_*t Z 10
正如没人提到的那样 - 你可以对在什么范围内可见的名称有相当大的控制权- 并且有很多可用的范围.以下是另外 三种将类的构造限制为工厂方法的方法:
#Define the class within the factory method
def factory():
class Foo:
pass
return Foo()
Run Code Online (Sandbox Code Playgroud)
要么
#Assign the class as an attribute of the factory method
def factory():
return factory.Foo()
class Foo:
pass
factory.Foo = Foo
del Foo
Run Code Online (Sandbox Code Playgroud)
(注意:这仍然允许从外部引用类(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
Run Code Online (Sandbox Code Playgroud)
这使得不可能(至少不使用至少一个魔术(双下划线)属性)来访问Foo该类,但仍允许多个函数使用它(通过在删除全局Foo名称之前定义它们).
此外,还会识别使用前导或尾部下划线的以下特殊形式(这些形式通常可与任何案例约定结合使用):
_single_leading_underscore:弱"内部使用"指标.例如,"from M import *"不会导入名称以下划线开头的对象.
single_trailing_underscore_:用于避免与Python关键字冲突的约定,例如Tkinter.Toplevel(master, class_='ClassName')
__double_leading_underscore:当命名一个类属性时,调用名称修改(在类FooBar中,__boo变为_FooBar__boo;见下文).
__double_leading_and_trailing_underscore__:生成在用户控制的命名空间中的"魔术"对象或属性.例如__init__,__import__或__file__.不要发明这样的名字; 只记录使用它们.
尽管 Python 中不存在严格的私有属性,但您可以使用元类来防止使用MyClass()语法来创建MyClass对象。
以下是改编自Trio项目的示例:
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
Run Code Online (Sandbox Code Playgroud)
下面是一个使用示例:
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
Run Code Online (Sandbox Code Playgroud)
首先,术语“构造函数”不适用于Python,因为虽然__init__()方法扮演了一个角色,但它只是一个在对象已经创建并需要初始化时调用的方法。
Python 中类的每个方法都是公共的。通常,程序员用方法名称_或__方法名称来标记“私有”方法,例如:
# inheriting from object is relevant for Python 2.x only
class MyClass(object):
# kinda "constructor"
def __init__(self):
pass
# here is a "private" method
def _some_method(self):
pass
# ... and a public one
def another_method(self):
pass
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
20479 次 |
| 最近记录: |