编写类块时,将创建 类属性 (或类变量)。您在类块中分配的所有名称,包括您定义的方法都将
def成为类属性。
创建类实例后,任何引用该实例的对象都可以在其上创建实例属性。在方法内部,“当前”实例几乎总是与名称绑定
self,这就是为什么您将它们视为“自变量”的原因。通常,在面向对象的设计中,附加到类的代码应该可以控制该类的实例的属性,因此几乎所有实例属性的分配都在方法内部完成,使用对
self参数的接收来引用实例。方法。
通常将类属性与在Java,C#或C ++等语言中发现的 静态
变量(或方法)进行比较。但是,如果您想更深入地理解,我会避免将类属性视为与静态变量“相同”。尽管它们通常用于相同的目的,但基本概念却大不相同。在该行下面的“高级”部分中,有更多关于此的内容。
一个例子!
class SomeClass: def __init__(self): self.foo = 'I am an instance attribute called foo' self.foo_list = [] bar = 'I am a class attribute called bar' bar_list = []
执行该块之后,有一类
SomeClass,3类的属性:
__init__,
bar,和
bar_list。
然后,我们将创建一个实例:
instance = SomeClass()
发生这种情况时,将执行
SomeClass的
__init__方法,并在其
self参数中接收新实例。此方法创建两个实例属性:
foo和
foo_list。然后将此实例分配到
instance变量中,因此将其绑定到具有这两个实例属性的事物:
foo和
foo_list。
但:
print instance.bar
给出:
I am a class attribute called bar
这怎么发生的?当我们尝试通过点语法 检索 属性而该属性不存在时,Python会通过一系列步骤尝试尝试满足您的请求。下一步将尝试查看实例类的 类属性
。在这种情况下,它发现一个属性
bar的
SomeClass,所以它返回。
这也是方法调用的方式。
mylist.append(5)例如,当您调用时,
mylist没有名为的属性
append。但 类
的
mylist事情,它绑定到一个方法的对象。该方法对象由该
mylist.append位返回,然后该
(5)位使用参数调用该方法
5。
这很有用,因为的 所有
实例
SomeClass都可以访问同一
bar属性。我们可以创建一百万个实例,但是我们只需要将一个字符串存储在内存中,因为它们都可以找到它。
但是您必须小心一点。看一下以下操作:
sc1 = SomeClass()sc1.foo_list.append(1)sc1.bar_list.append(2)sc2 = SomeClass()sc2.foo_list.append(10)sc2.bar_list.append(20)print sc1.foo_listprint sc1.bar_listprint sc2.foo_listprint sc2.bar_list
您如何看待此打印?
[1][2, 20][10][2, 20]
这是因为每个实例都有其自己的副本
foo_list,因此将它们分别附加到。但是 所有
实例共享对同一实例的访问
bar_list。因此,当我们这样做
sc1.bar_list.append(2)时
sc2,即使它
sc2还不存在,它也会受到影响!并且同样
sc2.bar_list.append(20)影响了
bar_list通过检索
sc1。这通常不是您想要的。
接下来是高级学习。:)
要真正掌握Python(来自Java和C#等传统的静态类型的OO语言),您必须学习重新考虑类。
在Java中,类本身并不是 一件 真正的 事情
。当您编写一个类时,您在声明的东西更多是该类的所有实例都具有的共同点。在运行时,只有实例(和静态方法/变量,但是它们实际上只是与类关联的名称空间中的全局变量和函数,与OO无关)。类是您在源代码中写下实例在运行时的样子的方式。它们仅“存在”于您的源代码中,而不存在于正在运行的程序中。
在Python中,类没有什么特别的。就像其他任何东西一样,它是一个对象。因此,“类属性”实际上与“实例属性”完全相同;实际上,只有“属性”。产生区别的唯一原因是我们倾向于
使用 类而非非对象的对象。底层机制都是一样的。这就是为什么我说将类属性视为其他语言的静态变量是错误的。
但是真正使Python类不同于Java样式类的是,就像其他任何对象一样, 每个类都是某个类的实例 !
在Python中,大多数类都是称为的内置类的实例
type。此类控制类的常见行为,并使所有OO东西按其方式进行。具有类的实例的默认OO方式具有自己的属性,并具有由类定义的通用方法/属性,这只是Python中的协议。您可以根据需要更改其大多数方面。如果您曾经听说过使用
元类 ,那么所有定义的是一个类,该类是与的不同类的实例
type。
关于类的唯一真正“特殊”的东西(除了所有内置的机制,使它们按默认方式工作),是类块语法,使您更轻松地创建
type。这个:
class Foo(baseFoo): def __init__(self, foo): self.foo = foo z = 28
大致等同于以下内容:
def __init__(self, foo): self.foo = fooclassdict = {'__init__': __init__, 'z': 28 }Foo = type('Foo', (baseFoo,) classdict)并且它将安排所有内容
classdict成为要创建的对象的属性。
因此,看到您可以
Class.attribute像一样轻松地访问class属性变得微不足道
i = Class();i.attribute。这两个
i和
Class的对象,对象也有属性。这也使您易于理解在创建类后如何修改它。只需像对待其他对象一样分配属性即可!
实际上,实例与用于创建实例的类没有特殊的特殊关系。Python知道在哪个类中搜索实例中未找到的__class__
属性的方式是通过hidden属性。与其他任何属性一样,您可以阅读以了解其是哪个类的实例`c
some_instance.class
。现在,您已经有了一个c`绑定到类的变量,即使它的名称可能与该类的名称不同。您可以使用它来访问类属性,甚至可以调用它来创建它的更多实例(即使您不知道它是什么类!)。
您甚至可以分配
i.__class__更改其实例的类!如果执行此操作,则不会立即发生任何特别的事情。这不是惊天动地。这意味着,当您查找实例中不存在的属性时,Python会查看的新内容
__class__。由于其中包括大多数方法,并且方法通常希望它们所操作的实例处于特定状态,因此,如果您随机执行操作,通常会导致错误,这非常令人困惑,但是可以做到。如果您非常小心,请存放在里面的东西
__class__甚至不必成为类对象;Python要做的所有事情就是在特定情况下查找属性,因此您所需要的只是具有正确种类的属性的对象(除了一些警告,Python确实对类或特定类的实例有些挑剔)。
现在可能就足够了。希望(如果您还读过这么远的话)我没有对您感到困惑。当您了解Python的工作原理时,Python十分简洁。:)



