Python之魔术方法

Python魔术方法

__开头,__结尾的方法就是魔术方法.

  • 1.__str__格式化输出对象
    __repr__表示对象本身
class A:
    def __str__(self):
        return 'This is A'
    
    # 表示对象本身
    def __repr__(self):
        return "I'm a A"

a = A()
print(a)  # This is A
a  # I'm a A
  • 2.__init____new__

__init__ 初始化实例,无返回值
__new__创建一个实例,并返回类的实例.
__new__是一个特殊的类方法,不需要使用@classmethod来装饰.

使用__new__单例模式
# 借助__new__方法实现单例模式
class Singleton:
    instance = None
    
    def __new__(cls, *args, **kwargs):
        # 判断实例对象是否已经存在
        if cls.instance is None:
            # 说明实例对象不存在.需要创建
            cls.instance = super().__new__(Singleton, *args, **kwargs)
        return cls.instance  

s = Singleton()
s2 = Singleton()
s is s2
out: True
display(id(s), id(s2))
out: 78960288  78960288
  • 3.数学运算、比较运算
    运算符重载

+:__add__(value)
-: __sub__(value) substract
*: __mul__(value) mulply
/: __truediv__(value) (Python 3.x), __div__(value) (Python 2.x) divide
//: __floordiv__(value)
%: __mod__(value)
&: __and__(value)
|:__or__(value)

# 自定义字典的加法
class Dict(dict):
    # 实现加法
    def __add__(self, other):
        # 判断other是否是字典.
        if isinstance(other, dict):
            new_dict = {}
            new_dict.update(self)
            new_dict.update(other)
            return new_dict
        else:
            raise TypeError('not a dict')

d1 = {1: 11, 2: 22}
d2 = {1: 111, 2: 222, 3:333}
dd1 = Dict(d1)
dd1 + d2
out:{1: 111, 2: 222, 3: 333}
# 定义一个类,长方形  , 让长方形类的实例对象可以实现减法操作.
class Rectangle:
    def __init__(self, height, width):
        self.height = height
        self.width = width
        
    # 实现减法
    def __sub__(self, other):
        if isinstance(other, Rectangle):
            return Rectangle(abs(self.height - other.height), abs(self.width - other.width))
        else:
            raise TypeError('not a rectangle')
            
    def __repr__(self):
        return  f'<Rectangle ({self.height}, {self.width})>'

r1 = Rectangle(1,2)
r2 = Rectangle(1,1)
r1 - r2
out:<Rectangle (0, 1)>

比较运算符的重载

==: __eq__(value)
!=: __ne__(value)
>: __gt__(value)
>=: __ge__(value)
<: __lt__(value)
<=: __le__(value)

# 定一个类实现数学上的无穷大
class Inf:
    def __eq__(self, other):
        return False
    
    def __ne__(self, other):
        return True
    
    def __gt__(self, other): 
        return True
    
    def __ge__(self, other):
        return False
    
    def __lt__(self, other):
        return False
    
    def __le__(self, other):
        return False

inf = Inf()
inf > 20 ** 10000
out:True
# 练习: 写个长方体, 让长方体的实例对象之间可以比体积大小.
# 优化版本
class Cuboid:
    def __init__(self, lenght, width, height):
        self.lenght = lenght
        self.width = width
        self.height = height
        
    @property
    def V(self):
        return self.lenght * self.width * self.height
    
    def __gt__(self, other):
        if isinstance(other, Cuboid):
            return self.V > other.V
        else:
            raise TypeError('not a cuboid')
            
    def __repr__(self):
        return f'<Cuboid  ({self.lenght}, {self.width}, {self.height}>'

c1 = Cuboid(2,3,4)
c2 = Cuboid(1,1,1)
c1 > c2
out:True
sorted([c1,c2])  # 对体积进行排序
out:[<Cuboid  (1, 1, 1>, <Cuboid  (2, 3, 4>]
  • 4.容器方法

__len__ -> len
__iter__ -> for
__contains__ -> in
__getitem__ 对 string, bytes, list, tuple, dict 有效
__setitem__ 对 list, dict 有效
__missing__ 对 dict 有效, 字典的预留接口, dict 本身并没有实现

l = [1,2,3]
len(l)
out:3
l.__len__()
out:3
l[0]
out: 1
l.__getitem__(0)
out: 1

l[0] = 8
l
out:[8, 2, 3]
l.__setitem__(0,10)
l
out: [10, 2, 3]
d1 = {1: 111, 2: 222, 3: 333}
d1[0]
out:---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-77-f64ff61913e8> in <module>()
----> 1 d1[0]
KeyError: 0

# 让字典的key找不到的时候,不要报错.返回空列表
class Dict(dict):
    def __missing__(self, key):
        return []
ddd = Dict(d1)
ddd[0]
out: []
  • 5.上下文管理 with:

__enter__进入 with 代码块前的准备操作
__exit__ 退出时的善后操作
文件对象、线程锁、socket 对象 等 都可以使用 with 操作
with 不管with语句块中是否出现异常,资源依然可以被正常的释放.

exceptions = []
class A:
    def __enter__(self):
        print('enter....')
        print(self)
        return self
    
    def __exit__(self, Error, error, Exception):
        print(Error, error, Exception)
        exceptions.append(Error)
        exceptions.append(error)
        exceptions.append(Exception)
        print('exiting....')

with A() as a:
    print(a)
    print('------------------')
    raise TypeError() 

out:enter....
<__main__.A object at 0x0000000004E44940>
<__main__.A object at 0x0000000004E44940>
------------------
<class 'TypeError'>  <traceback object at 0x0000000004DD9848>
exiting....
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-111-421bdf2504b3> in <module>()
      2     print(a)
      3     print('------------------')
----> 4     raise TypeError()
      5 
TypeError: 
exceptions
out:[TypeError, TypeError(), <traceback at 0x4dd9848>]
Error, error, trace = exceptions
import traceback
traceback.print_exception(Error, error, trace)  # 打印出异常

out:Traceback (most recent call last):
  File "<ipython-input-111-421bdf2504b3>", line 4, in <module>
    raise TypeError()
TypeError

python的内省

setattr() # 设置属性__setattr__()
getattr() # 获取属性__getattribute__
hasattr() # 判断是否有某个属性

class A:
    def __init__(self,  x, y):
        self.x = x
        self.y = y
a = A(1,2)

setattr(a, 'z', 3)
a.z
out: 3
a.__setattr__('z', 9)
a.z
out: 9

getattr(a, 'x')
out: 1
a.__getattribute__('x')
out: 1
# __getattr__当__getattribute__找不到属性的时候,会执行__getattr__

# 默认获取不到会报错
getattr(a, 'a', 0)
out: 0

hasattr(a, 'a') 
out: False
'a' in a.__dict__
out: False  # 没有a.__hasattr__('a')
# 常用于属性监听
class User:
    '''TestClass'''
    z = [7,8,9]
    def __init__(self):
        self.money = 10000
        self.y = 'abc'

    def __setattr__(self, name, value):
        if name == 'money' and value < 0:
            raise ValueError('money < 0')
        print('set %s to %s' % (name, value))
        object.__setattr__(self, name, value)

    def __getattribute__(self, name):
        print('get %s' % name)
        return object.__getattribute__(self, name)

    def __getattr__(self, name):
        print('not has %s' % name)
        return -1

    def foo(self, x, y):
        return x ** y

# 对比
a = User()
# print(User.__dict__)
# print(a.__dict__)
out: set money to 10000
set y to abc
a.money -= 11000  #  = a.money = a.money - 11000
out: get money
---------------------------------------------------------------------------
ValueError  
---> 11             raise ValueError('money < 0')
     12         print('set %s to %s' % (name, value))
     13         object.__setattr__(self, name, value)
ValueError: money < 0
  • 8.槽: __slots__

固定类所具有的属性
实例不会分配 __dict__
实例无法动态添加属性
优化内存分配, 大概能节约40%的内存.

class B:
    __slots__ = ['x', 'y']

b = B()
b.x = 10
b.x
out: 10

b.z = 10
out: ---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-147-47de4eac37de> in <module>()
----> 1 b.z = 10
AttributeError: 'B' object has no attribute 'z'

b.__dict__  # 报错没有__dict__
out:---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-148-395029f23f31> in <module>()
----> 1 b.__dict__
AttributeError: 'B' object has no attribute '__dict__'
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值