简介

在实际项目中,我们其实并不会太多的使用魔法函数,但是一些方法或者函数均是有魔法函数演变而来的,且在一些面试过程中会遇到一些关于常见方法的实现,就会牵扯到相应的魔法函数,此处将介绍一些我认为比较常用的魔法函数。

__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 常用的魔法函数的更多相关文章

  1. python常用内置函数

    Python所以内置函数如下: 下面列举一些常用的内置函数: chr()和ord() chr()将数字转换为对应的ascii码表字母 >>> r=chr(65) >>&g ...

  2. python进阶之魔法函数

    __repr__ Python中这个__repr__函数,对应repr(object)这个函数,返回一个可以用来表示对象的可打印字符串.如果我们直接打印一个类,向下面这样 class A():     ...

  3. $Python常用内置函数典型用法

    Python中有许多功能丰富的内置函数,本文基于Python 2.7,就常用的一些函数的典型用法做一些积累,不断更新中. sorted函数的三种用法 # coding:utf-8 # sorted函数 ...

  4. 致Python初学者,Python常用的基础函数你知道有哪些吗?

    Python基础函数: print()函数:打印字符串 raw_input()函数:从用户键盘捕获字符 len()函数:计算字符长度 format(12.3654,'6.2f'/'0.3%')函数:实 ...

  5. python常用内置函数和关键字

    常用内置方法 在Python中有许许多多的内置方法,就是一些Python内置的函数,它们是我们日常中经常可以使用的到的一些基础的工具,可以方便我们的工作. 查看所有的内置类和内置方法 # 方法一 bu ...

  6. python 类的魔法函数 内置函数 类方法 静态方法 抽象类

    魔法函数 __init__函数 init函数会在实例化A这个类的时候被调用 class A(): def __init__(self): print('__init__函数') a = A() 显示结 ...

  7. python常用内置函数整理

    1.最常见的内置函数是print print("Hello World!") 2.数学运算 abs(-5) # 取绝对值,也就是5 round(2.6) # 四舍五入取整,也就是3 ...

  8. Python常用内置函数整理(lambda,reduce,zip,filter,map)

    匿名函数lambda lambda argument1,argument2,...argumentN :expression using arguments 1.lambda是一个表达式,而不是一个语 ...

  9. Python常用内置函数介绍

    Python提供了一个内联模块buildin.内联模块定义了一些开发中经常使用的函数,利用这些函数可以实现数据类型的转换.数据的计算.序列的处理等功能.下面将介绍内联模块中的常用函数. Python内 ...

随机推荐

  1. CRM项目的整理---第一篇

    CRM:cunstomer relationship management  客户管理系统 1.项目的使用者:销售  班主任    讲师  助教 2.项目的需求分析 2.1.注册 2.2.登录 2.3 ...

  2. SSO 方案演进

    背景介绍 随着业务与技术的发展,现今比以往任何时候都更需要单点登录 SSO 身份验证. 现在几乎每个网站都需要某种形式的身份验证才能访问其功能和内容. 随着网站和服务数量的增加,集中登录系统已成为一种 ...

  3. ThreadLocal夺命11连问

    前言 前一段时间,有同事使用ThreadLocal踩坑了,正好引起了我的兴趣. 所以近期,我抽空把ThreadLocal的源码再研究了一下,越看越有意思,发现里面的东西还真不少. 我把精华浓缩了一下, ...

  4. Git 上传文件项目到github,gitee详细教程!(本文用的gitee)

    1:安装Git 下载地址:https://git-scm.com/ 2:生成ssh密钥不会的可以去另一篇文章 https://www.cnblogs.com/psfjc/p/15980893.html ...

  5. 189. Rotate Array - LeetCode

    Question 189. Rotate Array Solution 题目大意:数组中最后一个元素移到第一个,称动k次 思路:用笨方法,再复制一个数组 Java实现: public void rot ...

  6. CentOS7软件环境

    一.软件环境 1.1 centos7 [root@centos7 ~]# cat /etc/redhat-release CentOS Linux release 7.4.1708 (Core) [r ...

  7. Python技法:用argparse模块解析命令行选项

    1. 用argparse模块解析命令行选项 我们在上一篇博客<Linux:可执行程序的Shell传参格式规范>中介绍了Linux系统Shell命令行下可执行程序应该遵守的传参规范(包括了各 ...

  8. Fail2ban 配置详解 监禁配置(jail.conf)

    ### # 包含配置 ### [INCLUDES] # after = # 在加载本配置文件之后再加载指定的独立配置文件. before = paths-debian.conf # 在加载本配置文件之 ...

  9. 20 HTTP 长连接与短连接

    20 HTTP 长连接与短连接 每日一句 纸上得来终觉浅,绝知此事要躬行. 每日一句 Never give up until the fight is over. 永远不要放弃,要一直战斗到最后一秒. ...

  10. MTK 虚拟 sensor bring up (pick up) sensor2.0

    pick up bring up sensor2.0 1.SCP侧的配置 (1) 放置驱动pickup.c (2) 添加底层驱动文件编译开关 (3) 加入编译文件 (4) 增加数据上报方式 (5)修改 ...