Python类成员

时间:2012-09-13 15:25:41

标签: python class member-variables

我只是在学习Python,而且我来自C背景,所以如果我在两者之间有任何混淆/混淆,请告诉我。

假设我有以下课程:

class Node(object):
    def __init__(self, element):
        self.element = element
        self.left = self.right = None

    @classmethod
    def tree(cls, element, left, right):
        node = cls(element)
        node.left = left
        node.right = right
        return node

这是一个名为Node的类,它重载构造函数,以便在需要时能够处理不同的参数。

仅在self.element中定义__init__(如上所示)与执行以下操作之间有什么区别:

class Node(object):
    element, left, right = None
    def __init__(self, element):
        self.element = element
        self.left = self.right = None

self.element中的__init__与定义的类element变量不同吗?这不会只是从element覆盖None到传递到element的{​​{1}}值吗?

7 个答案:

答案 0 :(得分:69)

一个是类属性,而另一个是实例属性。它们是不同的,但它们彼此密切相关的方式使它们看起来有时相同。

它与python查找属性的方式有关。有层次结构。在简单的情况下,它可能如下所示:

instance -> Subclass -> Superclass -> object (built-in type)

当您在instance上查找属性时......

`instance.val`

......实际发生的是 first ,Python在实例本身中查找val。然后,如果找不到val,则会在其类Subclass中查找。然后,如果在那里找不到val,则会查找SubclassSuperclass的父级。这意味着当你这样做时......

>>> class Foo():
    foovar = 10  
    def __init__(self, val):
        self.selfvar = val

... Foo 的所有实例共享 foovar,但拥有自己独特的selfvar。以下是一个简单,具体的例子:

>>> f = Foo(5)
>>> f.foovar
10
>>> Foo.foovar
10

如果我们不触及foovar,则fFoo的情况相同。但是,如果我们改变f.foovar ...

>>> f.foovar = 5
>>> f.foovar
5
>>> Foo.foovar
10

...我们添加了一个有效掩盖Foo.foovar值的实例属性。现在,如果我们直接更改Foo.foovar,则不会影响我们的foo实例:

>>> Foo.foovar = 7
>>> f.foovar
5

但它确实会影响新的foo实例:

>>> Foo(5).foovar
7

还要记住,可变对象增加了另一层间接(正如mgilson提醒我的那样)。这里,f.foovar引用与Foo.foovar相同的对象,因此当您更改对象时,更改将在层次结构中向上传播:

>>> Foo.foovar = [1]
>>> f = Foo(5)
>>> f.foovar[0] = 99
>>> Foo.foovar
[99]

答案 1 :(得分:12)

在python中,可以使用同名的类变量和实例变量。它们分别位于内存中,访问方式完全不同。

在您的代码中:

class Node(object):
    element, left, right = None
    def __init__(self, element):
        self.element = element
        self.left = self.right = None

第一组变量(在__init__函数之外)被称为类变量。这些可以随后使用Node.element等进行访问。这些等同于C ++中的静态成员变量,并且它们由类的所有实例共享。

第二组变量(在__init__函数内)称为实例变量。这些是通过self对象访问的,例如self.element,或实例名称,例如课外myNode.element

请务必注意,您必须使用self.variableNode.variable表单从成员函数中访问其中任何一个。只需访问variable即可尝试访问名为variable的本地变量。

答案 2 :(得分:2)

构造函数中的self.element是一个实例变量(如果一个节点对象修改了它的值,它只对该对象进行了更改),其中第二个版本中的那个是一个类变量(所以如果一个节点对象修改它的值,它将会更改所有节点对象。)

C ++中的类比将是非静态的,而不是类中的静态成员变量。

答案 3 :(得分:0)

重要的部分是self的{​​{1}}参数。实际上,在任何实例方法中,这将是第一个参数。这是通过设计完成的;在Python中,实际访问实例的唯一时间是在方法调用期间,并且使用__init__参数显式显示。

当你在self定义中时,你还没有任何实例,所以你真正修改的是类本身。因此,如果在类级别定义属性,那么它们实际上变为类属性,而不是实例。

将它与C(++)进行比较,您可能会说这些语言中的“类”基本上是它们所代表的对象的蓝图。 “这些对象应具有classfoo属性,此外还有以下方法。”然而,在Python中,类本身就是对象,它们的主要优点是它们可以创建自己的副本(实例),这也恰好使用了类的方法。所以,它更像是“你将barfoo作为类属性,此外,还有以下用于创建实例的方法。”

因此,而不是蓝图,它更像是一步一步的操作方法。

答案 4 :(得分:0)

init 中的 self.element是一个实例变量,您可以通过键入self.element在任何其他成员函数中获取/设置它。在类中声明的元素是类变量,您可以通过键入Node.element来获取/设置它。

答案 5 :(得分:0)

当您尝试使用类访问变量时,它仅查看

cls.__dict__

但是当你尝试用实例访问变量时,它首先看起来

self.__dict__ 

如果找到然后返回或者如果找不到那么它也会查找

cls.__dict__

这里cls是班级

class Test:
    temp_1=10
    temp_2=20

    def __init__(self):
        self.test_1=10
        self.test_2=20

    @classmethod
    def c_test(cls):
        pass

    def t_method(self):
        pass


print Test.__dict__
print Test().__dict__

<强>输出

{'c_test': <classmethod object at 0x7fede8f35a60>, '__module__': '__main__', 't_method': <function t_method at 0x7fede8f336e0>, 'temp_1': 10, '__doc__': None, '__init__': <function __init__ at 0x7fede8f335f0>, 'temp_2': 20}

{'test_2': 20, 'test_1': 10}

详细信息class special attribute

答案 6 :(得分:0)

我想添加一个答案,但上述答案均未提及(不是说它们不好!)->“ 大小 < / em>”。

前言:在Python中,无论好坏,都可以在RUN TIME中将“新”(附加)INSTANCE类成员“创建”(添加)到特定对象实例,这意味着,例如,如果某个特定类具有两个实例成员,则可以在创建对象实例之后添加第三个成员,并且仅将其添加到该特定类的实例中(即,该类的“蓝图”将不变)。参见下面的示例代码中的#1)。

现在,如果此“新” INSTANCE成员的名称恰好与“全局”类成员的名称相同->则对于此特定对象实例,将添加一个具有相同名称的附加实例成员从已经拥有的类成员开始的名称(并与该类的所有其他实例共享)。参见下面的示例代码中的#2)。

->因此,当您出于“设置目的”而通过SPECIFIC实例对象而不是通过类名访问“全局”(类)成员时,即:my_class_obj2.class_data_member = some_value和NOT MyClass.class_data_member根据下面的示例代码,那么将发生的是,为此特定实例创建了一个额外的实例成员-因此其SIZE也已更改(如果运行示例代码,您将看到两个不同的实例具有两个不同的大小我对Python的大小“分配”不满意,因此我期望看到my_class_obj2的大小大于my_class_obj->,但是不是,我想可以在this Q&A中看到有关Python对象大小的更多信息,我从asizeof程序包的pympler函数中获得了使用示例)。

有关更完整的示例,请参见以下代码:

import sys
from pympler import asizeof

class MyClass:

    class_data_member = 15

    def __init__(self, num):
        self.num = num
        self.string = ""

    def define_some_class_member(self):
        pass

    def print_me(self):
        self.x = 17
        print("MyClass::print_me - num is:" + str(self.num) + ", string is:" + self.string)
        print("MyClass::print_me - self.x is:" + str(self.x))

    def foo(self):
        print("Hi there form " + __class__.__name__ + "::foo")


def classes_and_object_example():
    func_name = "classes_and_object_example - "
    print(func_name + "creating MyClass object")
    my_class_obj = MyClass(12)
    my_class_obj.print_me()

    print(func_name + "creating another MyClass object")
    my_class_obj2 = MyClass(17)
    my_class_obj2.print_me()

    # 1)
    my_class_obj.some_new_instance_member = 90
    print(func_name + "the new additional instance member is:" + str(my_class_obj.some_new_instance_member))
    # Pay attention that the "new instance member" was added to my_class_obj and NOT to my_class_obj2 so the below statement is illegal
    # print("the new additional instance member is:" + str(my_class_obj2.some_new_instance_member))

    print(func_name + "the \"global\" data member seen by my_class_obj.class_data_member"
      + " is:" + str(my_class_obj.class_data_member) + " and the \"global\" data member seen by my_class_obj2.class_data_member"
      + " is (also):" + str(my_class_obj2.class_data_member))

    # 2)
    my_class_obj2.class_data_member = 99
    print(func_name + "the \"global\" data member seen by my_class_obj2.class_data_member"
      + " after intentionally modifying it is:" + str(my_class_obj2.class_data_member) + ", while on the other hand it is STILL seen by my_class_obj.class_data_member"
      + " as:" + str(MyClass.class_data_member))

    MyClass.class_data_member = 67
    print(func_name + "after setting the \"global (static)\" data member that is shared among all MyClass instances"
      + " using the assignemt:MyClass.class_data_member = 67, its value is:" + str(MyClass.class_data_member) + ", while on the other hand my_class_obj2 STILL has its \"own\" INSTANCE member with the same name and value of:" 
      + str(my_class_obj2.class_data_member))

    size_of_my_class_orig_object = asizeof.asizeof(my_class_obj)
    print(func_name + "the size of a MyClass object instance is:" + str(size_of_my_class_orig_object))

    size_of_my_class_modified_object = asizeof.asizeof(my_class_obj2)
    print(func_name + "the size of a MyClass object instance after \"adding\" to it an additional instance member is:" + str(size_of_my_class_modified_object))

# run the sample code for illustration
classes_and_object_example()