7.16. 一些魔法方法

7.16.1. __call__方法

eg:

#!/usr/bin/env python
#-*- coding:utf8 -*-
class DistanceFrom(object):
    def __init__(self,orage):
        self.orage = orage

    def __call__(self, x):
        return abs(x + self.orage)

number = [1, 2, 3, 4, 5, 6, 7]
hu = DistanceFrom(10)
for i in number:
    print(hu(2)+i)

eg:

#!/usr/bin/env python
#-*- coding:utf8 -*-
class Prod:
    def __init__(self, data):
        self.data = data

    def __call__(self, other):
        return self.data * other


x = Prod(2)
print(x(3))         #6
print(x(4))         #8

7.16.2. __doc__方法

#!/usr/bin/env python
#-*- coding:utf8 -*-
class Func():
    """
    这里显示的是描述信息
    """
    def func(self):
        pass

print(Func.__doc__)

7.16.3. __del__方法

析构函数是构造函数的反向函数,析构函数往往用来做“清理善后”的工作,例如数据库链接对象可以在析构函数中释放对象数据库资源的占用,是一个没有返回值和参数的函数。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @auther:   18793
# @Date:    2020/12/15 20:23
# @filename: 03.py
# @Email:    1879324764@qq.com
# @Software: PyCharm


class MyClass(object):
    message = "Hello,Developer."

    def show(self):
        print(self.message)

    def __init__(self, name="unset", color="black"):
        print("Construcotor is called with param: ", name, " ", color)

    def __del__(self):
        print("开始清理工作")


if __name__ == '__main__':
    inst = MyClass()
    inst.show()

    inst2 = MyClass("hujianli")
    inst2.show()

    del inst, inst2

    inst3 = MyClass("huxiaojian", "yellow")
    inst3.show()

    del inst3

7.16.4. __getitem__方法

#!/usr/bin/env python
#-*- coding:utf8 -*-
class Company(object):
    def __init__(self,employee_list):
        self.employee = employee_list

    def __getitem__(self, item):
        # print(self.employee[item])
        return self.employee[item]

company = Company(['11','22','33'])
a = ["derek1","derek2"]
name_set = set()

name_set.add("hujianli1")
name_set.add("hujianli2")

##extend里面可以添加任何可迭代的参数,给类添加一个魔法函数__getitem__,类就变成可迭代的,所以可以extend进去
a.extend(company)
print(a)

a.extend(name_set)
print(a)

7.16.5. __init__方法和__new__方法的区别

#!/usr/bin/env python
#-*- coding:utf8 -*-
'''
__new__方法如果不返回对象,不会执行init方法
'''
'''
class User:
    def __new__(cls, *args, **kwargs):
        print("in new")

    def __init__(self,name):
        print("in init")
        self.name = name

# new是用用来控制对象的生成过程,在对象生成之前
# init是用来完善对象的
# 如果new方法不返回对象,则不会调用init函数
if __name__ == '__main__':
    user = User("derek")
'''


class User:
    def __new__(cls, *args, **kwargs):
        print("in new")         #in new
        print(cls)              #cls是当前class对象    <class '__main__.User'>
        print(type(cls))        #<class 'type'>
        return super().__new__(cls)   #必须返回class对象,才会调用__init__方法

    def __init__(self, name):
        print("in init")        #in init
        print(self)             #self是class的实例对象      <__main__.User object at 0x00000000021B8780>
        print(type(self))       #<class '__main__.User'>
        self.name = name

# new是用用来控制对象的生成过程,在对象生成之前
# init是用来完善对象的
# 如果new方法不返回对象,则不会调用init函数
if __name__ == '__main__':
    user = User(name="derek")

#总结
# __new__ 用来创建实例,在返回的实例上执行__init__,如果不返回实例那么__init__将不会执行
# __init__ 用来初始化实例,设置属性什么的

7.16.6. __slots__限制实例的变量

#!/usr/bin/env python
#-*- coding:utf8 -*-
"""
可以使用__slots__限制实例的变量,比如,只允许Foo的实例添加name和age属性
"""
def print_doc(self):
    print("哈哈")

class Foo:
    __slots__ = ("name","age")
    pass

class AAA(object):
    pass

object1 = Foo()
object2 = Foo()

#动态添加实例变量
object1.name = "hujianli"
object2.age = 18

# object.sex = "man"

Foo.show = print_doc
object1.show()
object2.show()

#因为内部有__slots__限制实例的变量
print(Foo.__dict__)

节省内存空间,限制实例只能设置特定的属性,但不限制类来添加动态的属性

class Dog:
    __slots__ = ["walk", "walk2", "age", "name"]

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


def hujianli(self):
    print("预先定义的hujianli方法")
    print("【{}】正在慢慢走向你".format(self.name))


d = Dog("Snoopy")

from types import MethodType

# 只允许为实例动态添加walk、age、name这三个属性或方法
d.walk = MethodType(hujianli, d)
d.walk2 = MethodType(lambda self, one_arg: print("这是lambda函数,Dog name is 【{}】 "
                                                 "传入参数:{}".format(self.name, one_arg)), d)
d.age = 5
d.walk()
d.walk2("参数测试1")
print()
print()
print("但不限制类来添加动态的属性,使用类来动态定义bar方法,正常输出")
# 但不限制类来添加动态的属性,使用类来动态定义bar方法,正常输出
Dog.bar = MethodType(hujianli, d)
Dog.bar()
# d.foo = 30      # 报错

输出结果:

预先定义的hujianli方法
【Snoopy】正在慢慢走向你
这是lambda函数,Dog name is 【Snoopy】 传入参数:参数测试1


但不限制类来添加动态的属性,使用类来动态定义bar方法,正常输出
预先定义的hujianli方法
【Snoopy】正在慢慢走向你

__slots__属性指定的限制只对当前的类的实例起作用,对子类不起作用。

class GunDog(Dog):
    def __init__(self,name):
        super(GunDog, self).__init__(name)
        pass


hujianli_Class = GunDog("hujianli")
hujianli_Class.speed = 99
print(hujianli_Class.speed)

7.16.7. __str__和__repr__的使用

#!/usr/bin/env python
#-*- coding:utf8 -*-
'''
__str__()
__repr__()
'''

class Ppersopn(object):
    def __init__(self,name,age,height,weight):
        self.name = name
        self.age = age
        self.height = height
        self.weight = weight

    def __str__(self):
        return "age:{0} name:{1} height:{2} weight:{3}".format(self.name,self.age,self.height,self.weight)

per =Ppersopn("hanmeimei", 18, 170, 60)
print(per)

'''
___str__()调用时使用,是给用户用的,是一个描述对象的方法
__repr__()给机器用的,在python解释器里面直接敲对象名称在
回车后调用的方法,
注意:在没有str时,且有__repe__  str=repr

当一个对象的属性值很多,都需要打印时,
重写了__str__后,简化了代码
'''

eg

#!/usr/bin/env python
# -*- coding:utf8 -*-
# auther; 18793
# Date:2019/5/15 16:02
# filename: repr方法.py
class Apple:
    # 实现构造方法
    def __init__(self, color, weight):
        self.color = color
        self.weight = weight

    def __repr__(self):
        '''
        重写__repr__()方法,实现Apple对象的“自我描述”
        :return:
        '''
        return "Apple[color=" + self.color + ", weight=" + str(self.weight) + "]"


if __name__ == '__main__':
    hu = Apple("红色", 5.68)
    print(hu)

7.16.8. 构造方法和__del__析构方法

#!/usr/bin/env python
#-*- coding:utf8 -*-
class Test(object):
    def __init__(self):
        print("这个是构造函数....")

    def __del__(self):
        print("这个是析构函数....,结束时自动调用...")

hu = Test()

eg

#!/usr/bin/env python
# -*- coding:utf8 -*-
# auther; 18793
# Date:2019/5/15 16:08
# filename: del 析构方法.py

class Item:
    def __init__(self, name, price):
        self.name = name
        self.price = price

    def __del__(self):
        print("del删除对象")


if __name__ == '__main__':
    im = Item("鼠标", 29.8)
   # x = im     #如果注释掉这里,将先打印---del删除对象--

    #打印im所引用的Item对象
    del im
    print("------------------------------")

7.16.9. __dir__()方法,列出所有属性和方法

#!/usr/bin/env python
# -*- coding:utf8 -*-
# auther; 18793
# Date:2019/5/15 16:14
# filename: __dir__方法.py
"""
查看内置属性和方法和所有定义的属性和方法组成列表。
"""
class Item:
    def __init__(self, name, price):
        self.name = name
        self.price = price

    def info(self):
        pass


if __name__ == '__main__':
    im = Item("鼠标", 29.8)
    print(im.__dir__())
    print(dir(im))

7.16.10. 运算符重载_add_

#!/usr/bin/env python
#-*- coding:utf8 -*-

class Complex(object):
    def __init__(self, real, imag=0):
        self.real = real
        self.imag = imag

    def __repr__(self):
        return "Complex(%s, %s)" %(self.real,self.imag)

    def __str__(self):
        return "(%g+%gj)" %(self.real,self.imag)

    #self + other
    def __add__(self, other):
        return Complex(self.real + other, self.imag + other)
    #self - other
    def __sub__(self, other):
        return Complex(self.real - other, self.imag - other)

if __name__ == '__main__':
    c = Complex(4, 2)
    print(c)
#!/usr/bin/env python
#-*- coding:utf8 -*-

#自定义类实现类的特别的运算方式

class Book:

    def __init__(self,name="python入门到精通"):
        self.name = name

    def __add__(self, other):
        #加运算
        return self.name + ' add ' + other.name        #得到书名相加

    def __len__(self):
        return len(self.name)

if __name__ == '__main__':
    booka = Book()
    bookb = Book('Java入门到精通')
    print("len(booka):",len(booka))
    print("len(bookb):",len(bookb))
    print(booka + bookb)

7.16.11. is 判断对象是否属于相同的对象

#!/usr/bin/env python
#-*- coding:utf8 -*-
# auther; 18793
# Date:2019/6/10 23:07
# filename: is魔法方法.py
class Person():
    def __init__(self):
        self.name = "Bob"


bob = Person()
same_bob = bob

print(same_bob is bob)


other_bob = Person()
print(other_bob is bob)

7.16.12. 其他一些魔法方法

#!/usr/bin/env python
#-*- coding:utf8 -*-
'''
和比较相关的魔术方法
__eq__(self, other) self == other
__ne__(self, other) self != other
__lt__(self, other) self < other
__gt__(self, other) self > other
__le__(self, other) self <= other
__ge__(self, other) self >= other

和数学相关的魔术方法
__add__(self, other) self + other
__sub__(self, other) self - other
__mul__(self, other) self * other
__floordiv__(self, other) self // other
__truediv__(self, other) self / other
__mod__(self, other) self % other
__pow__(self, other) self ** other
'''

class Word():
    def __init__(self,text):
        self.text = text

    # def __eq__(self, other):
    #     if self.text.lower() == other.lower():
    #         print("True")
    #     else:
    #         print("False")

    def __add__(self, other):
        if isinstance(self.text, int):
            return self.text + other
        else:
            return False

    # def __str__(self):
    #     return self.text

    def __repr__(self):
        return 'Word("self.text")'

first = Word(10)
first.__eq__(10)
print(first)

add = first.__add__(20)
print(add)

eg

#!/usr/bin/env python
# -*- coding:utf8 -*-
# auther; 18793
# Date:2019/6/15 14:40
# filename: 比较运算符.py
class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height

    # 定义setSize()函数
    def setSize(self, size):
        self.width, self.height = size

    # 定义getSize()函数
    def getSize(self):
        return self.width, self.height

    # 使用property定义属性
    size = property(getSize, setSize)

    # 定义gt方法
    def __gt__(self, other):
        # 判断是否是Rectangle
        if not isinstance(other, Rectangle):
            raise TypeError(">比较要求目标是Rectangle")
        return True if self.width * self.height > other.width * other.height else False

    # 定义eq方法
    def __eq__(self, other):
        # 判断是否是Rectangle
        if not isinstance(other, Rectangle):
            raise TypeError("==比较要求目标是Rectangle")
        return True if self.width * self.height == other.width * other.height else False

    # 定义ge方法
    def __ge__(self, other):
        # 判断是否是Rectangle
        if not isinstance(other, Rectangle):
            raise TypeError(">=比较要求目标是Rectangle")
        return True if self.width * self.height >= other.width * other.height else False


    def __repr__(self):
        return "Rectangle(width={},height={})".format(self.width, self.height)


r1 = Rectangle(4, 5)
r2 = Rectangle(3, 4)
print(r1 > r2)
print(r1 == r2)
print(r1 >= r2)
print(r1 != r2)

r3 = Rectangle(2, 6)
print(r2 > r3)
print(r2 == r3)
print(r2 >= r3)
print(r2 != r3)
print(r1)
print(r2)
print(r3)

输出信息

True
False
True
True
False
True
True
False
Rectangle(width=4,height=5)
Rectangle(width=3,height=4)
Rectangle(width=2,height=6)

7.16.13. __getattr__和__getattribute__的区别

#!/usr/bin/env python
#-*- coding:utf8 -*-
'''
object.__getattr__(self, name)
找不到attribute的时候,会调用getattr,返回一个值或AttributeError异常。

object.__getattribute__(self, name)
无条件被调用,通过实例访问属性。如果class中定义了__getattr__(),则__getattr__()不会被调用(除非显示调用或引发AttributeError异常)
'''

class User:
    def __init__(self, info={}):
        self.info = info

    #__getattr__是在查找不到属性的时候调用
    def __getattr__(self, item):
        return self.info[item]

    #__getattribute不管属性存不存在,都访问这个
    def __getattribute__(self, item):
        return "zhang_derek"


if __name__ == '__main__':
    user = User(info={"name":"derek","age":24})
    #不管属性存不存在,都走__getattribute__
    print(user.name)    #zhang_derek     #即使属性存在也走__getattribute__
    print(user.test)     #zhang_derek    #不存在的属性也能打印
    print(user.company)   #zhang_derek   #不存在的属性也能打印

7.16.14. __setattr__、__getattr、__getattribute、__delattr__ 方法

  • __setattr__(self,name,value):如果要给name赋值,就调用这个方法。

  • __getattr__(self,name):如果name被访问,同时它不存在,此方法被调用。

  • __getattribute__(self,name):当name被访问时自动被调用(注意:这个仅能用于新式类),无论name是否存在,都要被调用。

  • __delattr__(self,name):如果要删除name,这个方法就被调用。

#!/usr/bin/env python
#-*- coding:utf8 -*-
class Bird(object):
    feather = True

class chicken(Bird):
    fly = False
    def __init__(self,age):
        self.age = age

    def __getattr__(self, item):
        if item == "hujianli":
            if self.age > 1.0:
                return True
            else:
                return False
        else:
            return AttributeError(item)


if __name__ == '__main__':
    hu = chicken(10)
    print(hu.hujianli)          #True

    hu.age = 0.2
    print(hu.hujianli)          #False

    print(hu.jian)

eg

#!/usr/bin/env python
# -*- coding:utf8 -*-
# auther; 18793
# Date:2019/6/15 2:54
# filename: getattr和setattr.py
class Rectangle:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __setattr__(self, key, value):
        # print("--------设置{}属性-----".format(key))
        if key == "name":
            if 2 < len(value) <= 8 or len(value) > 8:
                self.__dict__["name"] = value
            else:
                raise ValueError("name 的长度必须在2~8之间")
        elif key == "age":
            if 10 < value < 60:
                self.__dict__["age"] = value
            else:
                raise ValueError("age必须在10~60之间")


if __name__ == '__main__':
    hu = Rectangle("huajianli", 20)
    print(hu.name)
    print(hu.age)
    hu.age = 12
    hu.name = "huj"
    print(hu.name)
    # hu.age = 2  #报错