请帮助我理解python类和实例变量

时间:2014-03-06 04:00:19

标签: python oop

我是Python的新手,我在理解Python如何解释类​​和实例变量方面遇到了一些麻烦。我的背景是C#,所以我对OOP(来自C#思维模式)有相当好的理解,但是我对python有点困惑。我猜这是因为我在思考错误的思维方式。

以下面的课程为例:

class User():
    """The default user implementation"""

    # define the variables
    id = None
    first_name = None
    last_name = None
    email = None
    password = None
    created = None
    deleted = False

    def __init__(self):
        """Creates a new instance of the User object."""
        self.is_admin = False

从我读过的文档中,所有id,first_name,last_name等都是类属性,它们在实例之间共享。这些将是C#思维模式中的 static 。然后 is_admin 实例属性,它仅限于对象的特定实例。这些将是C#中的 fields properties

然而,当我做这样的事情时,我的困惑就出现了:


    new_user = User()
    new_user.id = "blah"
    new_user.last_name = "lasty"

    new_user1 = User()
    new_user1.id = "some_id"
    new_user1.last_name = "firsty"


这将值设置为:


    new_user.id = "blah"
    new_user.last_name = "lasty"

    new_user1.id = "some_id"
    new_user1.last_name = "firsty"

鉴于 id last_name 被定义为类属性,我会假设对new_user1对象的调用会覆盖“blah” “和”lasty“值,但每个实例都保留了为其定义的值。因此,我的困惑。

如果这是正常的,有人可以详细说明为什么会这样吗?此外,在这种情况下,如何定义静态变量?

干杯, 贾斯汀

4 个答案:

答案 0 :(得分:3)

Python在实例上查找属性,然后查找实例的类,然后查找任何基类及其父类。因此idlast_name是隐藏类同名属性的实例属性。如果您访问未在实例上设置的属性(例如first_name),那么您将获得该类的属性,因为它未在实例上找到。

答案 1 :(得分:1)

最简单的想法,它可以工作并显示类变量和实例变量之间的区别:

>>> import datetime
>>> class Example:
...     my_name = 'example'
...     def __init__(self):
...         self.now = datetime.datetime.now()
...
>>> e = Example()
>>> e.my_name
'example'
>>> e.now
datetime.datetime(2015, 6, 1, 2, 2, 58, 211399)
>>> d = Example()
>>> d.my_name
'example'
>>> d.now
datetime.datetime(2015, 6, 1, 2, 4, 21, 165731)
>>>

my_name是类变量 - 它是类的属性,类的任何实例都可以访问该属性。现在是实例变量 - 只有Example类型的对象可以访问datetime,并且每个对象的datetime都不同。

为了让点回家,让我们尝试从类本身访问每个变量:

>>> Example.now
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'Example' has no attribute 'now'
>>> Example.my_name
'example'
>>>

对象可以修改该实例的类变量

>>> d.my_name = "George"
>>> d.may_name
'George'
>>> Example.my_name
'example'

但不适合全班。

Static是一个在C和C ++中引用静态链接的关键字,在许多现代OO语言中用于表示由类的所有对象共享但是不是类的一段代码方法或变量本身。 Python作为方法的staticmethod装饰器。但是没有静态变量,只有类变量。

我希望澄清事情。

答案 2 :(得分:0)

在C和Java使用该术语的意义上,类变量并不是真正的“静态”。它们很容易被覆盖。最好将它们视为与类对象关联的单一副本默认值。

考虑(在Python 3中):

class Foo(object):
    cv='cv'
    def __setattr__(self, name, value):
        if name in self.__class__.__dict__:
            print('Overloading class var "{}" with instance attribute "{}"'.format(self.__class__.__dict__[name], value))
            super(self.__class__, self).__setattr__(name, value)

    def __getattribute__(*args):
        self, name, *the_rest=args
        if name in Foo.__dict__:
            print('there is a class variable called "{}" with value of: "{}"'.format(name, Foo.__dict__[name]))      
        return object.__getattribute__(*args)  

现在实例化类Foo的副本并测试类变量和实例变量:

>>> foo=Foo()
>>> foo.cv
there is a class variable called "cv" with value of: "cv"
'cv'
>>> foo.cv='IV'
Overloading class var "cv" with instance attribute "IV"
>>> foo.cv
there is a class variable called "cv" with value of: "cv"
'IV'
>>> Foo.cv='NEW CV'
>>> bar=Foo()
>>> bar.cv
there is a class variable called "cv" with value of: "NEW CV"
'NEW CV'

答案 3 :(得分:0)

Python没有常量或静态变量。对于类属性,它是相同的。该类在导入时加载了值。如果用户更改了导入值。

class MyClass(object):
    id = 1

def main():

    myclass = MyClass()
    print("class1", myclass.id)
    print()

    myclass2 = MyClass()
    myclass2.id = 2
    print("class1", myclass.id)
    print("class2", myclass2.id)
    print()

    MyClass.id = 3
    myclass3 = MyClass()
    print("class1", myclass.id)
    print("class2", myclass2.id)
    print("class3", myclass3.id)
    print()

    myclass4 = MyClass()
    print("class1", myclass.id)
    print("class2", myclass2.id)
    print("class3", myclass3.id)
    print("class4", myclass4.id)
    print()

    myclass5 = MyClass()
    myclass5.id = 5 
    print("class1", myclass.id)
    print("class2", myclass2.id)
    print("class3", myclass3.id)
    print("class4", myclass4.id)
    print("class5", myclass5.id)
# end main

if __name__ == '__main__':
    main()

结果很有趣。

class1 1

class1 1
class2 2

class1 3
class2 2
class3 3

class1 3
class2 2
class3 3
class4 3

class1 3
class2 2
class3 3
class4 3
class5 5

如果您尚未设置实例ID,则默认为类ID。

MyClass.id = 1

如果实例未设置值,则会更改实例的值。