python 常用的魔法函数
简介
在实际项目中,我们其实并不会太多的使用魔法函数,但是一些方法或者函数均是有魔法函数演变而来的,且在一些面试过程中会遇到一些关于常见方法的实现,就会牵扯到相应的魔法函数,此处将介绍一些我认为比较常用的魔法函数。
__new __、__init __
类的构造函数,一般初始化传值使用
class Init():
def __init__(self, name):
self.name = name
def show_name(self):
print(self.name)
i = Init('tom')
i.show_name()
tom
__str __ 与 __repr __
当直接查看对象的时候调用的是__repr__方法,对象需要转字符串的时候调用的是__str__方法,但是当字典列表等容器的时候调用的还是__repr__方法,可以通过str()和repr()来实现结果的输出,str输出的结果一般可读性相对较强,repr的结果输出相对较为准确,当调用str()时会调用 __str __ 当调用repr()时会调用 __repr __,一般而言,__repr __更适合开发者使用
class StrRepr():
def __str__(self):
return '__str__'
def __repr__(self):
return '__repr__'
strRepr = StrRepr()
print(str(strRepr))
print(repr(strRepr))
import datetime
print(str(datetime.datetime.today()))
print(repr(datetime.datetime.today()))
tom
__str__
__repr__
2022-06-08 13:50:11.131003
datetime.datetime(2022, 6, 8, 13, 50, 11, 131031)
由datetime可以看出,__repr __比__str __较为准确
__getitem __、__setitem __、__delitem __
主要针对于字典的key、value进行操作
getitem: 获取键的值
setitem:设置键的值
delitem:删除对应的键
以上的操作都是基于dict[ ]进行操作的
class GetItem():
def __init__(self):
self.data = {}
def __getitem__(self, key):
print('__getitem__')
return self.data[key]
def __setitem__(self, key, value):
print('__setitem__')
self.data[key] = value
def __delitem__(self, key):
print('__delitem__')
del self.data[key]
get = GetItem()
get['name'] = 'tom'
print(get['name'])
del get['name']
print(get['name'])
__setitem__
__getitem__
tom
__delitem__
__getitem__
Traceback (most recent call last):
File "/home/ts/flask_study/常见的魔法函数/magic_method.py", line 62, in <module>
print(get['name'])
File "/home/ts/flask_study/常见的魔法函数/magic_method.py", line 48, in __getitem__
return self.data[key]
KeyError: 'name'
__iter __、__next __
之前曾经记录过关于迭代器、可迭代对象、生成器这三个名词,这两个魔法函数__iter __、__next __就是迭代器的内部实现,可迭代对象则是__iter __的内部实现,生成器则不需要依赖这两者,取而代之的是yield方法。
下面实现了一个简单的range用法
class rangeDemo():
def __init__(self, count):
self.start = 0
self.count = count
def __iter__(self):
return self
def __next__(self):
if self.start < self.count:
self.start += 1
return self.start
else:
raise StopIteration
for i in rangeDemo(10):
print(i, end=',')
print()
n = rangeDemo(10)
print(next(n))
print(next(n))
print(next(n))
1,2,3,4,5,6,7,8,9,10,
1
2
3
当一个类或者对象是否可迭代或者说可遍历时,一般会实现__iter __方法。
__iter __一般返回本身,__next __一般返回下一个元素,超出则抛出异常
__call __
当一个类实例化一个对象后,调用对象时会触发__call __方法
class Call():
def __init__(self):
pass
def __call__(self):
print('__call__')
pass
c = Call()
# 调用对象
c()
__enter __、__exit __
大家在读写文件时一般会用到with open,然而对应with来说,enter、__exit__就是其内部实现,__enter__返回其对象,方便后续进行操作,__exit__则是在结束前进行的操作,有点类似于try except finally。
class WithDemo():
def __init__(self):
pass
def __enter__(self):
# 必须要返回对象本身,供后面进行调用
print('__enter__')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print('__exit__')
def run(self):
print('test')
with WithDemo() as f:
f.run()
__enter__
test
__exit__
__contains __
判断一个容器是否存在某个元素,可以使用in、not in进行判断的,一般都实现了__contains__。
class Contains():
def __contains__(self, item):
print('__contains__', item)
print(1 in Contains())
class Contains2():
def __contains__(self, item):
print('__contains__', item)
return True
print(1 in Contains2())
__contains__ 1
False
__contains__ 1
True
由此可见,默认情况下__contains__会返回False
__setattr __、__getattr __
__ setattr__(self, key, value):设置属性,会将对应的值放入__dict__中,是否需要注册到__dict__中,会影响对应的属性的获取,在类中对属性进行赋值操作时,python会自动调用__setattr__()函数,来实现对属性的赋值。但是重写__setattr__()函数时要注意防止无限递归的情况出现,一般解决办法有两种,一是用通过super()调用__setatrr__()函数,二是利用字典操作对相应键直接赋值。
简单的说,__ setattr__()在属性赋值时被调用,并且将值存储到实例字典中,这个字典应该是self的__dict__属性。
即:在类实例的每个属性进行赋值时,都会首先调用__setattr__()方法,并在__setattr__()方法中将属性名和属性值添加到类实例的__dict__属性中。
__getattr __(self, item):访问不存在的属性
class Attr():
def __init__(self):
print(self.__dict__)
def __setattr__(self, key, value):
print('__setattr__')
self.__dict__[key] = value
pass
def __getattr__(self, key):
print('__getattr__')
print(self.__dict__[key])
attr = Attr()
attr.name = 'tom'
print(attr.__dict__)
print(attr.name)
print(attr.age)
{}
__setattr__
{'name': 'tom'}
tom
__getattr__
Traceback (most recent call last):
File "/home/ts/flask_study/常见的魔法函数/magic_method.py", line 162, in <module>
print(attr.age)
File "/home/ts/flask_study/常见的魔法函数/magic_method.py", line 155, in __getattr__
print(self.__dict__[key])
KeyError: 'age'
总结:Python的实例属性的定义、获取和管理可以通过__setattr__()和__dict__配合进行,当然还有对应的__getattr__()方法,如上文所示。
__ setattr__(self, key, value)方法在类的属性赋值时被调用,并通常需要把属性名和属性值存储到self的__dict__字典中。
__getattribute __
属性拦截器:当这个类的属性被访问时(指的是__init__构造方法中的属性),会自动调用类的__getattribute__方法,注意不要在__getattribute__中调用本类中的方法和实例属性,会出现反反复复的情况。
class Attribute():
def __init__(self, name, age):
self.name = name
self.age = age
pass
def __getattribute__(self, name):
# 获取的是获取属性的key值,不是属性的值
print('__getattribute__, name:{}'.format(name))
if name == 'name':
return True
else:
return 'no found'
attribute = Attribute('tom', 18)
print(attribute.name)
print(attribute.age)
attribute = Attribute('mike', 18)
print(attribute.name)
print(attribute.age)
__getattribute__, name:name
True
__getattribute__, name:age
no found
__getattribute__, name:name
True
__getattribute__, name:age
no found
__dir __
该方法会返回一个类的所有类属性及类方法,包括静态方法、类方法、实例方法等,不会返回实例属性(也就是__init__的属性)。可以通过dir来获取。
如下存在一个Test类
class Test():
test = 1
def __init__(self, name):
self.name = name
def run(self):
print('run')
@staticmethod
def test():
print('test')
@classmethod
def class_test(cls):
print('class_test')
我们使用__dir__取获取
print(object.__dir__)
print(dir(object))
from test import Test
print(dir(Test))
<method '__dir__' of 'object' objects>
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'class_test', 'run', 'test']
__all __
通过在模块文件中设置 __ all__ 变量,当其它文件以“from 模块名 import *”的形式导入该模块时,该文件中只能使用 __ all__ 列表中指定的成员。
也就是说,只有以“from 模块名 import ”形式导入的模块,当该模块设有 __ all__ 变量时,只能导入该变量指定的成员,未指定的成员是无法导入的。
__ all__:如果存在__all__ 可以直接导入 直接使用__all__的列表中的所有成员(包括属性和函数)并使用,如果没有__all__,则默认__all __里是所有函数或属性。
当前存在一个包,里面内容如下,将run1、run2添加至__all__中
__all__ = ['run1', 'run2']
def run1():
print('run1')
pass
def run2():
print('run2')
pass
def run3():
print('run3')
pass
导入*进行操作
from test2 import *
run1()
run2()
run3()
显示run3没有被定义,因为导入包时,做了限制,不过只是限制了*
run1
run2
Traceback (most recent call last):
File "/home/ts/flask_study/常见的魔法函数/magic_method.py", line 203, in <module>
run3()
NameError: name 'run3' is not defined
由于__all __只会限制*的导入方式,因此可以采取导入到详细函数的方式来使用
from test2 import run3
run3()
run3
__slots __
限制绑定的属性
普通的设置属性,如上面的__setattr __所示,会将设置的属性放置在__dict __ 中,__getattr 也会从 dict__中拿取,详细如下:
class Student2(object):
def __init__(self, name="mike"):
self.name = name
print(hasattr("name", ""))
pass
def run(self):
print('run')
s = Student2()
print(dir(s))
print(hasattr(s, "name"))
s.name = "mike"
s.gender = "man"
print(s.name)
print(s.gender)
s.age = 3
print(s.age)
False
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name', 'run']
True
mike
man
3
class Student(object):
# 限制绑定的属性
__slots__ = ["name", "gender"]
def __init__(self, name="mike"):
self.name = name
print(hasattr("name", ""))
pass
def run(self):
print('run')
s = Student()
print(dir(s))
print(hasattr(s, "name"))
s.name = "mike"
s.gender = "man"
print(s.name)
print(s.gender)
s.age = 3
print(s.age)
False
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'gender', 'name', 'run']
True
mike
man
Traceback (most recent call last):
File "/home/ts/flask_study/常见的魔法函数/magic_method.py", line 231, in <module>
s.age = 3
AttributeError: 'Student' object has no attribute 'age'
由上方两个可以看出,当使用__slots __限制绑定属性后,__dict __属性消失了。
综上,__slots __限制的是类属性的设置及获取,适用于类属性固定的状态下,除此之外,使用__slots __能大大减小内存占用。
持续更新中
python 常用的魔法函数的更多相关文章
- python常用内置函数
Python所以内置函数如下: 下面列举一些常用的内置函数: chr()和ord() chr()将数字转换为对应的ascii码表字母 >>> r=chr(65) >>&g ...
- python进阶之魔法函数
__repr__ Python中这个__repr__函数,对应repr(object)这个函数,返回一个可以用来表示对象的可打印字符串.如果我们直接打印一个类,向下面这样 class A(): ...
- $Python常用内置函数典型用法
Python中有许多功能丰富的内置函数,本文基于Python 2.7,就常用的一些函数的典型用法做一些积累,不断更新中. sorted函数的三种用法 # coding:utf-8 # sorted函数 ...
- 致Python初学者,Python常用的基础函数你知道有哪些吗?
Python基础函数: print()函数:打印字符串 raw_input()函数:从用户键盘捕获字符 len()函数:计算字符长度 format(12.3654,'6.2f'/'0.3%')函数:实 ...
- python常用内置函数和关键字
常用内置方法 在Python中有许许多多的内置方法,就是一些Python内置的函数,它们是我们日常中经常可以使用的到的一些基础的工具,可以方便我们的工作. 查看所有的内置类和内置方法 # 方法一 bu ...
- python 类的魔法函数 内置函数 类方法 静态方法 抽象类
魔法函数 __init__函数 init函数会在实例化A这个类的时候被调用 class A(): def __init__(self): print('__init__函数') a = A() 显示结 ...
- python常用内置函数整理
1.最常见的内置函数是print print("Hello World!") 2.数学运算 abs(-5) # 取绝对值,也就是5 round(2.6) # 四舍五入取整,也就是3 ...
- Python常用内置函数整理(lambda,reduce,zip,filter,map)
匿名函数lambda lambda argument1,argument2,...argumentN :expression using arguments 1.lambda是一个表达式,而不是一个语 ...
- Python常用内置函数介绍
Python提供了一个内联模块buildin.内联模块定义了一些开发中经常使用的函数,利用这些函数可以实现数据类型的转换.数据的计算.序列的处理等功能.下面将介绍内联模块中的常用函数. Python内 ...
随机推荐
- c# DateTime 格式化输出字符串
DateTime 输出字符串 带 T,结尾 +08:00 $"{DateTime.Now:O}"; // 2020-12-20T16:11:18.2353338+08:00 $&q ...
- 个人冲刺(二)——体温上报app(二阶段)
冲刺任务:完成app首页.第二页面和特殊情况的页面布局 activity_main.xml <?xml version="1.0" encoding="utf-8& ...
- Fail2ban 配置详解 配置说明
fail2ban的配置主要由基础配置(fail2ban.conf)和监禁配置(jail.conf)两部分组成. fail2ban的配置采用标签块"[块名]"和键值"key ...
- WPF|快速添加新手引导功能(支持MVVM)
阅读导航 前言 案例一 案例二 案例三(本文介绍的方式) 如何使用? 控件如何开发的? 总结 1. 前言 案例一 站长分享过 眾尋 大佬的一篇 WPF 简易新手引导 一文,新手引导的效果挺不错的,如下 ...
- SpringCloud Alibaba Sentinel 限流详解
点赞再看,养成习惯,微信搜索[牧小农]关注我获取更多资讯,风里雨里,小农等你,很高兴能够成为你的朋友. 项目源码地址:公众号回复 sentinel,即可免费获取源码 熔断规则 在上一篇文章中我们讲解了 ...
- MTK 平台sensor arch 介绍-scp
架构介绍 路径:vendor/mediatek/proprietary/tinysys/scp 1.[build]编译相关 2.[driver]scp 的driver,I2C,power,eint 3 ...
- 我用 AntV/S2 买了一套房
背景 经过一年多的摇号,我在前两天收到了某网红盘的摇中通知.还沉浸在摇中房屋喜悦中的我,很快被售房顾问告知选房的人很多,每位购房者的选房时间都很短,必须 一分钟内 快速选房.并且,排在 400 多号的 ...
- 【Java面试】请你简单说一下Mysql的事务隔离级别
一个工作了6年的粉丝,去阿里面试,在第一面的时候被问到"Mysql的事务隔离级别". 他竟然没有回答上来,一直在私信向我诉苦. 我说,你只能怪年轻时候的你,那个时候不够努力导致现在 ...
- Redis基础与性能调优
Redis是一个开源的,基于内存的结构化数据存储媒介,可以作为数据库.缓存服务或消息服务使用. Redis支持多种数据结构,包括字符串.哈希表.链表.集合.有序集合.位图.Hyperloglogs等. ...
- Docker安装Portainer管理工具
1.下载镜像 docker pull portainer/portainer 2.启动 docker run -d -p 9000:9000 --restart=always -v /var/run/ ...