2014-01-08 15 views
2

所以我不是来自计算机科学背景,而且我很难搜索/搜索正确的术语来回答这个问题。如果我有一个Python类与类变量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

也许我要澄清,我想我的'MyClass'的用户使用'objects',但我不想MyClass'的'实例使用对象。由jonrsharpe提供的链接谈论了很多关于如何使私人事物,这是不是我想要解决这个问题。我更感兴趣的是,如果可能只有类中存在类变量,而不是实例中。 – Randy

+0

为什么你需要在你的课堂里添加这样的变量?将它添加到模块的根目录并不简单?例如'在您的类定义之外添加'MY_VARIABLE ='test'' – furins

+0

将它添加到模块根目录可能会更简单,但我处于这种情况下需要对调用代码进行很多其他更改,这就是为什么我想保留它在课堂上。 – Randy

回答

1

的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) 
+0

我是元类的最近粉丝,我的代码已经以类似的方式使用它们来在对象传递给用户之前执行一些对象的引导。在元类中这样做非常好。 – Randy

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. 
+0

我想让其他人访问'MyClass.objects',而不是'a.objects',所以我想'__init__'可以设置'self.objects = None'? – Randy

+0

好的,我编辑了我的问题,以显示一种方法来做到这一点 – jonrsharpe

+1

请注意,该类的实例仍然可以重新定义'__getattribute__'函数,删除保护。从这一部分,这是一个优雅的方法。 – furins

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' 

的原因是:

当你创建一些类的实例没有什么可以阻止 你从内闲逛,并使用各种内部,私人 方法,这些方法(一)所需类的功能,但(b)不是 ,旨在直接使用/访问。

python中没有什么是真正的私有。 没有任何课堂或班级实例可以让你远离所有内在的东西(这使得自省 可能和强大)。 Python相信你。它说:“嘿,如果你想在黑暗的地方四处张望,我会相信你有一个很好的理由,而且你不会遇到麻烦。” Karl Fast

+0

谢谢@furins,这是我怀疑的,但我只是想确保这种类型的行为,特别是当我想要一定的'MyClass.objects'的可访问性。在其他SO答案中的名称 - 等等,并不完全符合我的这种微妙的方法。 – Randy

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]: [] 
相关问题