Python类是否可以访问成员,但不能从类的实例中访问?

时间:2014-01-08 17:12:25

标签: python

所以我不是来自计算机科学背景,我在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中有一个类变量可供类的用户访问(即不仅仅来自类中),但不能访问该类的实例?我认为这被称为私人会员或其他语言的静态会员?

4 个答案:

答案 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