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

Dav*_*nez 4 python attributes initialization

可能重复:
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()
Run Code Online (Sandbox Code Playgroud)

但是声明__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()
Run Code Online (Sandbox Code Playgroud)

Ale*_*per 8

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

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

以身作则

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

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

class MyClassOne:
    def __init__(self):
        self.country = "Spain"
        self.city = "Barcelona"
        self.things = []
Run Code Online (Sandbox Code Playgroud)

还有一个具有类属性:

class MyClassTwo:
    country = "Spain"
    city = "Barcelona"
    things = []
Run Code Online (Sandbox Code Playgroud)

并且打印出有关这些对象之一的信息的函数:

def information(obj):
    print "I'm from {0}, ({1}). I own: {2}".format(
                obj.city, obj.country, ','.join(obj.things))
Run Code Online (Sandbox Code Playgroud)

让我们创建2个MyClassOne对象并将其变为米兰,并给米兰"一些东西":

foo1 = MyClassOne()
bar1 = MyClassOne()

foo1.city = "Milan"
foo1.country = "Italy"
foo1.things.append("Something")
Run Code Online (Sandbox Code Playgroud)

当我们呼吁information()foo1,bar1我们会得到您期望的价值:

>>> information(foo1)
I'm from Milan, (Italy). I own: Something

>>> information(bar1)
I'm from Barcelona, (Spain). I own: 
Run Code Online (Sandbox Code Playgroud)

但是,如果我们要做同样的事情,但是使用MyClassTwo你的实例会看到类属性在实例之间共享.

foo2 = MyClassTwo()
bar2 = MyClassTwo()

foo2.city = "Milan"
foo2.country = "Italy"
foo2.things.append("Something")
Run Code Online (Sandbox Code Playgroud)

然后打电话给information()...

>>> information(foo2)
I'm from Milan, (Italy). I own: Something
>>> information(bar2)
I'm from Barcelona, (Spain). I own: Something
Run Code Online (Sandbox Code Playgroud)

正如您所看到的 - things正在实例之间共享.things是对每个实例都可以访问的列表的引用.因此,如果您从任何实例追加到所有其他实例将看到相同列表的内容.

您在字符串变量中没有看到此行为的原因是您实际上正在为实例分配新变量.在这种情况下,引用由实例"拥有"而不在类级别共享.为了说明,让我们为事物分配一个新列表bar2:

bar2.things = []
Run Code Online (Sandbox Code Playgroud)

这导致:

>>> information(foo2)
I'm from Milan, (Italy). I own: Something
>>> information(bar2)
I'm from Barcelona, (Spain). I own: 
Run Code Online (Sandbox Code Playgroud)


mgi*_*son 5

你这两个版本的代码有很大的不同。在 python 中,您有 2 个不同的实体: classesclass instances。实例是您执行以下操作时创建的内容:

new_instance = my_class()
Run Code Online (Sandbox Code Playgroud)

您可以将属性绑定到__init__via self(self是新实例)内的实例。

class MyClass(object):
    def __init__(self):
        self.country = ""  #every instance will have a `country` attribute initialized to ""
Run Code Online (Sandbox Code Playgroud)

self和没有什么特别特别的地方__init__self是用于表示传递给每个方法的实例的惯用名称(默认情况下)。

a.method()  #-> Inside the class where `method` is defined, `a` gets passed in as `self`
Run Code Online (Sandbox Code Playgroud)

这里唯一特别的是__init__在构造类时被调用:

a = MyClass()  #implicitly calls `__init__`
Run Code Online (Sandbox Code Playgroud)

您还可以将属性绑定到类(将其放在外面__init__):

class MyClass(object):
    country = ""  #This attribute is a class attribute.
Run Code Online (Sandbox Code Playgroud)

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

my_instance = MyClass()
my_instance.attribute = something
Run Code Online (Sandbox Code Playgroud)

或者通过以下方式为类添加新属性:

MyClass.attribute = something
Run Code Online (Sandbox Code Playgroud)

现在它变得有趣了。如果实例没有请求的属性,则 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']
Run Code Online (Sandbox Code Playgroud)