You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python类变量、实例属性访问机制及命名空间相关技术疑问

Python Class vs. Instance Attribute Lookup: Deep Dive

Great question—let’s break this down clearly, starting with your code (fixed for proper indentation) and then diving into Python’s core attribute resolution rules, plus the connection to nested function scopes.

First, Let’s Fix & Run Your Code

Here’s your code formatted correctly, with minor tweaks to avoid overwriting instances:

class Dog(object):
    population = 0  # Class variable: shared across all Dog instances
    
    def __init__(self, name):
        self.name = name
        self.num_legs = 4  # Instance attribute: created for every new Dog
        Dog.population += 1  # Increment class-level population count
    
    def get_num_legs(self):
        return self.num_legs

# First batch of instances
dog1 = Dog('dog1')
dog2 = Dog('dog2')
print(Dog.population)  # Output: 2
print(dog1.population)  # Output: 2 (not 4—you might have typoed your initial note!)

# Modify dog1's instance-specific leg count
dog1.num_legs = 2
print("Dog1 has {} legs".format(dog1.get_num_legs()))  # Output: 2
print("Dog2 has {} legs".format(dog2.get_num_legs()))  # Output: 4

# Update the Dog class's num_legs variable
Dog.num_legs = 10

# Create new instances (renamed to avoid overwriting earlier ones)
dog3 = Dog('dog3')
dog4 = Dog('dog4')
print("Dog3 has {} legs".format(dog3.get_num_legs()))  # Output: 4 (your core question!)
print("Dog4 has {} legs".format(dog4.get_num_legs()))  # Output: 4

The Core Mechanism: Instance Attribute Resolution

Python follows a strict, scope-first rule for looking up attributes on instances—this is formally tied to the instance and class __dict__ dictionaries:

  1. Check the instance’s own __dict__ first: Every object in Python has a private __dict__ that stores attributes set directly on it (like self.name or self.num_legs in your __init__ method). If the attribute exists here, Python returns it immediately—it never checks the class or parent classes for this attribute.
  2. Only if not found, check the class’s __dict__: If the instance doesn’t have the attribute in its own dictionary, Python looks up the class hierarchy (starting with the instance’s class, then parent classes via MRO) to find a class-level variable.

In your code, the __init__ method explicitly sets self.num_legs = 4 for every new Dog instance. That means every Dog will have num_legs in its own __dict__—so when you create dog3 after updating Dog.num_legs =10, Python still grabs the instance’s num_legs=4 and never looks at the class’s value.

What If We Removed self.num_legs =4?

If you deleted that line from __init__:

  • New instances wouldn’t have num_legs in their __dict__
  • Calling dog.get_num_legs() would return the class’s num_legs value (10, after your update)
  • Any existing instances would also start returning 10, unless you’d already set an instance-specific num_legs for them.

Why dog1.population Returns 2

For the population variable:

  • You never set self.population in __init__, so no Dog instance has population in its __dict__
  • When you call dog1.population, Python checks the instance’s dictionary (no match), then falls back to the class’s __dict__ where population=2 lives.
  • If you later set dog1.population =5, that would add population to dog1’s __dict__, and dog1.population would return 5 while Dog.population and dog2.population stayed at 2.

Is This Similar to Nested Function Scopes?

Absolutely! This follows the same "closest scope first" logic as Python’s LEGB rule for nested functions:

  • For functions: Python checks Local scope (current function variables), then Enclosing function scopes, then Global scope, then Built-in names.
  • For instance attributes: Python checks the Instance’s local scope (__dict__), then the Class’s scope (__dict__), then parent Class scopes (via MRO).

In both cases, a name in a closer scope shadows the same name in a farther scope. Python stops searching as soon as it finds a match—this is the core parallel between the two systems.

Quick Recap of Your Outputs

To tie everything together:

  • print(Dog.population) → 2: Two instances created, so the class-level counter was incremented twice.
  • print(dog1.population) → 2: dog1 has no instance-specific population, so it uses the class variable.
  • dog1.get_num_legs() → 2: dog1’s __dict__ now has num_legs=2, overriding any class-level value.
  • dog2.get_num_legs() →4: dog2’s __dict__ still has the original num_legs=4 set in __init__.
  • New instances after Dog.num_legs=10 still return 4: Their __init__ sets self.num_legs=4, so Python never checks the class’s updated value.

内容的提问来源于stack exchange,提问作者Prashin Jeevaganth

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:26:48