繁体   English   中英

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

[英]Please help my understanding of python class vs instance variables

我是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#思维模式中是静态的 然后, is_admin是一个实例属性 ,仅限于该对象的特定实例。 这些将是C#中的字段属性

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

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"

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

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

干杯,贾斯汀

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

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

>>> 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是一个类变量 - 它是类的一个属性,该类的任何实例都可以访问该属性。 now是一个实例变量 - 只有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装饰器。 但是没有静态变量,只有类变量。

我希望澄清事情。

在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'

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

如果实例未设置值,这将更改实例的值。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM