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

Python 在init内部或外部声明数据属性有什么区别__,python,attributes,initialization,Python,Attributes,Initialization,可能重复: 我试图了解Python中的OOP,但在类中声明变量时,我有点困惑。我应该在\uuu init\uu过程内部还是外部声明它们?有什么区别 以下代码工作正常: # Declaring variables within __init__ class MyClass: def __init__(self): country = "" city = "" def information(self): print "Hi! I'm

可能重复:

我试图了解Python中的OOP,但在类中声明变量时,我有点困惑。我应该在
\uuu init\uu
过程内部还是外部声明它们?有什么区别

以下代码工作正常:

# 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()
但是在
\uuuu init\uuu
过程之外声明变量也可以:

# 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()

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

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

new_instance = my_class()
您可以通过
self
self
是新实例)将属性绑定到
中的实例

self
\uuuuu init\uuuu
没有什么特别之处
self
是常用名称,用于表示传递给每个方法的实例(默认情况下)

这里唯一特别的是,在构造类时调用
\uuuu init\uuu

a = MyClass()  #implicitly calls `__init__`
您还可以将属性绑定到类(将其置于
\uuuu init\uuuu
之外):

在任何时候,您都可以通过以下方式将新属性绑定到实例:

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']
def MyClass(对象):
cls_attr=[]
定义初始化(自):
self.inst_attr=[]
a=MyClass()
a、 inst_attr.append('a添加了此')
a、 cls_attr.append('a将此添加到类')
b=MyClass()

打印(b.inst_attr)#[]在第一个示例中,您定义的是实例属性。第二,类属性

类属性在该类的所有实例之间共享,其中as实例属性由该特定实例“拥有”

class MyClass(object):
    def __init__(self):
        self.country = ""  #every instance will have a `country` attribute initialized to ""
示例差异

为了理解差异,让我们举个例子

我们将使用实例属性定义一个类:

class MyClassOne:
    def __init__(self):
        self.country = "Spain"
        self.city = "Barcelona"
        self.things = []
class MyClassTwo:
    country = "Spain"
    city = "Barcelona"
    things = []
还有一个具有类属性:

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
对象,并将其中一个对象更改为Milan,并给Milan“一些东西”:

当我们在
foo1
bar1
上调用
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
如您所见-
实例之间正在共享内容<代码>事物
是对每个实例都可以访问的列表的引用。所以,如果您附加到任何实例中的内容,那么所有其他实例都会看到相同的列表

foo2 = MyClassTwo()
bar2 = MyClassTwo()

foo2.city = "Milan"
foo2.country = "Italy"
foo2.things.append("Something")
在字符串变量中看不到这种行为的原因是,实际上您正在为实例分配一个新变量。在这种情况下,引用由实例“拥有”,而不是在类级别共享。为了举例说明,让我们为
bar2
的内容分配一个新列表:

bar2.things = []
这导致:

>>> information(foo2)
I'm from Milan, (Italy). I own: Something
>>> information(bar2)
I'm from Barcelona, (Spain). I own: 

这个问题似乎也混淆了实例属性和方法局部变量。python中没有变量声明这样的东西!变量只分配给/初始化(bined是正确的术语)。声明和初始化之间没有区别。强调一下
\uuuuu init\uuuu
绝对没有什么特殊之处可能会有用。您可以在每个方法中,甚至在类代码之外添加实例属性(就像Op所做的那样,即使我不知道他是否知道这点)。@Bakuriu--Updated。也许现在会更清楚了?很好,但我也应该更清楚,类属性是跨实例共享的,这可能会给不理解这一点的人带来问题。非常感谢!现在,这是完全有道理的。我想我会感到困惑,因为我使用的是不可变类型。