在__init__内部或外部声明数据属性有什么区别



可能的重复:
Python:类和实例属性之间的区别

我试图在 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()

在第一个示例中,您将定义实例属性。第二,类属性

类属性在该类的所有实例之间共享,其中作为实例属性由该特定实例"拥有"。

示例差异

为了理解差异,让我们使用一个例子。

我们将定义一个具有实例属性的类:

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")

当我们在foo1bar1上调用information()时,我们会得到您期望的值:

>>> 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: 

你们两个版本的代码非常不同。 在python中,你有2个不同的实体:类和类实例。 实例是在执行以下操作时创建的内容:

new_instance = my_class()

您可以通过self将属性绑定到__init__中的实例(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']

当您在类范围(在任何方法之外)定义变量时,它将成为类属性。 在方法作用域中定义值时,它将成为方法局部变量。 如果将值分配给self的属性(或引用对象的任何其他标签),则该值将成为(或修改)实例属性。

最新更新