Python 开发者不得不知的魔术方法(Magic Method)_what is the magic method for creating an instance (1)

最后

🍅 硬核资料:关注即可领取PPT模板、简历模板、行业经典书籍PDF。
🍅 技术互助:技术群大佬指点迷津,你的问题可能不是问题,求资源在群里喊一声。
🍅 面试题库:由技术群里的小伙伴们共同投稿,热乎的大厂面试真题,持续更新中。
🍅 知识体系:含编程语言、算法、大数据生态圈组件(Mysql、Hive、Spark、Flink)、数据仓库、Python、前端等等。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

正确用法

def setattr(self, name, value):
self.dict[name] = value # 给类中的属性名分配值

定制特有属性

更多Python视频、源码、资料加群683380553免费获取


Python的魔术方法很强大,但是用时却需要慎之又慎,了解正确的使用方法非常重要。


**创建自定义容器**


有很多方法可以让你的Python类行为向内置容器类型一样,比如我们常用的list、dict、tuple、string等等。Python的容器类型分为可变类型(如list、dict)和不可变类型(如string、tuple),可变容器和不可变容器的区别在于,不可变容器一旦赋值后,不可对其中的某个元素进行修改。   在讲创建自定义容器之前,应该先了解下协议。这里的协议跟其他语言中所谓的”接口”概念很像,它给你很多你必须定义的方法。然而在Python中的协议是很不正式的,不需要明确声明实现。事实上,他们更像一种指南。


**自定义容器的magic method**


下面细致了解下定义容器可能用到的魔术方法。首先,实现不可变容器的话,你只能定义 \_\_len\_\_ 和 \_\_getitem\_\_ (下面会讲更多)。可变容器协议则需要所有不可变容器的所有,另外还需要 \_\_setitem\_\_ 和 \_\_delitem\_\_。如果你希望你的对象是可迭代的话,你需要定义 \_\_iter\_\_ 会返回一个迭代器。迭代器必须遵循迭代器协议,需要有 \_\_iter\_\_(返回它本身) 和 next。



len(self)


返回容器的长度。对于可变和不可变容器的协议,这都是其中的一部分。



getitem(self, key)


定义当某一项被访问时,使用self[key]所产生的行为。这也是不可变容器和可变容器协议的一部分。如果键的类型错误将产生TypeError;如果key没有合适的值则产生KeyError。



setitem(self, key, value)


当你执行self[key] = value时,调用的是该方法。



delitem(self, key)


定义当一个项目被删除时的行为(比如 del self[key])。这只是可变容器协议中的一部分。当使用一个无效的键时应该抛出适当的异常。



iter(self)


返回一个容器迭代器,很多情况下会返回迭代器,尤其是当内置的iter()方法被调用的时候,以及当使用for x in container:方式循环的时候。迭代器是它们本身的对象,它们必须定义返回self的\_\_iter\_\_方法。



reversed(self)


实现当reversed()被调用时的行为。应该返回序列反转后的版本。仅当序列可以是有序的时候实现它,例如对于列表或者元组。



contains(self, item)


定义了调用in和not in来测试成员是否存在的时候所产生的行为。你可能会问为什么这个不是序列协议的一部分?因为当\_\_contains\_\_没有被定义的时候,如果没有定义,那么Python会迭代容器中的元素来一个一个比较,从而决定返回True或者False。



missing(self, key)


dict字典类型会有该方法,它定义了key如果在容器中找不到时触发的行为。比如d = {‘a’: 1}, 当你执行d[notexist]时,d.\_\_missing\_\_[‘notexist’]就会被调用。


**一个例子**


下面是书中的例子,用魔术方法来实现Haskell语言中的一个数据结构。



-- coding: utf-8 --

更多Python视频、源码、资料加群683380553免费获取

class FunctionalList:
‘’’ 实现了内置类型list的功能,并丰富了一些其他方法: head, tail, init, last, drop, take’‘’

def init(self, values=None):
if values is None:
self.values = []
else:
self.values = values

def len(self):
return len(self.values)

def getitem(self, key):
return self.values[key]

def setitem(self, key, value):
self.values[key] = value

def delitem(self, key):
del self.values[key]

def iter(self):
return iter(self.values)

def reversed(self):
return FunctionalList(reversed(self.values))

def append(self, value):
self.values.append(value)

def head(self):
# 获取第一个元素
return self.values[0]

def tail(self):
# 获取第一个元素之后的所有元素
return self.values[1:]

def init(self):
# 获取最后一个元素之前的所有元素
return self.values[:-1]

def last(self):
# 获取最后一个元素
return self.values[-1]

def drop(self, n):
# 获取所有元素,除了前N个
return self.values[n:]

def take(self, n):
# 获取前N个元素
return self.values[:n]


其实在collections模块中已经有了很多类似的实现,比如Counter、OrderedDict等等。


**反射**


你也可以控制怎么使用内置在函数sisinstance()和issubclass()方法 反射定义魔术方法. 这个魔术方法是:



instancecheck(self, instance)


检查一个实例是不是你定义的类的实例



subclasscheck(self, subclass)


检查一个类是不是你定义的类的子类


这些魔术方法的用例看起来很小, 并且确实非常实用. 它们反应了关于面向对象程序上一些重要的东西在Python上,并且总的来说Python: 总是一个简单的方法去找某些事情, 即使是没有必要的. 这些魔法方法可能看起来不是很有用, 但是一旦你需要它们,你会感到庆幸它们的存在。


**可调用的对象**


你也许已经知道,在Python中,方法是最高级的对象。这意味着他们也可以被传递到方法中,就像其他对象一样。这是一个非常惊人的特性。


在Python中,一个特殊的魔术方法可以让类的实例的行为表现的像函数一样,你可以调用它们,将一个函数当做一个参数传到另外一个函数中等等。这是一个非常强大的特性,其让Python编程更加舒适甜美。



call(self, [args…])


允许一个类的实例像函数一样被调用。实质上说,这意味着 x() 与 x.\_\_call\_\_() 是相同的。注意 \_\_call\_\_ 的参数可变。这意味着你可以定义 \_\_call\_\_ 为其他你想要的函数,无论有多少个参数。


\_\_call\_\_ 在那些类的实例经常改变状态的时候会非常有效。调用这个实例是一种改变这个对象状态的直接和优雅的做法。用一个实例来表达最好不过了:



-- coding: UTF-8 --

python学习交流群:103456743

class Entity:
“”"
调用实体来改变实体的位置
“”"

def init(self, size, x, y):
self.x, self.y = x, y
self.size = size

def call(self, x, y):
“”"
改变实体的位置
“”"
self.x, self.y = x, y


**上下文管理**


with声明是从Python2.5开始引进的关键词。你应该遇过这样子的代码:



with open(‘foo.txt’) as bar:

do something with bar


在with声明的代码段中,我们可以做一些对象的开始操作和退出操作,还能对异常进行处理。这需要实现两个魔术方法: \_\_enter\_\_ 和 \_\_exit\_\_。



enter(self)


定义了当使用with语句的时候,会话管理器在块被初始创建时要产生的行为。请注意,\_\_enter\_\_的返回值与with语句的目标或者as后的名字绑定。



exit(self, exception_type, exception_value, traceback)


定义了当一个代码块被执行或者终止后,会话管理器应该做什么。它可以被用来处理异常、执行清理工作或做一些代码块执行完毕之后的日常工作。如果代码块执行成功,exceptiontype,exceptionvalue,和traceback将会为None。否则,你可以选择处理这个异常或者是直接交给用户处理。如果你想处理这个异常的话,请确保\_\_exit在所有语句结束之后返回True。如果你想让异常被会话管理器处理的话,那么就让其产生该异常。


**创建对象描述器**


描述器是通过获取、设置以及删除的时候被访问的类。当然也可以改变其它的对象。描述器并不是独立的。相反,它意味着被一个所有者类持有。当创建面向对象的数据库或者类,里面含有相互依赖的属相时,描述器将会非常有用。一种典型的使用方法是用不同的单位表示同一个数值,或者表示某个数据的附加属性。


为了成为一个描述器,一个类必须至少有\_\_get\_\_,\_\_set\_\_,\_\_delete\_\_方法被实现:



get(self, instance, owner)


定义了当描述器的值被取得的时候的行为。instance是拥有该描述器对象的一个实例。owner是拥有者本身



set(self, instance, value)


定义了当描述器的值被改变的时候的行为。instance是拥有该描述器类的一个实例。value是要设置的值。



delete(self, instance)


定义了当描述器的值被删除的时候的行为。instance是拥有该描述器对象的一个实例。


下面是一个描述器的实例:单位转换。



-- coding: UTF-8 --

python学习交流群:103456743

class Meter(object):
“”"
对于单位"米"的描述器
“”"
def init(self, value=0.0):
self.value = float(value)

def get(self, instance, owner):
return self.value

def set(self, instance, value):
self.value = float(value)

class Foot(object):
“”"
对于单位"英尺"的描述器
“”"
def get(self, instance, owner):
return instance.meter * 3.2808
def set(self, instance, value):
instance.meter = float(value) / 3.2808

class Distance(object):
“”"
用米和英寸来表示两个描述器之间的距离
“”"
meter = Meter(10)
foot = Foot()


使用时:



d = Distance()
print d.foot
print d.meter
32.808
10.0


**复制**




**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化学习资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618317507)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 21
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值