所以我不是来自计算机科学背景,我在google搜索/搜索正确的术语以回答这个问题时遇到了麻烦。如果我有一个带有类变量objects
的Python类,如下所示:
class MyClass(object):
objects = None
pass
MyClass.objects = 'test'
print MyClass.objects # outputs 'test'
a = MyClass()
print a.objects # also outputs 'test'
该类的类和实例都可以访问objects
变量。我知道我可以像这样更改实例值:
a.objects = 'bar'
print a.objects # outputs 'bar'
print MyClass.objects # outputs 'test'
但是有可能在Python中有一个类变量可供类的用户访问(即不仅仅来自类中),但不能访问该类的实例?我认为这被称为私人会员或其他语言的静态会员?
答案 0 :(得分:2)
Python旨在允许类的实例通过实例访问该类的属性。
这只是深入一级,所以你可以使用元类:
class T(type):
x = 5
class A(object):
__metaclass__ = T
请注意,Python 3中的元类语法不同。这有效:
>>> A.x
5
>>> A().x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'x'
但是,它不会阻止您设置类的实例属性;为了防止你必须玩__setattr__
魔法:
class A(object):
x = 1
def __getattribute__(self, name):
if name == 'x':
raise AttributeError
return super(A, self).__getattribute__(name)
def __setattr__(self, name, value):
if name == 'x':
raise AttributeError
return super(A, self).__setattr__(name, value)
def __delattr__(self, name):
if name == 'x':
raise AttributeError
return super(A, self).__delattr__(name)
答案 1 :(得分:2)
实现它的最简单方法是使用descriptor。描述符是 用于提供对属性访问的更高级别控制的东西。例如:
class ClassOnly(object):
def __init__(self, name, value):
self.name = name
self.value = value
def __get__(self, inst, cls):
if inst is not None:
msg = 'Cannot access class attribute {} from an instance'.format(self.name)
raise AttributeError(msg)
return self.value
class A(object):
objects = ClassOnly('objects', [])
用作:
In [11]: a = A()
In [12]: a.objects
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-12-24afc67fd0ba> in <module>()
----> 1 a.objects
<ipython-input-9-db6510cd313b> in __get__(self, inst, cls)
5 def __get__(self, inst, cls):
6 if inst is not None:
----> 7 raise AttributeError('Cannot access class attribute {} from an instance'.format(self.name))
8 return self.value
AttributeError: Cannot access class attribute objects from an instance
In [13]: A.objects
Out[13]: []
答案 2 :(得分:1)
如果你希望objects
有一个“单一的事实来源”,你可以把它变成一个可变的类型:
class MyClass(object):
objects = []
对于不可变类型,每个实例以MyClass
的相同引用开始的事实是无关紧要的,因为第一次为该实例更改该属性时,它将与类的值“断开连接”。
但是,如果该属性是可变的,则在实例中更改它会更改该类以及该类的所有其他实例:
>>> MyClass.objects.append(1)
>>> MyClass.objects
[1]
>>> a = MyClass()
>>> a.objects
[1]
>>> a.objects.append(2)
>>> a.objects
[1, 2]
>>> MyClass.objects
[1, 2]
在Python中,实际上“私有”没有任何内容,因此您无法阻止实例访问或更改objects
(在这种情况下,它是一个合适的类属性吗?),但如果您通常不希望直接访问它们,则通常会使用下划线添加名称:_objects
。
实际保护objects
免受实例访问的一种方法是覆盖__getattribute__
:
def __getattribute__(self, name):
if name == "objects":
raise AttributeError("Do not access 'objects' though MyClass instances.")
return super(MyClass, self).__getattribute__(name)
>>> MyClass.objects
[1]
>>> a.objects
...
AttributeError: Do not access 'objects' though MyClass instances.
答案 3 :(得分:0)
不,你不能(编辑:你不能以完全无法访问的方式,如Java或C ++)。
如果您愿意,可以这样做:
class MyClass(object):
objects = None
pass
MyClass_objects = 'test'
print MyClass_objects # outputs 'test'
a = MyClass()
print a.objects # outputs 'None'
或:
your_module.py
中的:
objects = 'test'
class MyClass(object):
objects = None
pass
yourapp.py
中的:
import your_module
print your_module.objects # outputs 'test'
a = your_module.MyClass()
print a.objects # outputs 'None'
原因是:
当您创建某个类的实例时,没有什么可以阻止的 你来自内心,使用各种内部,私人 方法是(a)班级运作所必需的,但是(b)不是 供直接使用/访问。
python中没有什么是私有的。没有类或类实例可以 让你远离所有内在的东西(这使得内省 可能和强大的)。 Python信任你。它说“嘿,如果你想要的话 在黑暗的地方逛逛,我会相信你有一个 有充分的理由而且你没有制造麻烦。“ Karl Fast