Python学习小记(5)---Magic Method
具体见The Python Language Reference
与Attribute相关的有
__get__
__set__
__getattribute__
__getattr__
__setattr__
__getitem__
__setitem__
Reference描述如下
3.3.2. Customizing attribute access
The following methods can be defined to customize the meaning of attribute access (use of, assignment to, or deletion of
x.name) for class instances.
object.__getattr__(self, name)Called when the default attribute access fails with an
AttributeError(either__getattribute__()raises anAttributeErrorbecause name is not an instance attribute or an attribute in the class tree forself; or__get__()of a name property raisesAttributeError). This method should either return the (computed) attribute value or raise anAttributeErrorexception.Note that if the attribute is found through the normal mechanism,
__getattr__()is not called. (This is an intentional asymmetry between__getattr__()and__setattr__().) This is done both for efficiency reasons and because otherwise__getattr__()would have no way to access other attributes of the instance. Note that at least for instance variables, you can fake total control by not inserting any values in the instance attribute dictionary (but instead inserting them in another object). See the__getattribute__()method below for a way to actually get total control over attribute access.
object.__getattribute__(self, name)Called unconditionally to implement attribute accesses for instances of the class. If the class also defines
__getattr__(), the latter will not be called unless__getattribute__()either calls it explicitly or raises anAttributeError. This method should return the (computed) attribute value or raise anAttributeErrorexception. In order to avoid infinite recursion in this method, its implementation should always call the base class method with the same name to access any attributes it needs, for example,object.__getattribute__(self, name).Note
This method may still be bypassed when looking up special methods as the result of implicit invocation via language syntax or built-in functions. See Special method lookup.
object.__setattr__(self, name, value)Called when an attribute assignment is attempted. This is called instead of the normal mechanism (i.e. store the value in the instance dictionary). name is the attribute name, value is the value to be assigned to it.
If
__setattr__()wants to assign to an instance attribute, it should call the base class method with the same name, for example,object.__setattr__(self, name, value).
object.__delattr__(self, name)Like
__setattr__()but for attribute deletion instead of assignment. This should only be implemented ifdelobj.nameis meaningful for the object.
object.__dir__(self)Called when
dir()is called on the object. A sequence must be returned.dir()converts the returned sequence to a list and sorts it.3.3.2.1. Customizing module attribute access
Special names
__getattr__and__dir__can be also used to customize access to module attributes. The__getattr__function at the module level should accept one argument which is the name of an attribute and return the computed value or raise anAttributeError. If an attribute is not found on a module object through the normal lookup, i.e.object.__getattribute__(), then__getattr__is searched in the module__dict__before raising anAttributeError. If found, it is called with the attribute name and the result is returned.The
__dir__function should accept no arguments, and return a list of strings that represents the names accessible on module. If present, this function overrides the standarddir()search on a module.For a more fine grained customization of the module behavior (setting attributes, properties, etc.), one can set the
__class__attribute of a module object to a subclass oftypes.ModuleType. For example:import sys
from types import ModuleType class VerboseModule(ModuleType):
def __repr__(self):
return f'Verbose {self.__name__}' def __setattr__(self, attr, value):
print(f'Setting {attr}...')
super().__setattr__(attr, value) sys.modules[__name__].__class__ = VerboseModuleNote
Defining module
__getattr__and setting module__class__only affect lookups made using the attribute access syntax – directly accessing the module globals (whether by code within the module, or via a reference to the module’s globals dictionary) is unaffected.Changed in version 3.5:
__class__module attribute is now writable.New in version 3.7:
__getattr__and__dir__module attributes.See also
- PEP 562 - Module __getattr__ and __dir__
- Describes the
__getattr__and__dir__functions on modules.3.3.2.2. Implementing Descriptors
The following methods only apply when an instance of the class containing the method (a so-called descriptorclass) appears in an owner class (the descriptor must be in either the owner’s class dictionary or in the class dictionary for one of its parents). In the examples below, “the attribute” refers to the attribute whose name is the key of the property in the owner class’
__dict__.
object.__get__(self, instance, owner)Called to get the attribute of the owner class (class attribute access) or of an instance of that class (instance attribute access). owner is always the owner class, while instance is the instance that the attribute was accessed through, or
Nonewhen the attribute is accessed through the owner. This method should return the (computed) attribute value or raise anAttributeErrorexception.
object.__set__(self, instance, value)Called to set the attribute on an instance instance of the owner class to a new value, value.
object.__delete__(self, instance)Called to delete the attribute on an instance instance of the owner class.
object.__set_name__(self, owner, name)Called at the time the owning class owner is created. The descriptor has been assigned to name.
New in version 3.6.
The attribute
__objclass__is interpreted by theinspectmodule as specifying the class where this object was defined (setting this appropriately can assist in runtime introspection of dynamic class attributes). For callables, it may indicate that an instance of the given type (or a subclass) is expected or required as the first positional argument (for example, CPython sets this attribute for unbound methods that are implemented in C).3.3.2.3. Invoking Descriptors
In general, a descriptor is an object attribute with “binding behavior”, one whose attribute access has been overridden by methods in the descriptor protocol:
__get__(),__set__(), and__delete__(). If any of those methods are defined for an object, it is said to be a descriptor.The default behavior for attribute access is to get, set, or delete the attribute from an object’s dictionary. For instance,
a.xhas a lookup chain starting witha.__dict__['x'], thentype(a).__dict__['x'], and continuing through the base classes oftype(a)excluding metaclasses.However, if the looked-up value is an object defining one of the descriptor methods, then Python may override the default behavior and invoke the descriptor method instead. Where this occurs in the precedence chain depends on which descriptor methods were defined and how they were called.
The starting point for descriptor invocation is a binding,
a.x. How the arguments are assembled depends ona:
- Direct Call
- The simplest and least common call is when user code directly invokes a descriptor method:
x.__get__(a).- Instance Binding
- If binding to an object instance,
a.xis transformed into the call:type(a).__dict__['x'].__get__(a,type(a)).- Class Binding
- If binding to a class,
A.xis transformed into the call:A.__dict__['x'].__get__(None, A).- Super Binding
- If
ais an instance ofsuper, then the bindingsuper(B, obj).m()searchesobj.__class__.__mro__for the base classAimmediately precedingBand then invokes the descriptor with the call:A.__dict__['m'].__get__(obj, obj.__class__).For instance bindings, the precedence of descriptor invocation depends on the which descriptor methods are defined. A descriptor can define any combination of
__get__(),__set__()and__delete__(). If it does not define__get__(), then accessing the attribute will return the descriptor object itself unless there is a value in the object’s instance dictionary. If the descriptor defines__set__()and/or__delete__(), it is a data descriptor; if it defines neither, it is a non-data descriptor. Normally, data descriptors define both__get__()and__set__(), while non-data descriptors have just the__get__()method. Data descriptors with__set__()and__get__()defined always override a redefinition in an instance dictionary. In contrast, non-data descriptors can be overridden by instances.Python methods (including
staticmethod()andclassmethod()) are implemented as non-data descriptors. Accordingly, instances can redefine and override methods. This allows individual instances to acquire behaviors that differ from other instances of the same class.The
property()function is implemented as a data descriptor. Accordingly, instances cannot override the behavior of a property.3.3.2.4. __slots__
__slots__ allow us to explicitly declare data members (like properties) and deny the creation of __dict__ and __weakref__ (unless explicitly declared in __slots__ or available in a parent.)
The space saved over using __dict__ can be significant.
object.__slots__This class variable can be assigned a string, iterable, or sequence of strings with variable names used by instances. __slots__ reserves space for the declared variables and prevents the automatic creation of __dict__ and __weakref__ for each instance.
3.3.2.4.1. Notes on using __slots__
- When inheriting from a class without __slots__, the __dict__ and __weakref__ attribute of the instances will always be accessible.
- Without a __dict__ variable, instances cannot be assigned new variables not listed in the __slots__definition. Attempts to assign to an unlisted variable name raises
AttributeError. If dynamic assignment of new variables is desired, then add'__dict__'to the sequence of strings in the __slots__ declaration.- Without a __weakref__ variable for each instance, classes defining __slots__ do not support weak references to its instances. If weak reference support is needed, then add
'__weakref__'to the sequence of strings in the __slots__ declaration.- __slots__ are implemented at the class level by creating descriptors (Implementing Descriptors) for each variable name. As a result, class attributes cannot be used to set default values for instance variables defined by __slots__; otherwise, the class attribute would overwrite the descriptor assignment.
- The action of a __slots__ declaration is not limited to the class where it is defined. __slots__ declared in parents are available in child classes. However, child subclasses will get a __dict__ and __weakref__unless they also define __slots__ (which should only contain names of any additional slots).
- If a class defines a slot also defined in a base class, the instance variable defined by the base class slot is inaccessible (except by retrieving its descriptor directly from the base class). This renders the meaning of the program undefined. In the future, a check may be added to prevent this.
- Nonempty __slots__ does not work for classes derived from “variable-length” built-in types such as
int,bytesandtuple.- Any non-string iterable may be assigned to __slots__. Mappings may also be used; however, in the future, special meaning may be assigned to the values corresponding to each key.
- __class__ assignment works only if both classes have the same __slots__.
- Multiple inheritance with multiple slotted parent classes can be used, but only one parent is allowed to have attributes created by slots (the other bases must have empty slot layouts) - violations raise
TypeError.
Python学习小记(5)---Magic Method的更多相关文章
- Python学习小记(4)---class
1.名称修改机制 大概是会对形如 __parm 的成员修改为 _classname__spam 9.6. Private Variables “Private” instance variables ...
- python学习小记
python HTTP请求示例: # coding=utf-8 # more materials: http://docs.python-requests.org/zh_CN/latest/user/ ...
- Python学习小记(3)---scope&namespace
首先,函数里面是可以访问外部变量的 #scope.py def scope_test(): spam = 'scope_test spam' def inner_scope_test(): spam ...
- Python学习小记(1)---import小记
在这种目录结构下,import fibo会实际导入fibo文件夹这个module λ tree /F 卷 Programs 的文件夹 PATH 列表 卷序列号为 BC56-3256 D:. │ fib ...
- Python学习小记(2)---[list, iterator, and, or, zip, dict.keys]
1.List行为 可以用 alist[:] 相当于 alist.copy() ,可以创建一个 alist 的 shallo copy,但是直接对 alist[:] 操作却会直接操作 alist 对象 ...
- python 学习小记之冒泡排序
lst =[11,22,44,2,1,5,7,8,3] for i in range(len(lst)): i = 0 while i < len(lst)-1: ...
- Python魔术方法-Magic Method
介绍 在Python中,所有以"__"双下划线包起来的方法,都统称为"Magic Method",例如类的初始化方法 __init__ ,Python中所有的魔 ...
- Python:Python学习总结
Python:Python学习总结 背景 PHP的$和->让人输入的手疼(PHP确实非常简洁和强大,适合WEB编程),Ruby的#.@.@@也好不到哪里(OO人员最该学习的一门语言). Pyth ...
- Magic Method
Python 的 Magic Method 在 Python 中,所有以 "__" 双下划线包起来的方法,都统称为"魔术方法".比如我们接触最多的 __init ...
随机推荐
- 搞定SpringBoot多数据源(3):参数化变更源
目录 1. 引言 2. 参数化变更源说明 2.1 解决思路 2.2 流程说明 3. 实现参数化变更源 3.1 改造动态数据源 3.1.1 动态数据源添加功能 3.1.2 动态数据源配置 3.2 添加数 ...
- CF6B President's Office 题解
看到大致思路一致的题解,决定发一篇运用STL不用dfs的题解 好久不发题解,心里不爽 思路: 1.输入的同时找到总统桌子的位置,用vector<pair <int,int> ...
- python3中的RE(正则表达式)
记录大佬的 整理 原文来自:https://blog.csdn.net/weixin_40136018/article/details/81183504 1.引入正则模块(Regular Expres ...
- Java基础系列1:Java基本类型与封装类型
Java基础系列1:Java基本类型与封装类型 当初学习计算机的时候,教科书中对程序的定义是:程序=数据结构+算法,Java基础系列第一篇就聊聊Java中的数据类型. 本篇聊Java数据类型主要包括两 ...
- 简单实现Android手机“全局可调试”(ro.debuggable = 1)的方法【锤子坚果3】
在Android真机上调试程序有一个前提,就是这个apk包必须有 debuggable=true 的属性才行.而除了自己开发的apk能够控制打包属性之外,其他的程序发行之后显然不会设这个值为 true ...
- C语言 获取系统时间与睡眠时间函数
摘要: 以ms为单位,获取系统时间.睡眠或延迟时间函数的使用方法. #include<stdio.h> #include <time.h> #include <sys/t ...
- PBR原理
漫反射和镜面反射 漫反射和镜面反射(或反射)光是描述光和材料之间两种主要相互作用类型的两个术语.镜面光是指从表面反弹的光.在光滑的表面上,这种光将反射所有相同的方向,并且表面将呈现镜像.漫射光是被吸收 ...
- 科普文,搭建python开发环境
Python简介!首先,是一门面向对象的程序设计语言,先说3个优点!1.有条理,简单,易学,易用.2.强大!可以把其他编程语言制作的模块利用起来.3.拥有丰富的库.Python作为高级编程语言,拥有的 ...
- linux-centos7 gcc 简单使用
在虚拟机VirtualBox 安装CentOS6.3后,默认是没有安装gcc. 进入root,命令 yum -y install gcc gcc-c++ autoconf ...
- Python里的装饰器
装饰器 装饰器是干什么用的? 装饰器可以在不修改某个函数的情况下,给函数添加功能. 形象点来说,从前有一个王叔叔,他一个人住在家里,每天打扫家,看书.于是定义如下一个函数: def uncle_wan ...