• python16个魔法函数


    1、__ init__():

    所有类的超类object,有一个默认包含pass的__ init __()实现,这个函数会在对象初始化的时候调用,我们可以选择实现,也可以选择不实现,一般建议是实现的,不实现对象属性就不会被初始化,虽然我们仍然可以对其进行赋值,但是它已经成了隐式的了,编程时显示远比隐式的更好,看下面的小栗子:

    class test_1:
      def method(self):
        self.a = "1"
        self.b = "2"
        return self.a,self.b
    
    class test_2:
      def __init__(self):
        self.a = "1"
        self.b = "2"
    
      def method(self):
        return self.a,self.b
    
    print(vars(test_1()))
    print("-"*10)
    print(vars(test_2()))
    """
    {}
    ----------
    {'a': '1', 'b': '2'}
    """

    我们可以通过vars函数获知显示声明的属性,但是隐式的就无法获知了,这并不值得提倡,但是在知道参数的情况下我们还是可以对其进行赋值的,如下:

    class test_1:
      def method(self):
        return self.a, self.b
    
    
    class test_2:
      def __init__(self):
        self.a = "1"
        self.b = "2"
    
      def method(self):
        return self.a, self.b
    
    
    t1 = test_1()
    t1.a = 1
    t1.b = 2
    print(t1.method())  # (1, 2)
    print('-' * 10)
    t2 = test_2()
    t2.a = 3
    t2.b = 4
    print(t2.method())  # (3, 4)

    2、__ str__():

    直接打印对象的实现方法,__ str__是被print函数调用的,一般都是return一个什么东西,这个东西应该是以字符串的形式表现的。如果不是要用str()函数转换,我们可以直接print的对象都是实现了__ str__这个方法的,比如dict。看下面的例子。

    print(dir({}))
    """
    ['__class__', '__contains__', '__delattr__', '__delitem__', 
    '__dir__', '__doc__', '__eq__', '__format__', '__ge__', 
    '__getattribute__', '__getitem__', '__gt__', '__hash__', 
    '__init__', '__init_subclass__', '__iter__', '__le__', 
    '__len__', '__lt__', '__ne__', '__new__', '__reduce__', 
    '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', 
    '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 
    'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 
    'update', 'values']
    """
    __ str__是dict其中的一个方法,这个方法的实现赋予了它直接被print的能力,知道这些,我们就可以给自己的类定义这个方法使其可以print了,例子如下:
    class test:
      def __init__(self):
        self.a = "1"
    
      def __str__(self):
        return "this is a str magic method,self.a=" + str(self.a)
    
    
    print(test())
    # this is a str magic method,self.a=1

    但是这个函数返回值必须为string,否则会抛异常:

    class test:
      def __init__(self):
        self.a = 1
    
      def __str__(self):
        return self.a
    
    print(test())
    """
    Traceback (most recent call last):
      File "/test/test.py", line 9, in <module>
        print(test())
    TypeError: __str__ returned non-string (type int)
    
    """

    3、__ new__():

    在object类中存在一个静态的__ new__(cls, *args, **kwargs)方法,该方法需要传递一个参数cls,cls表示需要实例化的类,此参数在实例化时由Python解释器自动提供,__ new__方法必须有返回值,且返回的是被实例化的实例,只有在该实例返回后才会调用__ init__来进行初始化,初始化所用的实例就是__ new__返回的结果,也就可以认为是self,我们来看下面的例子:

    class test:
      def __init__(self):
        print('start init ...')
        self.a = 1
    
      def __new__(cls, *args, **kwargs):
        print('create a instance {%s}' % cls)
        return object.__new__(cls,*args,**kwargs)
    
    test()
    """
    create a instance {<class '__main__.test'>}
    start init ...
    """

    可以看到,在实例化时候,先执行__ new__再执行__ init__,而且python会自动传入我们希望实例化的类,这里我们显示的调用了object的__ new__,也可以调用其他的父类的__ new__,那么如果我们定义了__ new__,但是并没有返回一个本身实例,会发生什么事呢?例子如下:

    class test:
      def __init__(self):
        print('start init ...')
        self.a = 1
    
      def __new__(cls, *args, **kwargs):
        print('create a instance {%s}' % cls)
        return "abc"
    
    test()
    # create a instance {<class '__main__.test'>}

    可以看到本身的__ init__函数并未被调用,而是调用了str的__ init__,可能这样并不直观,那么换一个实例返回,如下:

    class obj:
      def __init__(self):
        print('another object called')
    
    
    class test:
      def __init__(self):
        print('start init ...')
    
      def __new__(cls, *args, **kwargs):
        print('create a instance {%s}' % cls)
        test_new = obj()
        return test_new
    
    test()
    """
    create a instance {<class '__main__.test'>}
    another object called
    """

    这个就比较明显了,另一个实例的__ init__被调用了。

    4、__ unicode__():

    __ unicode__()方法是在一个对象上调用unicode()时被调用的。因为Django的数据库后端会返回Unicode字符串给model属性,所以我们通常会给自己的model写一个__ unicode__()方法。如果定义了__ unicode__()方法但是没有定义__ str__()方法,Django会自动提供一个__ str__()方法调用 __ unicode__()方法,然后把结果转换为UTF-8编码的字符串对象,所以在一般情况下,只定义__ unicode__()方法,让 Django来处理字符串对象的转换,看一个小栗子:

    class test:
      def __init__(self):
        self.a = 1
    
      def __unicode__(self):
        return "the value is {%s}" % self.a
    
    print(test().__unicode__())
    # the value is {1}

    在django中,虽然没有定义__ str__,但是django会将__ unicode__转为了str,当然你调用unicode更加是没有问题的。

    5、__ call__():

    对象通过提供call()方法可以模拟函数的行为,如果一个对象提供了该方法,就可以像函数一样使用它,还是用例子进行说明。

    class test:
      def __init__(self):
        self.a = 1
    
      def __call__(self, x):
        return "the value is {%s}" % x
    
    b = test()
    print(b(100))
    # the value is {100}

    可以看到,我们在像使用函数一样使用类,实在是很有意思的事。

    6、__ len__():

    len调用后会调用对象的__ len__函数,我们可以为其定制输出,如下例子:

    class test:
      def __init__(self):
        self.a = [1, 2, 3, 4, 5]
    
      def __len__(self):
        return len(self.a) + 100
    
    b = test()
    print(len(b))  # 105
    print(type(len(b))) #<class 'int'>

    但是该函数要求我们返回的值必须为int,否则会报错,如下:

    class test:
      def __init__(self):
        self.a = [1, 2, 3, 4, 5]
    
      def __len__(self):
        return str(len(self.a) + 100)
    
    b = test()
    print(len(b))
    """
    Traceback (most recent call last):
      File "/test/test.py", line 10, in <module>
        print(len(b))  # 105
    TypeError: 'str' object cannot be interpreted as an integer
    """

    7、__ repr__():

    函数str() 用于将值转化为适于人阅读的形式,而repr() 转化为供解释器读取的形式,某对象没有适于人阅读的解释形式的话,str() 会返回与repr(),所以print展示的都是str的格式。例子:

    class test:
        def __init__(self):
            self.a = (1, 2, 3, 4, 5)
    
        def __str__(self):
            return 'this is a string ' + str(len(self.a) + 100)
    
        def __repr__(self):
            return str(len(self.a) + 100)
    
    print(test())  # this is a string 105
    print('%r' % test())  # 105
    print(repr(test()))  # 105

    8、__ setattr__():

    该函数可以设置函数的属性,文字不知怎么描述,直接上例子

    class test:
        def __setattr__(self, name, value):
            if name == "a":
                object.__setattr__(self, name, value + 50)
            if name == "b":
                object.__setattr__(self, name, value - 30)
    
    set_attr = test()
    set_attr.a = 100
    set_attr.b = 200
    print(vars(set_attr))
    # {'a': 150, 'b': 170}

    从上例可以看出,__setattr__函数可以支持对象增加属性,我们可以有计划的修改增加属性的内容。

    class test:
        def __init__(self):
            self.a = (1, 2, 3, 4, 5)
    
        def __str__(self):
            return 'this is a string ' + str(len(self.a) + 100)
    
        def __repr__(self):
            return str(len(self.a) + 100)
    
    print(test())  # this is a string 105
    print('%r' % test())  # 105
    print(repr(test()))  # 105

    9、__ getattr__():

    获取对象属性,只有在属性没有找到的时候调用,还是看例子:

    class ob:
        def __init__(self):
            self.o = 5
    
    
    class test:
        def __init__(self):
            self.a = 5
    
        def __setattr__(self, name, value):
            if name == "a":
                object.__setattr__(self, name, value + 50)
            if name == "b":
                object.__setattr__(self, name, value - 30)
    
        def __getattr__(self, name):
            a = ob()
            print("can not find attr %s" % name)
            return a.__getattribute__(name)
    
    set_attr = test()
    set_attr.a = 100
    set_attr.b = 200
    print(set_attr.a)  # 150
    print("*" * 10)
    print(set_attr.o)
    # can not find attr o
    # 5

    10、__ getattrbute__():

    该函数和上面介绍的__getattr__很像,都是获取属性,但是__getattr__实在属性不存在的时被调用,而__getattrbute__是无条件被调用,这样会方便我们做一些控制,需要注意,一旦定义了__getattrbute__,则__getattr__不再会被调用,除非显示调用,例子如下:

    class ob:
        def __init__(self):
            self.o = 5
    
    class test:
    
        def __setattr__(self, name, value):
            if name == "a":
                object.__setattr__(self, name, value + 50)
            if name == "b":
                object.__setattr__(self, name, value - 30)
    
        def __getattribute__(self, name):
            try:
                ret = object.__getattribute__(self, name)
                print("attr %s exsited" % name)
                return ret
            except:
                a = ob()
                print("can not find attr %s" % name)
                return a.__getattribute__(name)
    
    set_attr = test()
    set_attr.a = 100
    set_attr.b = 200
    print(set_attr.a)
    # attr a exsited
    # 150
    print("-" * 10)
    print(set_attr.o)
    # can not find attr o
    # 5
  • 相关阅读:
    人脸识别(Unseen Domains)
    人脸识别(Unseen Domains)
    人脸聚类
    人脸聚类
    人脸聚类
    人脸检测和识别以及检测中loss学习
    Embedding-based Retrieval in Facebook Search
    Spring Cloud Alibaba(1)---入门篇
    2020Android面经,历时一个半月,斩获3个大厂offer
    【算法总结】递归和非递归实现二叉树的先序,中序,后序遍历
  • 原文地址:https://www.cnblogs.com/maplethefox/p/11568106.html
Copyright © 2020-2023  润新知