python魔法函数

目录

1. __init__

2. __new__

3. __call__

4.类执行顺序

4. __iter__和__next__

5. __str__和 __repr__和__doc__

5.1 __str__

5.2 __repr__

5.3 __doc__

6. __mro__

7. __get__和__set__和__delete__ 

7.1 __get__

7.2 __set__

7.3 __delete__

8. __getattr__和__setattr__和__delattr__

8.1 __getattr__

8.2 __setattr__

8.3 __delatrr__

9. __getitem__和__setitem__和__delitem__

9.1 __getitem__

9.2 __setitem__

9.3 __delitem__

10. __getattribute__

11. __dict__

12. __file__

13. __name__


1. __init__

在类准备将自身实例化时调用

class Person(object):
    """Silly Person"""

    def __new__(cls,*args,**kwargs):
        print('__new__ called.')
        return super(Person, cls).__new__(cls)

    def __init__(self, name, age):
        print('__init__ called.')
        self.name = name
        self.age = age


if __name__ == '__main__':
    piglei = Person('piglei', 24)
    print(piglei)
    
# 执行结果
    __new__ called.
    __init__ called.
    <__main__.Person object at 0x7fe8524f0ac8>

2. __new__

在类准备将自身实例化时调用

用途:单例模式 

class Person(object):
    """Silly Person"""

    def __new__(cls,*args,**kwargs):
        print('__new__ called.')
        return super(Person, cls).__new__(cls)

    def __init__(self, name, age):
        print('__init__ called.')
        self.name = name
        self.age = age


if __name__ == '__main__':
    piglei = Person('piglei', 24)
    print(piglei)
    
# 执行结果
    __new__ called.
    __init__ called.
    <__main__.Person object at 0x7fe8524f0ac8>

3. __call__

类对象当作函数直接调用

class test(object):
    def __call__(self,num):
            print(num)
obj = test()
obj(5)                    #重点,其实例对象可以像函数一样被调用

# 结果:5

4.类执行顺序

  1. 创建类 ==》先执行type的__init__方法
  2. 类实例化(创建对象),执行type的__call__方法,__call__方法的返回值就是实例化的对象
    1. __call__内部调用
      1. 类.__new__方法,创建一个对象
      2. 类.__init__方法,初始化对象
class Person(object):
    """Silly Person"""

    def __new__(cls,*args,**kwargs):
        print('__new__ called.')
        return super(Person, cls).__new__(cls)

    def __init__(self, name, age):
        print('__init__ called.')
        self.name = name
        self.age = age


if __name__ == '__main__':
    piglei = Person('piglei', 24)
    print(piglei)
    
# 执行结果
    __new__ called.
    __init__ called.
    <__main__.Person object at 0x7fe8524f0ac8>

4. __iter__和__next__

python的可迭代对象实现

class Fib(object):
    def __init__(self):
        self.a, self.b = 0, 1

    def __iter__(self):
        return self

    def __next__(self):
        self.a, self.b = self.b, self.a + self.b
        if self.a > 1000:
            raise StopIteration()
        return self.a

for n in Fib():
    print(n)

5. __str__和 __repr__和__doc__

作用就是:注释

5.1 __str__

返回一个对象的描述信息

实际上str只是覆盖了repr以得到更友好的用户显示

服务对象:面向用户

class Cat:
    def __init__(self, new_name, new_age):
        self.name = new_name
        self.age = new_age

    def __str__(self):
        """返回一个对象的描述信息"""
        return "名字是:%s , 年龄是:%d" % (self.name, self.age)

tom = Cat("汤姆", 30)
print(tom)			# 名字是:汤姆 , 年龄是:30

5.2 __repr__

默认情况:返回对象的信息(类名+object at + 内存地址)

服务对象:面向程序

class Cat:
    def __init__(self, new_name, new_age):
        self.name = new_name
        self.age = new_age

    def __repr__(self):
        """返回一个对象的描述信息"""
        return "名字是:%s , 年龄是:%d" % (self.name, self.age)

# 创建了一个对象
tom = Cat("汤姆", 30)
print(tom)			# 名字是:汤姆 , 年龄是:30

5.3 __doc__

类中的注释内容

class test():
    """这是一段注释"""
    a = ""

t = test()
print(t.__doc__)   # 这是一段注释

6. __mro__

处理继承类中子类、父类中的方法/属性调用顺序

class A():pass

class B():pass

class C(A,B):pass
print(C.__mro__)	

#结果: (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)

7. __get__和__set__和__delete__ 

8. __getattr__和__setattr__和__delattr__

调用类属性的方法

# 在这例子中,参考了`flask源码中`的`线程间的数据隔离`

import threading
import time
try:
    import greenlet
    get_ident = greenlet.getcurrent
except Exception as e:
    get_ident = threading.get_ident
class Local(object):
    DIC = {}
    def __getattr__(self, item):
        ident = get_ident()
        if ident in self.DIC:
            return self.DIC[ident].get(item)
        return None

    def __setattr__(self, key, value):
        ident = get_ident()
        if ident in self.DIC:
            self.DIC[ident][key] = value
        else:
            self.DIC[ident] = {key:value}

import threading
import time
obj = Local()
def task(i):
    obj.xx = i
    time.sleep(2)
    print(obj.xx,i)
for i in range(3):
    t = threading.Thread(target=task,args=(i,))
    t.start()
    
    
# 结果
    1 1
    3 3
    2 2

9. __getitem__和__setitem__和__delitem__

类的字典调用方法

class A(object):
    def __init__(self):
        self['B'] = "BB"
        self['D'] = "DD"
        del self['D']

    def __setitem__(self, name, value):
        '''''
        @summary: 每当属性被赋值的时候都会调用该方法,因此不能再该方法内赋值 self.name = value 会死循环
        '''
        print("__setitem__:Set %s Value %s" % (name, value))
        self.__dict__[name] = value

    def __getitem__(self, name):
        ''''' 
        @summary: 当访问属性时会调用该方法
        '''
        print("__getitem__:No attribute named '%s'" % name)
        return None

    def __delitem__(self, name):
        ''''' 
        @summary: 当删除属性时调用该方法
        '''
        print("__delitem__:Delect attribute '%s'" % name)
        del self.__dict__[name]
        print(self.__dict__)


if __name__ == "__main__":
    X = A()
    b = X['bb']
    
    
# 结果
    __setitem__:Set B Value BB
    __setitem__:Set D Value DD
    {'B': 'BB', 'D': 'DD'}

10. __getattribute__

  • 对于类来说,type.__getattribute__()把B.x变成B.__dict__['x'].__get__(None,B)内部实现

    • def __getattribute__(self, key):
          "Emulate type_getattro() in Objects/typeobject.c"
          v = object.__getattribute__(self, key)
          if hasattr(v, '__get__'):
              return v.__get__(None, self)
          return v
    • 描述符被__getattribute__()方法调用

    • 重载__getattribute__()会阻止描述符自动调用

    • __getattribute__()只使用于新式类和对象

    • 数据描述符会重载实例字典

    • 非数据描述符可能会被实例字典重载

  • super()返回的对象会使用定制 __getattribute__()方法来调动描述符,调用super(B,obj).m()会紧邻着B的基类A搜索obj.__class__.__mro__

  • 然后返回A.__dict__['m'].__get__(obj,B)

    • 如果不是一个描述符,返回未改变的m

    • 如果不在字典中,m会调用object.__getattribute__()查询

11. __dict__

存储对象的数据

class A():
    def __init__(self):
        self.a = 2
        self.b = 3

    def test(self):
        print('a normal func.')

obj = A()
print(obj.__dict__)		# {'a': 2, 'b': 3}
print(A.__dict__)	
"""
{'__module__': '__main__',
	'__init__': <function A.__init__ at 0x7f541b16a268>, 
     'test': <function A.test at 0x7f541b16a378>, 
     '__dict__': <attribute '__dict__' of 'A' objects>,
     '__weakref__': <attribute '__weakref__' of 'A' objects>, 
     '__doc__': None
 }
 """

12. __file__

执行py文件时,默认把当前目录增加到sys.path中

test.py    #当前目录为  D:\user\flask\test.py
    import os
    print(__file__)

>>>  python test.py
结果:test.py

带上文件的绝对路径
>>> python D:\user\flask\test.py
结果:D:\user\flask\test.py

13. __name__

标识执行文件的模块名

test.py
    def run():
        print(__name__)
    if __name__ == __main__:
        print(__name__)				# __main__
        
test2.py
    import test
    test.run()			# test

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值