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 anAttributeError
because 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 anAttributeError
exception.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 anAttributeError
exception. 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.name
is 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__ = VerboseModule
Note
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
None
when the attribute is accessed through the owner. This method should return the (computed) attribute value or raise anAttributeError
exception.
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 theinspect
module 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.x
has 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.x
is transformed into the call:type(a).__dict__['x'].__get__(a,type(a))
.- Class Binding
- If binding to a class,
A.x
is transformed into the call:A.__dict__['x'].__get__(None, A)
.- Super Binding
- If
a
is an instance ofsuper
, then the bindingsuper(B, obj).m()
searchesobj.__class__.__mro__
for the base classA
immediately precedingB
and 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
,bytes
andtuple
.- 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 ...
随机推荐
- 关于爬虫的日常复习(8)—— 实战:request+正则爬取猫眼榜单top100
- [洛谷P3621] [APIO2007] 风铃
Description 你准备给弟弟 Ike 买一件礼物,但是,Ike 挑选礼物的方式很特别:他只喜欢那些能被他排成有序形状的东西. 你准备给 Ike 买一个风铃.风铃是一种多层的装饰品,一般挂在天花 ...
- 安装mysql遇到的问题
想在自己的PC上安装mysql服务器,首先在官网下载mysql的安装文件. MySQL安装文件分两种 .msi和.zip ,.msi需要安装,.zip文件需要配置环境变量. 我首先下载的是不需要安装的 ...
- 玩转Django2.0---Django笔记建站基础十一(二)((音乐网站开发))
11.5 歌曲排行榜 歌曲排行榜是通过首页的导航链接进入的,按照歌曲的播放次数进行降序显示.从排行榜页面的设计图可以看到,网页实现三个功能:网页顶部搜索.歌曲分类筛选和歌曲信息列表,其说明如下: 1. ...
- cmd命令行窗口和文件目录资源管理器快速切换
本文主要描述如何在指定目录下快速打开当前路径的命令行窗口和在命令行中快速打开指定目录的资源管理器两种快捷方法. 1.在指定目录下快速打开当前路径的命令行窗口 2.在命令行中快速打开当前目录的资源管理器 ...
- 自用代码css获取任意网址的/favicon.ico的方法教程
尝试过使用网友说的API接口获取 找到的都是失效了 暂时就使用这种办法获取 如果有好的方法望评论告知 谢谢 <img :ng-src="'http://'+list.url+'/fav ...
- MySql配置环境变量
完成后安装好MySQL,为MySQL配置环境变量. 0)在我的电脑上点击右键选择属性-->高级系统设置-->环境变量1)新建MYSQL_HOME变量,并配置:D:\Develop\mysq ...
- GitHub Pages 与 Gitee Pages 上的 Jekyll
GitHub 与 Gitee 提供的 Pages 服务中,均内嵌了 Jekyll 支持(Gitee 还提供了 Hugo 与 Hexo 支持).所谓「支持」,即指这些生成工具挂在云端:你只需要提供原始代 ...
- kettle安装部署基本操作及实操文档
一.kettle是什么? Kettle,简称ETL(Extract-Transform-Load的缩写,即数据抽取.转换.装载的过程),是一款国外开源的ETL工具,纯Java编写,可以在Window. ...
- django3.x版本不支持MySQL5.x版本
其实django2.0版本已经不再支持MySQL5.x的了,最开始是安装了MySQL5.1,在学习django 的时候,django版本为3.0,在执行`python manage.py migrat ...