Python和类属性声明

时间:2013-02-11 15:42:13

标签: python class attributes pep8

我被告知在类范围内声明动态属性不是'Python方式',但我不明白为什么。 有人可以向我解释这个或者给我一些文件,告诉我为什么这是一件坏事吗?老实说,我认为这是一个很好的做法,如果有任何自我记录代码。

示例:

class ClassA(object):
    user_data = {}

    def set_user(self):
        self.user_data['username'] = 'fred'

我可以看到不使用它的唯一原因是属性是静态的(因此可能会产生误导)..

4 个答案:

答案 0 :(得分:3)

在评论中,您说,“每个实例都有不同的可变user_data。”不,它不会。 ClassA的每个实例都将共享相同的user_data字典:

>>> class ClassA(object):
...     user_data = {}
...     def set_user(self, name):
...         self.user_data['name'] = name
...
>>> a1 = ClassA()
>>> a1.set_user('fred')
>>> a1.user_data
{'name': 'fred'}
>>>
>>> a2 = ClassA()
>>> a2.user_data
{'name': 'fred'}
>>> a2.set_user('barney')
>>> a2.user_data
{'name': 'barney'}
>>>
>>> a1.user_data
{'name': 'barney'}
>>>
>>> a1.user_data is a2.user_data
True

这不是Pythonic是否存在的问题。这是编写符合您需要的代码的问题。

答案 1 :(得分:1)

使用显示的代码,user_data不是动态属性(它不是“动态地”在类实例上创建的)。这是一个类属性,它更像是我认为的其他语言中的“静态”属性。这意味着它是在读取和初始化类时在类上声明的属性。这具有能够通过self.whatever访问同一对象的所有实例的副作用/好处。

换句话说:

class Foo(object):
    whatever = {}
    def __init__(self):
        print self.whatever is Foo.whatever

将始终打印True。当然,您可以通过向实例添加不同的whatever属性来更改此行为:

class Bar(object):
     whatever = {}
     def __init__(self):
         self.whatever = {}
         print self.whatever is Bar.whatever

使用Foo,如果我添加项目foo_instance.whatever['foo'] = 'bar',则foo_instance2也会看到此更改,而Bar则不会出现这种情况。< / p>

答案 2 :(得分:0)

以下是使用类和实例成员的示例:

class Test(object):
    instances = {}

    def __init__(self, name):

        self.instance = self
        self.instances[name] = self

    # rest of class

a = Test('alfred')
b = Test('banana')

# use a to get a
print a.instance

>>> 
<__main__.Test object at 0x0000000002BEBC50>

# get all instances of the Test class
print Test.instances

>>>
{'banana': <__main__.Test object at 0x0000000002BEBDA0>, 'alfred': <__main__.Test object at 0x0000000002BEBC50>}

由于这些仅仅是示例,它们并没有反映任何具体的内容,只是可以做的事情。

在某些情况下声明一个类成员很有用,如上所述,如果你想能够记录,并控制某个类的所有类型。但是你应该总是理解你在做什么,并且不要认为instance是每个实例都是本地的。

关于'最佳实践'和'最pythonic方式'的问题。就是这样,意见。有些人会不赞同某些事情,而不是其他人。只要您遵守您碰巧参与的任何劳动力规定的标准和标准,您就应该以一种让您感到舒适并且适合您的方式撰写。

答案 3 :(得分:0)

要清楚,类属性可能与您预期的不同。

示例:

class Example(object):
    class_data={}
    def __init__(self,val):
        self.val=val
    def __repr__(self):
        return str(self.val) 

>>> Example.class_data['one']=1    # assign value to the empty dict in class Example
>>> e1,e2=Example(1), Example(2)   # INSTANCES-self.val different for each instance
>>> print e1,e2,e1.class_data,e2.class_data
1 2 {'one': 1} {'one': 1}
      ^^^^^      ^^^^^         # SAME class_data in two different instances

请注意,示例的每个实例都具有相同的class_data可变副本。它不受保护,因为静态类变量可以是Java或C ++。

实际上,您可以随时随意更改,添加或删除这些类属性:

>>> Example.class_data='old dict is gone gone gone...'
>>> print e1,e2,e1.class_data,e2.class_data  
1 2 old dict is gone gone gone... old dict is gone gone gone...

你可能会看到这样的代码:

class Example(object):
    class_constants=('fee','fie','foe')
    # ...

由于这种错误的安慰,它表现得像常数(在另一种语言中):

>>> e1=Example(1)
>>> e1.class_constants[4]='fum'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment    

但这是一种错误的安慰,因为一段代码总能做到这一点:

>>> Example.class_constants=('another','tuple','of','constants')

一些人对类属性的麻烦在于他们没有做出预期的事情 - 好像它是一个常数。它们不是常数。类属性更改了类的所有现有和未来实例的数据。有时有用,但可能令人困惑。

真的,如果class属性是可变的那么无关紧要。如您所见 - 您可以随时更改属性。