Python中类的特殊行为

2024-09-28 03:23:37 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在学习Python,但是没有面向对象的经验。我在IDLE(Python 3.3)中输入了以下几行,对象的行为让我很困惑:

>>> class IBAN:
    ISOcode = '  '
    checkDigits = '00'
    class CCC:
        bankCode = '0000'
        branchCode = '0000'
        checkBank = '0'
        checkAccount = '0'
        account = '0000000000'


>>> >>> numberOne = IBAN()
>>> numberOne.CCC
<class '__main__.IBAN.CCC'>
>>> numberOne.CCC.bankCode
'0000'
>>> numberOne.ISOcode = 'ES'
>>> IBAN.ISOcode
'  '
>>> numberOne.ISOcode
'ES'
>>> IBAN.ISOcode = 'FR'
>>> numberOne.ISOcode
'ES'
>>> IBAN.ISOcode = 'FR'
>>> IBAN.ISOcode
'FR'
>>> numberTwo = IBAN()
>>> numberTwo.ISOcode
'FR'
>>> IBAN.ISOcode = 'IT'
>>> IBAN.ISOcode
'IT'
>>> numberOne.ISOcode
'ES'
>>> numberTwo.ISOcode
'IT'
>>> IBAN.ISOcode is numberTwo.ISOcode
True
>>> 

为什么对象numberTwo的ISOcode属性与对象IBAN的ISOcode相同,但与对象numberOne的ISOcode不同?你知道吗

我以为会这样:

>>> numberOne.ISOcode
'ES'
>>> numberTwo.ISOcode
'FR'

然而,这与我的结果不符。你知道吗

我发现a similar question on StackOverflow,这让我觉得结果应该是:

>>> numberOne.ISOcode
'IT'
>>> numberTwo.ISOcode
'IT'

但这和我的结果也不符。你知道吗

有人能解释或链接到解释Python中类行为的资源吗?我试图学习Python教程和Guido van Rossum的“Unifying types and classes in Python 2.2”,但我无法理解他们在说什么。你知道吗

谢谢你!你知道吗


Tags: 对象esibanit经验fr面向对象class
3条回答

类与类的实例是不同的对象。类有属性,实例有属性。每次尝试访问实例的属性时,如果实例没有该属性,则会在类中查找该属性。如果在实例上设置属性,它总是在实例上设置的,即使这意味着它在类上隐藏了一个同名的属性。你知道吗

在IBAN类中,您在上定义了一个属性ISOcode。执行numberOne.ISOcode = 'ES'操作时,在实例上设置一个新的属性。您已经将numberOne.ISOcode的值与IBAN.ISOcode的值解耦。但是您创建的任何新实例(如numberTwo)仍然没有自己的实例等位码。然后设置IBAN.ISOcode时,您正在更改属性。你知道吗

您可以将class属性视为“default”。在执行obj.attr操作时,如果obj没有自己的属性attr,则它将采用类当时的值。如果更改类的属性值,则更改默认值;如果稍后尝试访问没有自己属性的实例上的属性,则它们将看到您创建的新默认值。你知道吗

下面是一个更精简的示例:

>>> class Foo(object):
...     attr = "Something"
>>> one = Foo()
>>> two = Foo()

首先,所有的值都相同,因为我没有指定任何特定于实例的值,所以onetwo都从类中获取它们的值。你知道吗

>>> Foo.attr
'Something'
>>> one.attr
'Something'
>>> two.attr
'Something'

现在我只为one设置一个新值。这不会影响Foo,而且two仍然从Foo获取其值,因此two也不会受到影响。你知道吗

>>> one.attr = "This is only for #1"
>>> Foo.attr
'Something'
>>> one.attr
'This is only for #1'
>>> two.attr
'Something'

现在我将在类Foo上设置一个新值。这不会影响one,因为one有它自己的值。但是由于two没有它自己的值,它从类中获取它的值,并且因为我更改了类的值,所以这会更改我从two中获取的值:

>>> Foo.attr = "This is the class value"
>>> Foo.attr
'This is the class value'
>>> one.attr
'This is only for #1'
>>> two.attr
'This is the class value'

要记住的是,每次属性查找都是在执行时动态计算的。创建实例不会自动将类属性从类复制到实例。当您访问实例上的属性时,实例会对自己说“我有自己的属性吗?如果是,则返回该值。如果不是,则返回类的值。”每当您尝试访问一个属性时,它都会问自己这个问题;实例在任何时候都不会与类“独立”。你知道吗

ISOcode在您的示例中定义的是类属性,而不是实例属性

应该在类的__init__方法中设置self.ISOcode,使其对每个实例都是唯一的。否则属性将存储在类中。你知道吗

class IBAN:
    def __init__(self):
        self.ISOcode = '  '

您正在通过设置实例属性而不是类属性来进行一些混乱的名称阴影。你知道吗

>>> class A():
    stuff = ''

>>> a = A()
>>> a.stuff
''
>>> a.stuff = 'thing' # sets an instance attribute
>>> a.stuff 
'thing'
>>> a.__class__.stuff
''
>>> a.__class__.stuff = 'blah'
>>> a.stuff # instance attributes are checked FIRST
'thing'
>>> aa = A()
>>> aa.stuff
'blah'

基本上,不要这样做。如果希望属性成为实例属性,请在__init__中设置它们。你知道吗

相关问题 更多 >

    热门问题