Dynamically defining instance fields in Python classes

后端 未结 3 1480
闹比i
闹比i 2021-02-05 10:48

I am new to Python having come from mainly Java programming.

I am currently pondering over how classes in Python are instantiated.

I understand that __ini

3条回答
  •  南笙
    南笙 (楼主)
    2021-02-05 11:03

    This answer pertains to new-style Python classes, which subclass object. New-style classes were added in 2.2, and they're the only kind of class available in PY3.

    >>> print object.__doc__
    The most base type
    

    The class itself is an instance of a metaclass, which is usually type:

    >>> print type.__doc__
    type(object) -> the object's type
    type(name, bases, dict) -> a new type
    

    Per the above docstring, you can instantiate the metaclass directly to create a class:

    >>> Test = type('Test', (object,), {'__doc__': 'Test class'})
    >>> isinstance(Test, type)
    True
    >>> issubclass(Test, object)
    True
    >>> print Test.__doc__
    Test class
    

    Calling a class is handled by the metaclass __call__ method, e.g. type.__call__. This in turn calls the class __new__ constructor (typically inherited) with the call arguments in order to create an instance. Then it calls __init__, which may set instance attributes.

    Most objects have a __dict__ that allows setting and deleting attributes dynamically, such as self.value = 10 or del self.value. It's generally bad form to modify an object's __dict__ directly, and actually disallowed for a class (i.e. a class dict is wrapped to disable direct modification). If you need to access an attribute dynamically, use the built-in functions getattr, setattr, and delattr.

    The data model defines the following special methods for customizing attribute access: __getattribute__, __getattr__, __setattr__, and __delattr__. A class can also define the descriptor protocol methods __get__, __set__, and __delete__ to determine how its instances behave as attributes. Refer to the descriptor guide.

    When looking up an attribute, object.__getattribute__ first searches the object's class and base classes using the C3 method resolution order of the class:

    >>> Test.__mro__
    (, )
    

    Note that a data descriptor defined in the class (e.g. a property or a member for a slot) takes precedence over the instance dict. On the other hand, a non-data descriptor (e.g. a function) or a non-descriptor class attribute can be shadowed by an instance attribute. For example:

    >>> Test.x = property(lambda self: 10)
    >>> inspect.isdatadescriptor(Test.x)
    True
    >>> t = Test()
    >>> t.x
    10
    >>> t.__dict__['x'] = 0
    >>> t.__dict__
    {'x': 0}
    >>> t.x
    10
    
    >>> Test.y = 'class string'
    >>> inspect.isdatadescriptor(Test.y)
    False
    >>> t.y = 'instance string'
    >>> t.y
    'instance string'
    

    Use super to proxy attribute access for the next class in the method resolution order. For example:

    >>> class Test2(Test):
    ...     x = property(lambda self: 20)
    ... 
    >>> t2 = Test2()
    >>> t2.x
    20
    >>> super(Test2, t2).x
    10
    

提交回复
热议问题