python魔法方法浅析

python-魔法方法

1 前言

为什么python会有那么多的爱好者,和追捧者,分几个层面讲,

  • 在应用层面,python有300,585个项目,python除了不能给你生孩子,其他的什么都可以做,而且你都能找到相关的包,不必重复造轮子,拿来即用;
  • 在开发者层面,python做了很好的封装的同时又兼具开放性,我们可以通过魔法方法设计自己的类,让自己的类能够像python源码中的类具有相同的功能

话不多说,今天就来简单聊一聊魔法方法

2 预热

人生苦短,我用python这句zen of python 其实是有道理的!

# python求一个字符串的长度
string = "hello world"
len(string)
>11
type(string)
>class str
# string 是str类的一个实例
# 求一个字符串的长度相当于调用str类的__len__()方法
string.__str__()
>11

_ xx _ 双下划线开头,双下划线结尾,这种方法就是python的魔法方法

3 正题

自定义一个类,通过代码进行测试

3.1 实例化

class Foo:
	def __init__(self,x):
		self._x = x
f1 = Foo(1)
print(f1._x)
> 1

3.2 格式输出类

class Foo:
	def __str__(self):
		return "in __str__ comments of class"
	def __repr__(self):
		return "in __repr__ comments of class"
f1 = Foo()
print(f1)
> in __str__ comments of class
⇒ f1
> in __repr__ comments of class
# # 当直接查看对象的时候调用的是__repr__方法,对象需要转字符串的时候调用的是__str__方法,但是当字典列表等容器的时候调用的还是__repr__方法
# 一般来说__str__的可读性更强,而__repr__的返回结果更具有准确性,更加的适合开发者
# 我们在写类的时候,最好至少添加一个__repr__方法,来保证类到字符串的转换具有自定义的有效性,__str__是可选的,因为在默认情况下,__Str__方法默认实现调用的是__repr__方法,
# 所以在对象转字符串时候,找到底层str方法之后,会调用重写的__repr__方法

3.3 设置属性

class Foo:
	def __init__(self):
	# 初始化一个存储空间,这个存储空间类似于object.__dict__,用来存储属性与属性值
		object.__setattr__(self,"storage",{})
	# 类名.属性 "."这个语法糖就是靠下面这个特殊方法实现的
	
	def __setattr__(self,key,value):
		self.storage[key] = value
	
	def __getattr__(self,key):
		return self.storage[key]
	
	def __delattr__(self,key):
		del self.storage[key]

f1 = Foo()
f1.name = "kobe"
print(f1.name)
> "kobe"
del f1.name
print(f1.name)
> KeyError

3.4 运算&迭代

class Foo(object):
    """
    This is a test Class
    """
    def __init__(self, x=None, y=None):
        object.__setattr__(self,"_storage",{})
        self._x = x
        self._y = y
    def __repr__(self):
        return "this is a introduciton of test class"
    def __str__(self):
        return "instance of Foo"
	# 变成可迭代对象
    def __iter__(self):
        return iter(self._storage.items())
	# 这个类的实例化对象可以 使用 “+” 运算符
    def __add__(self, other):
        if isinstance(other, Foo):
            return self._x + other._x
        else:
            raise ValueError("diff class cann't add")
	# 这个类的实例化对象可以 使用 “-” 运算符
    def __sub__(self, other):
        pass
	# 这个类的实例化对象可以 使用 “*” 运算符
    def __mul__(self, other):
        pass
	# 这个类的实例化对象可以 使用 “/” 运算符
    def __divmod__(self, other):
        pass
	# 这个类的实例化对象可以 使用 “==” 运算符
    def __eq__(self, other):
        pass
	# 这个类的实例化对象可以 使用 “&” 运算符
    def __and__(self, other):
        if isinstance(other, Foo):
            return self._x - other._x
        else:
            return None
	# 这个类的实例化对象可以 使用 “|” 运算符
    def __or__(self, other):
        pass

3.5 上下文管理

python在进行IO操作时,需要获取链接资源,无论是文件还是数据库还是网络链接,资源都不是无数个的,所以在用完链接后必须断开链接,但是在链接过程中如果程序出现问题还没有运行到断开链接就挂掉了,这种情况就会浪费链接资源

# 链接数据库操作
try:
	db.conn()
	time.sleep(10) # 模拟数据操作
except Exception as e:
	print(e)
finally:
	db.disconn() 

# python 文件读取
open ("a.txt", 'w') as f:
	f.write("hello world")

# 这两种语法都可以实现程序意外停止导致的资源无法释放问题
# 我的Foo类也想实现这样的用法
def Foo():
	def __init__(self):
		pass

	def __enter__(self):
        self.open()

    def __exit__(self, exc_type, exc_val, exc_tb):
        #print(exc_val)
        self.close()
        return True 

    def open(self):
        print("执行连接操作,获取连接资源")

    def close(self):
        print("断开连接,释放资源")
 with f1 as hhh:
     print("hello workd")
     raise ValueError("error")
     print("working...")
> 执行连接操作,获取连接资源
> hello workd
> 断开连接,释放资源
> working...

未完待续

原创文章,如转载请注明出处

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kobe_OKOK_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值