可能重复:
Python: Difference between class and instance attributes
我正试图在Python中了解OOP,在一个类中声明变量时我有点困惑。我应该在__init__
程序内还是在程序外声明它们?有什么区别?
以下代码可以正常使用:
# Declaring variables within __init__
class MyClass:
def __init__(self):
country = ""
city = ""
def information(self):
print "Hi! I'm from %s, (%s)"%(self.city,self.country)
me = MyClass()
me.country = "Spain"
me.city = "Barcelona"
me.information()
但是声明__init__
过程之外的变量也有效:
# Declaring variables outside of __init__
class MyClass:
country = ""
city = ""
def information(self):
print "Hi! I'm from %s, (%s)"%(self.city,self.country)
me = MyClass()
me.country = "Spain"
me.city = "Barcelona"
me.information()
答案 0 :(得分:8)
在第一个示例中,您将定义实例属性。在第二个,类属性。
类属性在该类的所有实例之间共享,其中实例属性为"拥有"通过那个特定的例子。
示例差异
要理解这些差异,请使用示例。
我们将定义一个具有实例属性的类:
class MyClassOne:
def __init__(self):
self.country = "Spain"
self.city = "Barcelona"
self.things = []
有一个类属性:
class MyClassTwo:
country = "Spain"
city = "Barcelona"
things = []
打印出有关其中一个对象的信息的函数:
def information(obj):
print "I'm from {0}, ({1}). I own: {2}".format(
obj.city, obj.country, ','.join(obj.things))
让我们创建2个MyClassOne
个对象并将其变为米兰,然后给米兰"":
foo1 = MyClassOne()
bar1 = MyClassOne()
foo1.city = "Milan"
foo1.country = "Italy"
foo1.things.append("Something")
当我们在information()
和foo1
上致电bar1
时,我们会获得您期望的价值:
>>> information(foo1)
I'm from Milan, (Italy). I own: Something
>>> information(bar1)
I'm from Barcelona, (Spain). I own:
但是,如果我们要做同样的事情,但是使用MyClassTwo
的实例,您会看到类属性在实例之间共享。
foo2 = MyClassTwo()
bar2 = MyClassTwo()
foo2.city = "Milan"
foo2.country = "Italy"
foo2.things.append("Something")
然后拨打information()
...
>>> information(foo2)
I'm from Milan, (Italy). I own: Something
>>> information(bar2)
I'm from Barcelona, (Spain). I own: Something
正如您所看到的 - 实例之间共享things
。 things
是对每个实例有权访问的列表的引用。因此,如果您从任何实例附加到所有其他实例将看到相同列表的内容。
您在字符串变量中看不到此行为的原因是您实际上正在为实例分配新变量。在这种情况下,该参考是"拥有"由实例而不是在类级别共享。为了说明,我们为bar2
的内容分配了一个新列表:
bar2.things = []
这导致:
>>> information(foo2)
I'm from Milan, (Italy). I own: Something
>>> information(bar2)
I'm from Barcelona, (Spain). I own:
答案 1 :(得分:4)
你的两个版本的代码是非常不同的。在python中,您有2个不同的实体: classes 和 class instances 。实例是您执行的操作:
new_instance = my_class()
您可以通过__init__
将属性绑定到self
中的实例(self
是新实例)。
class MyClass(object):
def __init__(self):
self.country = "" #every instance will have a `country` attribute initialized to ""
self
和__init__
没有什么特别之处。 self
是用于表示传递给每个方法的实例的惯用名称(默认情况下)。
a.method() #-> Inside the class where `method` is defined, `a` gets passed in as `self`
这里唯一特别的是在构造类时调用__init__
:
a = MyClass() #implicitly calls `__init__`
您还可以将属性绑定到类(将其放在__init__
之外):
class MyClass(object):
country = "" #This attribute is a class attribute.
在任何时候,您都可以通过以下方式将新属性绑定到实例:
my_instance = MyClass()
my_instance.attribute = something
通过以下方式对类的新属性:
MyClass.attribute = something
现在它变得有趣了。如果一个实例没有请求的属性,那么python会查看该属性的类并返回它(如果它在那里)。因此,类属性是类的所有实例共享一段数据的一种方式。
考虑:
def MyClass(object):
cls_attr = []
def __init__(self):
self.inst_attr = []
a = MyClass()
a.inst_attr.append('a added this')
a.cls_attr.append('a added this to class')
b = MyClass()
print (b.inst_attr) # [] <- empty list, changes to `a` don't affect this.
print (b.cls_attr) # ['a added this to class'] <- Stuff added by `a`!
print (a.inst_attr) #['a added this']
答案 2 :(得分:0)
在类范围(任何方法之外)中定义变量时,它将成为类属性。在方法范围中定义值时,它将成为方法局部变量。如果为属性self
(或引用对象的任何其他标签)分配值,它将成为(或修改)实例属性。