[英]Python class syntax - is this a good idea?
我很想定义我的Python类:
class MyClass(object):
"""my docstring"""
msg = None
a_variable = None
some_dict = {}
def __init__(self, msg):
self.msg = msg
声明对象变量(msg,a_variable等)在顶部,如Java好还是坏或无关紧要? 我知道这是不必要的,但仍然很有诱惑力。
在类定义中定义变量就像这样,使得变量可以在该类的每个实例之间访问。 在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'
直接在类定义中声明变量使它们成为类变量而不是实例变量。 类变量有点类似于Java中的静态变量,应该像MyClass.a_variable
一样使用。 但它们也可以像self.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 = {}
使用两个下划线表示“私有”变量( 伪私有! )是可选的。 如果变量应该是公共的,只需保留其名称不带__
前缀。
小心。 这两个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
当你声明一个类时,Python将解析它的代码并将所有内容放在类的命名空间中; 那么这个类将被用作从它派生的所有对象的一种模板 - 但是任何对象都有自己的引用副本。
请注意,您始终有参考; 因此,如果您能够更改引用的对象,则更改将反映到它正在使用的所有位置。 但是,成员数据的插槽对于每个实例都是唯一的,因此将其分配给新对象将不会反映到正在使用的任何其他位置。
注意:Michael Foord有关于类实例化如何工作的非常好的博客文章 ; 如果你对这个话题感兴趣,我建议你阅读一下。
无论如何,对于所有实际用途,两种方法之间存在两个主要差异:
通常,审查代码我看到在班级宣布的成员有点怀疑; 它们有很多很好的用例,但它们很可能是以前使用其他编程语言的习惯。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.