python进阶--python魔术方法

python魔术方法

参考文档:https://www.cnblogs.com/nmb-musen/p/10861536.html

1. 构造方法__new__

构造方法包括创建对象和初始化对象,在python当中,分为两步执行:先执行__new__方法,然后执行__init__方法。

+ __init__是当实例对象创建完成后被调用的,然后设置对象属性的一些初始值。
+ __new__是在实例创建之前被调用的,因为它的任务就是创建实例然后返回该实例,是个静态方法。

也就是,__new__在__init__之前被调用,__new__的返回值(实例)将传递给__init__方法的第一个参数,然后__init__给这个实例设置一些参数
class A:
    def __new__(cls, *args, **kwargs):   # 至少要有一个参数cls,由Python解释器自动提供
        cls.instance = object.__new__(cls)
        print('这是__new__方法')
        print(cls)
        return cls.instance      # 必须要有返回值,返回实例化出来的实例

    def __init__(self):    # 有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作
        print('这是__init__方法')
        print(self)    # 不需要返回值


a =A()

>
这是__new__方法
<class '__main__.A'>
这是__init__方法
<__main__.A object at 0x7fc74c95bac0>

2. 单例模式

单例模式就是确保一个类只有一个实例

# 同一个类多次实例化后会获取多个不同的实例
class Demo:
    def __init__(self):
        pass

    def demo(self):
        pass


a = Demo()
print(id(a))

b = Demo()
print(id(b))
>

140598884625520
140598884683936
单例模式实现一:__new__方法
class Singleton(object):
    __instance = None       # 设置一个类属性来标记这个类没有创建过

    def __new__(cls, *args, **kwargs):
        if not cls.__instance:
            cls.__instance = object.__new__(cls)
        return cls.__instance


c = Singleton()
c.token = '12345'
print(id(c))


d = Singleton()
print(id(d))
print(d.token)

>
140710293916352
140710293916352
12345
单例模式实现二:装饰器方式
def singleton(cls):
    # 单下划线的作用是这个变量只能在当前模块里访问,仅仅是一种提示作用
    # 创建一个字典用来保存类的实例对象
    _instance = {}

    def _singleton(*args, **kwargs):
        # 先判断这个类有没有对象
        if cls not in _instance:
            _instance[cls] = cls(*args, **kwargs)  # 创建一个对象,并保存到字典当中
        # 将实例对象返回
        return _instance[cls]

    return _singleton

@singleton
class A(object):
    a = 1

    def __init__(self, x=0):
        self.x = x
        print('这是A的类的初始化方法')


a1 = A(2)
a2 = A(3)
print(id(a1), id(a2))


>
这是A的类的初始化方法
140683534546160 140683534546160

3. 方法__str__和__repr__

交互式运行时,print()方式调用的是__str__方法,直接输入变量调用的是__repr__方法

>>> a = '123'
>>> print(a)    # 触发__str__方法
123
>>> a           # 触发__repr__方法
'123'

__str__和__repr__方法必须返回str类型

print()、str()、format()方法均可调用__str__
repr()可调用__repr__方法
class DemoStr(object):
  def __str__(self):
    print('__str__方法')
    return '__str__'

  def __repr__(self):
    # print('__repr__')
    return '__repr__方法'


s = DemoStr()

print(s)
str(s)
format(s)
repr(s)
>

__str__方法
__str__
__str__方法
__str__方法
__repr__

当调用__str__方法不存在,调用的是__repr__方法

class DemoStr(object):
  # def __str__(self):
  #   print('__str__方法')
  #   return '__str__'

  def __repr__(self):
    print('__repr__')
    return '__repr__方法'


s = DemoStr()

print(s)
str(s)
format(s)


>
__repr__
__repr__方法
__repr__
__repr__

当调用时__repr__方法不存在,调用的是父类的__repr__方法

class DemoStr(object):

  pass

s = DemoStr()

print(s)

>
<__main__.DemoStr object at 0x7f88ee7ba160>

总结:一般来说__str__的可读性更强,而__repr__的返回结果更具有准确性,更加的适合开发者

4. 方法__call__

python中万物皆对象。函数之所以可以被调用,是因为有__call__方法

class DemoStr(object):
  pass
s = DemoStr()
s()

>
TypeError: 'DemoStr' object is not callable

class DemoStr(object):
  def __call__(self):
    print('__call__方法被调用了')
  
s = DemoStr()
s()

>
__call__方法被调用了

类装饰器实现
class Decorator(object):

  def __init__(self, func):
    self.func = func

  def __call__(self, *args, **kwargs):
    print('装饰器功能')
    return self.func(*args, **kwargs)

@Decorator
def fun(a, b):
  print('原函数功能')
  return a + b

a = fun(2, 3)

print(a)

>
装饰器功能
原函数功能
5

5. 上下文管理器

上下文管理器:在一个类里实现了__enter__和__exit__方法,这个类的实例就是一个上下文管理器

# 上下文管理器表达式标准语句体
with 上下文管理器 as f:
     语句体

当with遇到上下文管理器,就会在执行语句体之前,先执行上下文管理器的__enter__方法,然后再执行语句体,执行完语句体后,最后执行__exit__方法

class Demo:
    def __init__(self):
        print('首先使用__init__实例化一个对象')

    def __enter__(self):
        print('执行语句体之前,先执行上下文管理器的__enter__方法进入')

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('执行完语句体后,最后执行__exit__方法退出')

res_obj = Demo()

# with + 上下文管理器
with res_obj:
  print('哈哈哈哈')

>  
首先使用__init__实例化一个对象
执行语句体之前,先执行上下文管理器的__enter__方法进入
哈哈哈哈
执行完语句体后,最后执行__exit__方法退出

自定义Open上下文管理器

class Open:
    def __init__(self, filename, mode , encoding='utf-8'):
        self.filename = filename
        self.mode = mode
        self.encoding = encoding

    def __enter__(self):
        print('打开文件')
        self.f = open(self.filename, self.mode, encoding=self.encoding)
        return self.f

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('关闭文件')
        self.f.close()



with Open('mq.py', 'r') as f:
  print(f)

>
打开文件
<_io.TextIOWrapper name='mq.py' mode='r' encoding='utf-8'>
关闭文件
  • 上下文管理器实现mysql连接:https://blog.csdn.net/qq_25672165/article/details/111076772

6.算术方法

class SuanShu(object):
    def __init__(self, num):
        self.num = num
    #运算符重载
    def __add__(self, other): # self,other 都是对象
        print(self.num)
        print(other.num)
        return SuanShu(self.num + other.num)
    def __str__(self):
        return "num = " + str(self.num)

res1 = SuanShu(1)
res2 = SuanShu(2)
print(res1 + res2)    #res1 + res2 ==== res1.__add__(res2)
#print(res1.__add__(res2))
print(res1)
print(res2)

>
1
2
num = 3
num = 1
num = 2

7. 方法__dict__

__dict__可获取类和对象的所有成员

1. 子类比父类少了'__dict__'和'__weakref__'属性
2. 对象默认无成员,可自定义成员
class DemoA:
  pass

class DemoB(DemoA):
  pass


a = DemoA()
b = DemoB()
b.name ='123'

print(DemoA.__dict__)
print(DemoB.__dict__)
print(a.__dict__)
print(b.__dict__)

>
{'__module__': '__main__', '__dict__': <attribute '__dict__' of 'DemoA' objects>, '__weakref__': <attribute '__weakref__' of 'DemoA' objects>, '__doc__': None}
{'__module__': '__main__', '__doc__': None}
{}
{'name': '123'}

8. 方法__solts__

Python默认用一个字典来保存对象的实例属性,因此我们可以自定义新的实例属性。__solts__方法可用来限制属性,并节约内存(不会再自动生成__dict__等属性)

class DemoA:
  __slots__ = ['name']
  pass

a = DemoA()
a.age ='18'

>
Traceback (most recent call last):
  File "/Users/whtest/Desktop/Hrunner/HrunDemo/demo.py", line 6, in <module>
    a.age ='18'
AttributeError: 'DemoA' object has no attribute 'age'

9. 方法__*attr__

同时定义__getattribute__和__getattr__时,__getattr__方法不会再被调用,除非显示调用__getattr__方法或引发AttributeError异常

###  方法__*attr__

同时定义__getattribute__和__getattr__时,__getattr__方法不会再被调用,除非显示调用__getattr__方法或引发AttributeError异常

```python
class Demo:


  def __getattribute__(self, item):
    print('查找属性时触发__getattribute__')
    return '调用__getattribute__方法获取属性'

  def __getattr__(self, item):
    # 存在__getattribute__方法时__getattr__方法永远不会被调用
    print('属性不存在时触发__getattr__')
    return '调用__getattr__方法获取属性,属性不存在'

  def __setattr__(self, key, value):
    print('设置属性时触发__setattr__')

  def __delattr__(self, item):
    print('删除属性时触发__delattr__')



a = Demo()
print(a.name)

a.name = 'zhangsan'
print(a.name)

del a.name

>
查找属性时触发__getattribute__
调用__getattribute__方法获取属性
设置属性时触发__setattr__
查找属性时触发__getattribute__
调用__getattribute__方法获取属性
删除属性时触发__delattr__
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值