我很想定义我的Python类:
class MyClass(object):
"""my docstring"""
msg = None
a_variable = None
some_dict = {}
def __init__(self, msg):
self.msg = msg
声明对象变量(msg,a_variable等)在顶部,如Java好还是坏或无关紧要?我知道这是不必要的,但仍然很有诱惑力。
答案 0 :(得分:8)
在类定义中定义变量,使得变量可以在该类的每个实例之间访问。在Java术语中,有点像使变量成为静态。但是,如下所示,存在重大差异。
class MyClass(object):
msg = "ABC"
print MyClass.msg #prints ABC
a = MyClass()
print a.msg #prints ABC
a.msg = "abc"
print a.msg #prints abc
print MyClass.msg #prints ABC
print a.__class__.msg #prints ABC
从上面的代码可以看出,它并不完全相同,因为变量可以通过self.msg
进行访问,当它被赋值时,它不会被分配给类范围中定义的变量。
通过您执行的方法执行此操作的一个缺点是,它可能会导致错误,因为它会为类添加隐藏状态。假设有人从构造函数中遗漏了self.msg = "ABC"
(或者更实际的代码被重构,只有一个定义被更改)
a = MyClass()
print a.msg #prints ABC
#somewhere else in the program
MyClass.msg = "XYZ"
#now the same bit of code leads to a different result, despite the expectation that it
#leads to the same result.
a = MyClass()
print a.msg #prints XYZ
最好避免在类级别定义msg然后避免问题:
class MyClass(object):
pass
print MyClass.msg #AttributeError: type object 'MyClass' has no attribute 'msg'
答案 1 :(得分:6)
直接在类定义中声明变量使它们成为类变量而不是实例变量。类变量有点类似于Java中的静态变量,应该像MyClass.a_variable
一样使用。但它们也可以像self.a_variable
一样使用,这是一个问题,因为天真的程序员可以将它们视为实例变量。例如,您的“some_dict”变量将由MyClass
的每个实例共享,因此如果您向其添加密钥“k”,则任何实例都可以看到该变量。
如果你总是记得重新分配类变量,那么实例变量几乎没有区别。只保留MyClass
中的初始定义。但无论如何,这不是一个好习惯,因为你可能会在没有重新分配这些变量时遇到麻烦!
最好像这样编写课程:
class MyClass(object):
"""
Some class
"""
def __init__(self, msg):
self.__msg = msg
self.__a_variable = None
self.__some_dict = {}
对“私有”变量(pseudo-private!)使用两个下划线是可选的。如果变量应该是公共的,只需保留其名称不带__
前缀。
答案 2 :(得分:4)
小心。这两个msg属性实际上存储在两个不同的字典中。
一个遮蔽了另一个,但被破坏的msg
属性仍占据字典中的空间。所以它没有被使用,但仍占用了一些记忆。
class MyClass(object):
msg = 'FeeFiFoFum'
def __init__(self, msg):
self.msg = msg
m=MyClass('Hi Lucy')
请注意,我们将'Hi Lucy'
作为值。
print(m.__dict__)
# {'msg': 'Hi Lucy'}
请注意,MyClass的dict(通过m.__class__
访问)仍然有FeeFiFoFum
。
print(m.__class__.__dict__)
# {'__dict__': <attribute '__dict__' of 'MyClass' objects>, '__module__': '__main__', '__init__': <function __init__ at 0xb76ea1ec>, 'msg': 'FeeFiFoFum', 'some_dict': {}, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>, '__doc__': 'my docstring', 'a_variable': None}
另一种(也许更简单)的方式来看待这个:
print(m.msg)
# Hi Lucy
print(MyClass.msg)
# FeeFiFoFum
答案 3 :(得分:1)
当你声明一个类时,Python将解析它的代码并将所有内容放在类的命名空间中;那么这个类将被用作从它派生的所有对象的一种模板 - 但是任何对象都有自己的引用副本。
请注意,您总是有一个参考;因此,如果您能够更改引用的对象,则更改将反映到它正在使用的所有位置。但是,成员数据的插槽对于每个实例都是唯一的,因此将其分配给新对象将不会反映到正在使用的任何其他位置。
注意:Michael Foord对类实例化的工作原理有very nice blog entry;如果你对这个话题感兴趣,我建议你阅读一下。
无论如何,对于所有实际用途,两种方法之间存在两个主要差异:
通常,审查代码我看到在类级别声明的成员有点怀疑;它们有很多很好的用例,但它们很可能是以前使用其他编程语言的习惯。