• Task07:类、对象与魔法方法(3天)


    目录

    我把目录折叠起来了,如果需要查看直接点击

    一、类于对象
    
    1.对象=属性+方法
    
    2.self是什么?
    
    3.python的魔法方法
    
    4.公有和私有
    
    5.继承
    
    6.组合
    
    7.类、类对象和实例对象
    
    8.什么是绑定
    
    9.一些相关的内置函数(BIF)
    
    二、魔法方法
    
    1.基本的魔法方法
    
    2.算术运算符
    
    3.反算术运算符
    
    4.增量赋值运算符
    
    5.一元运算符
    
    6.属性访问
    
    7.描述符
    
    8.定制序列
    
    9.迭代器
    
    10.生成器
    View Code

     一、类于对象

    1.对象=属性+方法

    1.1对象是类的实例

    我们可以使用关键字 class 定义 Python 类,关键字后面紧跟类的名称、分号和类的实现

    class Turtle:  # Python中的类名约定以大写字母开头
        """关于类的一个简单例子"""
        # 属性
        color = 'green'
        weight = 10
        legs = 4
        shell = True
        mouth = '大嘴'
    
        # 方法
        def climb(self):
            print('我正在很努力的向前爬...')
    
        def run(self):
            print('我正在飞快的向前跑...')
    
        def bite(self):
            print('咬死你咬死你!!')
    
        def eat(self):
            print('有得吃,真满足...')
    
        def sleep(self):
            print('困了,睡了,晚安,zzz')
    
    
    tt = Turtle()
    print(tt)
    # <__main__.Turtle object at 0x0000007C32D67F98>
    
    print(type(tt))
    # <class '__main__.Turtle'>
    
    print(tt.__class__)
    # <class '__main__.Turtle'>
    
    print(tt.__class__.__name__)
    # Turtle
    
    tt.climb()
    # 我正在很努力的向前爬...
    
    tt.run()
    # 我正在飞快的向前跑...
    
    tt.bite()
    # 咬死你咬死你!!
    
    # Python类也是对象。它们是type的实例
    print(type(Turtle))
    # <class 'type'>

    1.2继承:子类自动共享父类之间数据和方法的机制

    class MyList(list):  #list本身也是一个类
        pass
    
    
    lst = MyList([1, 5, 2, 7, 8])
    lst.append(9)  #继承了list的append的方法
    lst.sort()
    print(lst)
    
    # [1, 2, 5, 7, 8, 9]

    1.3多态:不同对象对同一方法响应不同的行动

    class Animal:
        def run(self):
            raise AttributeError('子类必须实现这个方法')
    
    
    class People(Animal):
        def run(self):
            print('人正在走')
    
    
    class Pig(Animal):
        def run(self):
            print('pig is walking')
    
    
    class Dog(Animal):
        def run(self):
            print('dog is running')
    
    
    def func(animal):
        animal.run()
    
    
    func(Pig())
    # pig is walking

    2.self是什么?

    python的self相当于c++的this指针

    class Test:
        def prt(self):
            print(self)
            print(self.__class__)
    
    
    t = Test()
    t.prt()
    # <__main__.Test object at 0x000000BC5A351208>
    # <class '__main__.Test'>

    类的方法和普通函数只有一个区别,类的方法第一个参数名称是self

    class Ball:
        def setName(self, name):
            self.name = name
    
        def kick(self):
            print("我叫%s,该死的,谁踢我..." % self.name)
    
    
    a = Ball()
    a.setName("球A")
    b = Ball()
    b.setName("球B")
    c = Ball()
    c.setName("球C")
    a.kick()
    # 我叫球A,该死的,谁踢我...
    b.kick()
    # 我叫球B,该死的,谁踢我...

    3.python的魔法方法

    类有一个__init__(self [, 参数1,参数2..])的魔法方法,该方法在类实例化时会自动调用

    class Ball:
        def __init__(self, name):
            self.name = name
    
        def kick(self):
            print("我叫%s,该死的,谁踢我..." % self.name)
    
    
    a = Ball("球A")
    b = Ball("球B")
    c = Ball("球C")
    a.kick()
    # 我叫球A,该死的,谁踢我...
    b.kick()
    # 我叫球B,该死的,谁踢我...

    4.公有和私有

    我这篇文章有详细的介绍https://www.cnblogs.com/cgmcoding/p/13300909.html

    python中定义私有变量只需要在变量名或者函数名前加上__两个下划线

    私有变量,自然是外部不能访问,只有内部可以访问

    class JustCounter:
        __secretCount = 0  # 私有变量
        publicCount = 0  # 公开变量
    
        def count(self):
            self.__secretCount += 1
            self.publicCount += 1
            print(self.__secretCount)
    
    
    counter = JustCounter()
    counter.count()  # 1
    counter.count()  # 2
    print(counter.publicCount)  # 2
    
    print(counter._JustCounter__secretCount)  # 2 Python的私有为伪私有
    print(counter.__secretCount)   #不能访问
    # AttributeError: 'JustCounter' object has no attribute '__secretCount'

    私有方法,外部也是不能访问的

    class Site:
        def __init__(self, name, url):
            self.name = name  # public
            self.__url = url  # private
    
        def who(self):
            print('name  : ', self.name)
            print('url : ', self.__url)
    
        def __foo(self):  # 私有方法
            print('这是私有方法')
    
        def foo(self):  # 公共方法
            print('这是公共方法')
            self.__foo()
    
    
    x = Site('老马的程序人生', 'https://blog.csdn.net/LSGO_MYP')
    x.who()
    # name  :  老马的程序人生
    # url :  https://blog.csdn.net/LSGO_MYP
    
    x.foo()
    # 这是公共方法
    # 这是私有方法
    
    x.__foo()
    # AttributeError: 'Site' object has no attribute '__foo'

    5.继承

    类的继承

    class DerivedClassName(BaseClassName):
        <statement-1>
        .
        .
        .
        <statement-N>

    如果子类中定义与父类同名的方法或属性,则会自动覆盖父类对应的方法或属性

    # 类定义
    class people:
        # 定义基本属性
        name = ''
        age = 0
        # 定义私有属性,私有属性在类外部无法直接进行访问
        __weight = 0
    
        # 定义构造方法
        def __init__(self, n, a, w):
            self.name = n
            self.age = a
            self.__weight = w
    
        def speak(self):
            print("%s 说: 我 %d 岁。" % (self.name, self.age))
    
    
    # 单继承示例
    class student(people):
        grade = ''
    
        def __init__(self, n, a, w, g):
            # 调用父类的构函
            people.__init__(self, n, a, w)
            self.grade = g
    
        # 覆写父类的方法
        def speak(self):
            print("%s 说: 我 %d 岁了,我在读 %d 年级" % (self.name, self.age, self.grade))
    
    
    s = student('小马的程序人生', 10, 60, 3)
    s.speak()
    # 小马的程序人生 说: 我 10 岁了,我在读 3 年级

    只要该子类覆写了父类的方法,则该子类就不可以调用父类同名的方法

    import random
    
    class Fish:
        def __init__(self):
            self.x = random.randint(0, 10)
            self.y = random.randint(0, 10)
    
        def move(self):
            self.x -= 1
            print("我的位置", self.x, self.y)
    
    
    class GoldFish(Fish):  # 金鱼
        pass
    
    
    class Carp(Fish):  # 鲤鱼
        pass
    
    
    class Salmon(Fish):  # 三文鱼
        pass
    
    
    class Shark(Fish):  # 鲨鱼
        def __init__(self):
            self.hungry = True
    
        def eat(self):
            if self.hungry:
                print("吃货的梦想就是天天有得吃!")
                self.hungry = False
            else:
                print("太撑了,吃不下了!")
                self.hungry = True
    
    
    g = GoldFish()
    g.move()  # 我的位置 9 4
    s = Shark()
    s.eat() # 吃货的梦想就是天天有得吃!
    s.move()  
    # AttributeError: 'Shark' object has no attribute 'x'
    
    
    #解决方法
    #1,调用未绑定的父类方法Fish.__init__(self)
    class Shark(Fish):  # 鲨鱼
        def __init__(self):
            Fish.__init__(self)
            self.hungry = True
    
        def eat(self):
            if self.hungry:
                print("吃货的梦想就是天天有得吃!")
                self.hungry = False
            else:
                print("太撑了,吃不下了!")
                self.hungry = True
    
    #2.使用super函数super().__init__()
    class Shark(Fish):  # 鲨鱼
        def __init__(self):
            super().__init__()
            self.hungry = True
    
        def eat(self):
            if self.hungry:
                print("吃货的梦想就是天天有得吃!")
                self.hungry = False
            else:
                print("太撑了,吃不下了!")
                self.hungry = True

    Python 虽然支持多继承的形式,但我们一般不使用多继承,因为容易引起混乱

    class DerivedClassName(Base1, Base2, Base3):
        <statement-1>
        .
        .
        .
        <statement-N>

    需要注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,Python 从左至右搜索,即方法在子类中未找到时,从左到右查找父类中是否包含方法

    # 类定义
    class People:
        # 定义基本属性
        name = ''
        age = 0
        # 定义私有属性,私有属性在类外部无法直接进行访问
        __weight = 0
    
        # 定义构造方法
        def __init__(self, n, a, w):
            self.name = n
            self.age = a
            self.__weight = w
    
        def speak(self):
            print("%s 说: 我 %d 岁。" % (self.name, self.age))
    
    
    # 单继承示例
    class Student(People):
        grade = ''
    
        def __init__(self, n, a, w, g):
            # 调用父类的构函
            People.__init__(self, n, a, w)
            self.grade = g
    
        # 覆写父类的方法
        def speak(self):
            print("%s 说: 我 %d 岁了,我在读 %d 年级" % (self.name, self.age, self.grade))
    
    
    # 另一个类,多重继承之前的准备
    class Speaker:
        topic = ''
        name = ''
    
        def __init__(self, n, t):
            self.name = n
            self.topic = t
    
        def speak(self):
            print("我叫 %s,我是一个演说家,我演讲的主题是 %s" % (self.name, self.topic))
    
    
    # 多重继承
    class Sample01(Speaker, Student):
        a = ''
    
        def __init__(self, n, a, w, g, t):
            Student.__init__(self, n, a, w, g)
            Speaker.__init__(self, n, t)
    
    # 方法名同,默认调用的是在括号中排前地父类的方法
    test = Sample01("Tim", 25, 80, 4, "Python")
    test.speak()  
    # 我叫 Tim,我是一个演说家,我演讲的主题是 Python
    
    class Sample02(Student, Speaker):
        a = ''
    
        def __init__(self, n, a, w, g, t):
            Student.__init__(self, n, a, w, g)
            Speaker.__init__(self, n, t)
    
    # 方法名同,默认调用的是在括号中排前地父类的方法
    test = Sample02("Tim", 25, 80, 4, "Python")
    test.speak()  
    # Tim 说: 我 25 岁了,我在读 4 年级

    6.组合

    class Turtle:
        def __init__(self, x):
            self.num = x
    
    
    class Fish:
        def __init__(self, x):
            self.num = x
    
    
    class Pool:
        def __init__(self, x, y):
            self.turtle = Turtle(x)
            self.fish = Fish(y)
    
        def print_num(self):
            print("水池里面有乌龟%s只,小鱼%s条" % (self.turtle.num, self.fish.num))
    
    
    p = Pool(2, 3)
    p.print_num()
    # 水池里面有乌龟2只,小鱼3条

    7.类、类对象和实例对象

    类对象:创建一个类,其实也是一个对象也在内存开辟了一块空间,称为类对象,类对象只有一个

    # 类对象
    class A(object):
        pass

    实例对象:就是通过实例化类创建的对象,称为实例对象,实例对象可以有多个

    # 实例化对象 a、b、c都属于实例对象。
    a = A()
    b = A()
    c = A()

    类属性:类里面方法外面定义的变量称为类属性。类属性所属于类对象并且多个实例对象之间共享同一个类属性,说白了就是类属性所有的通过该类实例化的对象都能共享

    class A():
        a = 0  # 类属性
    
        def __init__(self, xx):
            # 使用类属性可以通过 (类名.类属性)调用。
            A.a = xx

    实例属性:实例属性和具体的某个实例对象有关系,并且一个实例对象和另外一个实例对象是不共享属性的,说白了实例属性只能在自己的对象里面使用,其他的对象不能直接使用,因为self是谁调用,它的值就属于该对象

    class 类名():
        __init__(self):
            self.name = xx #实例属性

    类属性和实例属性区别:

    1 类属性:类外面,可以通过实例对象.类属性和类名.类属性进行调用。类里面,通过self.类属性和类名.类属性进行调用。
    2 实例属性 :类外面,可以通过实例对象.实例属性调用。类里面,通过self.实例属性调用。
    3 实例属性就相当于局部变量。出了这个类或者这个类的实例对象,就没有作用了。
    4 类属性就相当于类里面的全局变量,可以和这个类的所有实例对象共享。
    # 创建类对象
    class Test(object):
        class_attr = 100  # 类属性
    
        def __init__(self):
            self.sl_attr = 100  # 实例属性
    
        def func(self):
            print('类对象.类属性的值:', Test.class_attr)  # 调用类属性
            print('self.类属性的值', self.class_attr)  # 相当于把类属性 变成实例属性
            print('self.实例属性的值', self.sl_attr)  # 调用实例属性
    
    
    a = Test()
    a.func()
    
    # 类对象.类属性的值: 100
    # self.类属性的值 100
    # self.实例属性的值 100
    
    b = Test()
    b.func()
    
    # 类对象.类属性的值: 100
    # self.类属性的值 100
    # self.实例属性的值 100
    
    a.class_attr = 200
    a.sl_attr = 200
    a.func()
    
    # 类对象.类属性的值: 100
    # self.类属性的值 200
    # self.实例属性的值 200
    
    b.func()
    
    # 类对象.类属性的值: 100
    # self.类属性的值 100
    # self.实例属性的值 100
    
    Test.class_attr = 300
    a.func()
    
    # 类对象.类属性的值: 300
    # self.类属性的值 200
    # self.实例属性的值 200
    
    b.func()
    # 类对象.类属性的值: 300
    # self.类属性的值 300
    # self.实例属性的值 100

    注意:属性与方法名相同,属性会覆盖方法

    class A:
        def x(self):
            print('x_man')
    
    
    aa = A()
    aa.x()  # x_man
    aa.x = 1
    print(aa.x)  # 1
    aa.x()
    # TypeError: 'int' object is not callable

    8.什么是绑定

    Python 严格要求方法需要有实例才能被调用,这种限制其实就是 Python 所谓的绑定概念

    Python 对象的数据属性通常存储在名为.__ dict__的字典中,我们可以直接访问__dict__,或利用 Python 的内置函数vars()获取.__ dict__

    class CC:
        def setXY(self, x, y):
            self.x = x
            self.y = y
    
        def printXY(self):
            print(self.x, self.y)
    
    
    dd = CC()
    print(dd.__dict__)
    # {}
    
    print(vars(dd))
    # {}
    
    print(CC.__dict__)
    # {'__module__': '__main__', 'setXY': <function CC.setXY at 0x000000C3473DA048>, 'printXY': <function CC.printXY at 0x000000C3473C4F28>, '__dict__': <attribute '__dict__' of 'CC' objects>, '__weakref__': <attribute '__weakref__' of 'CC' objects>, '__doc__': None}
    
    dd.setXY(4, 5)
    print(dd.__dict__)
    # {'x': 4, 'y': 5}
    
    print(vars(CC))
    # {'__module__': '__main__', 'setXY': <function CC.setXY at 0x000000632CA9B048>, 'printXY': <function CC.printXY at 0x000000632CA83048>, '__dict__': <attribute '__dict__' of 'CC' objects>, '__weakref__': <attribute '__weakref__' of 'CC' objects>, '__doc__': None}
    
    print(CC.__dict__)
    # {'__module__': '__main__', 'setXY': <function CC.setXY at 0x000000632CA9B048>, 'printXY': <function CC.printXY at 0x000000632CA83048>, '__dict__': <attribute '__dict__' of 'CC' objects>, '__weakref__': <attribute '__weakref__' of 'CC' objects>, '__doc__': None}

    9.一些相关的内置函数(BIF)

    1 issubclass(class, classinfo) 方法用于判断参数 class 是否是类型参数 classinfo 的子类。
    2 一个类被认为是其自身的子类。
    3 classinfo可以是类对象的元组,只要class是其中任何一个候选类的子类,则返回True。
    class A:
        pass
    
    
    class B(A):
        pass
    
    
    print(issubclass(B, A))  # True  B是A的之类
    print(issubclass(B, B))  # True  B同时也是自己的之类
    print(issubclass(A, B))  # False
    print(issubclass(B, object))  # True  类也是object

    isinstance(object, classinfo)和type

    1 isinstance(object, classinfo) 方法用于判断一个对象是否是一个已知的类型,类似type()。
    2 type()不会认为子类是一种父类类型,不考虑继承关系。
    3 isinstance()会认为子类是一种父类类型,考虑继承关系。
    4 如果第一个参数不是对象,则永远返回False。
    5 如果第二个参数不是类或者由类对象组成的元组,会抛出一个TypeError异常。
    a = 2
    print(isinstance(a, int))  # True
    print(isinstance(a, str))  # False
    print(isinstance(a, (str, int, list)))  # True
    
    
    class A:
        pass
    
    
    class B(A):
        pass
    
    
    print(isinstance(A(), A))  # True
    print(type(A()) == A)  # True
    print(isinstance(B(), A))  # True
    print(type(B()) == A)  # False

    hasattr(object, name)用于判断对象(实例)是否包含对应的属性

    class Coordinate:
        x = 10
        y = -5
        z = 0
    
    
    point1 = Coordinate()
    print(hasattr(point1, 'x'))  # True
    print(hasattr(point1, 'y'))  # True
    print(hasattr(point1, 'z'))  # True
    print(hasattr(point1, 'no'))  # False

    getattr(object, name[, default])用于返回一个对象(实例)属性值

    class A(object):
        bar = 1
    
    
    a = A()
    print(getattr(a, 'bar'))  # 1
    print(getattr(a, 'bar2', 3))  # 3
    print(getattr(a, 'bar2'))
    # AttributeError: 'A' object has no attribute 'bar2'
    
    
    #这个例子很酷!
    class A(object):
        def set(self, a, b):
            x = a
            a = b
            b = x
            print(a, b)
    
    
    a = A()
    c = getattr(a, 'set') 
    c(a='1', b='2')  # 2 1  #我觉得其实就是c=set()方法

    setattr(object, name, value)对应函数 getattr(),用于设置属性值,该属性不一定是存在的

    class A(object):
        bar = 1
    
    
    a = A()
    print(getattr(a, 'bar'))  # 1
    setattr(a, 'bar', 5)
    print(a.bar)  # 5
    setattr(a, "age", 28)
    print(a.age)  # 28

    delattr(object, name)用于删除属性

    class Coordinate:
        x = 10
        y = -5
        z = 0
    
    
    point1 = Coordinate()
    
    print('x = ', point1.x)  # x =  10
    print('y = ', point1.y)  # y =  -5
    print('z = ', point1.z)  # z =  0
    
    delattr(Coordinate, 'z')
    
    print('--删除 z 属性后--')  # --删除 z 属性后--
    print('x = ', point1.x)  # x =  10
    print('y = ', point1.y)  # y =  -5
    
    # 触发错误
    print('z = ', point1.z)
    # AttributeError: 'Coordinate' object has no attribute 'z'

    class property([fget[, fset[, fdel[, doc]]]])用于在新式类中返回属性值

    1 fget -- 获取属性值的函数
    2 fset -- 设置属性值的函数
    3 fdel -- 删除属性值函数
    4 doc -- 属性描述信息
    class C(object):
        def __init__(self):
            self.__x = None
    
        def getx(self):
            return self.__x
    
        def setx(self, value):
            self.__x = value
    
        def delx(self):
            del self.__x
    
        x = property(getx, setx, delx, "I'm the 'x' property.")
    
    
    cc = C()
    cc.x = 2
    print(cc.x)  # 2
    
    del cc.x
    print(cc.x)
    # AttributeError: 'C' object has no attribute '_C__x'

    作业:

    1、以下类定义中哪些是类属性,哪些是实例属性?

    class C:
        num = 0  #类属性
        def __init__(self):
            self.x = 4  #实例属性
            self.y = 5  #实例属性
            C.count = 6  #实例属性

    2、怎么定义私有⽅法?  

    class Site:
        def __foo(self):  # 私有方法
            print('这是私有方法')

    3、尝试执行以下代码,并解释错误原因:

    class C:
        def myFun():  #定义方法时没有用self  TypeError: myFun() takes 0 positional arguments but 1 was given
            print('Hello!')
        c = C()  #不需要缩进,这样就会当做是类里面的了
        c.myFun()
    #NameError: name 'C' is not defined

    4、按照以下要求定义一个游乐园门票的类,并尝试计算2个成人+1个小孩平日票价。

    要求:

    1 平日票价100元
    2 周末票价为平日的120%
    3 儿童票半价
    class Ticket:
    
    
        def __init__(self,time,adult_number,child_number):
            self.time=time
            self.adult_number=int(adult_number)
            self.child_number=int(child_number)
    
    
        def get_price(self):
            if self.time=="weekday":
                adult_price=120
                child_price=60
            if self.time=="workday":
                adult_price=100
                child_price=50
            total_price=self.adult_number*adult_price+self.child_number*child_price
            print("当%s去公园时,%d个成人和%d个小孩的票价是:%d" %(self.time,self.adult_number,self.child_number,total_price) )
    
    
    time=input("请输入去公园的时间:")
    adult_number=int(input("请输入成人数:"))
    child_number=int(input("请输入小孩数:"))
    t=Ticket(time,adult_number,child_number)
    t.get_price()

    二、魔法方法

    1 魔法方法总是被双下划线包围,例如__init__。
    2 魔法方法是面向对象的 Python 的一切,如果你不知道魔法方法,说明你还没能意识到面向对象的 Python 的强大。
    3 魔法方法的“魔力”体现在它们总能够在适当的时候被自动调用。
    4 魔法方法的第一个参数应为cls(类方法) 或者self(实例方法)。
    5 cls:代表一个类的名称
    6 self:代表一个实例对象的名称

    1.基本的魔法方法

    1.1 __init__(self[, ...]) 构造器,当一个实例被创建的时候调用的初始化方法

    class Rectangle:
        def __init__(self, x, y):
            self.x = x
            self.y = y
    
        def getPeri(self):
            return (self.x + self.y) * 2
    
        def getArea(self):
            return self.x * self.y
    
    
    rect = Rectangle(4, 5)
    print(rect.getPeri())  # 18
    print(rect.getArea())  # 20

    1.2 __new__(cls[, ...]) 在一个对象实例化的时候所调用的第一个方法,在调用__init__初始化前,先调用__new__

    1 __new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由 Python 解释器自动提供,后面的参数直接传递给__init__。
    2 __new__对当前类进行了实例化,并将实例返回,传给__init__的self。但是,执行了__new__,并不一定会进入__init__,只有__new__返回了,当前类cls的实例,当前类的__init__才会进入
    class A(object):
        def __init__(self, value):
            print("into A __init__")
            self.value = value
    
        def __new__(cls, *args, **kwargs):
            print("into A __new__")
            print(cls)
            return object.__new__(cls)
    
    
    class B(A):
        def __init__(self, value):
            print("into B __init__")
            self.value = value
    
        def __new__(cls, *args, **kwargs):
            print("into B __new__")
            print(cls)
            return super().__new__(cls, *args, **kwargs)
    
    
    b = B(10)
    
    # 结果:
    # into B __new__
    # <class '__main__.B'>
    # into A __new__
    # <class '__main__.B'>
    # into B __init__
    
    
    #若__new__没有正确返回当前类cls的实例,那__init__是不会被调用的,即使是父类的实例也不行,将没有__init__被调用
    class A(object):
        def __init__(self, value):
            print("into A __init__")
            self.value = value
    
        def __new__(cls, *args, **kwargs):
            print("into A __new__")
            print(cls)
            return object.__new__(cls)
    
    
    class B(A):
        def __init__(self, value):
            print("into B __init__")
            self.value = value
    
        def __new__(cls, *args, **kwargs):
            print("into B __new__")
            print(cls)
            return super().__new__(A, *args, **kwargs)  # 改动了cls变为A
    
    
    b = B(10)
    
    # 结果:
    # into B __new__
    # <class '__main__.B'>
    # into A __new__
    # <class '__main__.A'>

    利用__new__实现单例模式

    class Earth:
        pass
    
    
    a = Earth()
    print(id(a))  # 260728291456
    b = Earth()
    print(id(b))  # 260728291624
    
    class Earth:
        __instance = None  # 定义一个类属性做判断
    
        def __new__(cls):
            if cls.__instance is None:
                cls.__instance = object.__new__(cls)
                return cls.__instance
            else:
                return cls.__instance
    
    
    a = Earth()
    print(id(a))  # 512320401648
    b = Earth()
    print(id(b))  # 512320401648

    __new__方法主要是当你继承一些不可变的 class 时(比如int, str, tuple), 提供给你一个自定义这些类的实例化过程的途径

    class CapStr(str):
        def __new__(cls, string):
            string = string.upper()
            return str.__new__(cls, string)
    
    
    a = CapStr("i love lsgogroup")
    print(a)  # I LOVE LSGOGROUP

    1.3 __del__(self) 析构器,当一个对象将要被系统回收之时调用的方法

    Python 采用自动引用计数(ARC)方式来回收对象所占用的空间,当程序中有一个变量引用该 Python 对象时,Python 会自动保证该对象引用计数为 1;
    当程序中有两个变量引用该 Python 对象时,Python 会自动保证该对象引用计数为 2,依此类推,如果一个对象的引用计数变成了 0,
    则说明程序中不再有变量引用该对象,表明程序不再需要该对象,因此 Python 就会回收该对象。 大部分时候,Python 的 ARC 都能准确、高效地回收系统中的每个对象。但如果系统中出现循环引用的情况,
    比如对象 a 持有一个实例变量引用对象 b,而对象 b 又持有一个实例变量引用对象 a,此时两个对象的引用计数都是
    1,
    而实际上程序已经不再有变量引用它们,系统应该回收它们,此时 Python 的垃圾回收器就可能没那么快,
    要等专门的循环垃圾回收器(Cyclic Garbage Collector)来检测并回收这种引用循环。
    class C(object):
        def __init__(self):
            print('into C __init__')
    
        def __del__(self):
            print('into C __del__')
    
    
    c1 = C()
    # into C __init__
    c2 = c1
    c3 = c2
    del c3
    del c2
    del c1
    # into C __del__

    1.4 __str__(self):

    1 当你打印一个对象的时候,触发__str__
    2 当你使用%s格式化的时候,触发__str__
    3 str强转数据类型的时候,触发__str__

    1.5 __repr__(self):

    1 repr是str的备胎
    2 有__str__的时候执行__str__,没有实现__str__的时候,执行__repr__
    3 repr(obj)内置函数对应的结果是__repr__的返回值
    4 当你使用%r格式化的时候 触发__repr__

    1.4和1.5的例子

    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)
            
        def __repr__(self):
            """返回一个对象的描述信息"""
            return "Cat:(%s,%d)" % (self.name, self.age)
    
        def eat(self):
            print("%s在吃鱼...." % self.name)
    
        def drink(self):
            print("%s在喝可乐..." % self.name)
    
        def introduce(self):
            print("名字是:%s, 年龄是:%d" % (self.name, self.age))
    
    
    # 创建了一个对象
    tom = Cat("汤姆", 30)
    print(tom)  # 名字是:汤姆 , 年龄是:30
    print(str(tom)) # 名字是:汤姆 , 年龄是:30
    print(repr(tom))  # Cat:(汤姆,30)
    tom.eat()  # 汤姆在吃鱼....
    tom.introduce()  # 名字是:汤姆, 年龄是:30

    __str__(self) 的返回结果可读性强。也就是说,__str__ 的意义是得到便于人们阅读的信息,就像下面的 '2019-10-11' 一样。

    __repr__(self) 的返回结果应更准确。怎么说,__repr__ 存在的目的在于调试,便于开发者使用

    import datetime
    
    today = datetime.date.today()
    print(str(today))  # 2019-10-11
    print(repr(today))  # datetime.date(2019, 10, 11)
    print('%s' %today)  # 2019-10-11
    print('%r' %today)  # datetime.date(2019, 10, 11)

    2.算术运算符

     1 1 __add__(self, other)定义加法的行为:+
     2  2 __sub__(self, other)定义减法的行为:-
     3  3 __mul__(self, other)定义乘法的行为:*
     4  4 __truediv__(self, other)定义真除法的行为:/
     5  5 __floordiv__(self, other)定义整数除法的行为://
     6  6 __mod__(self, other) 定义取模算法的行为:%
     7  7 __divmod__(self, other)定义当被 divmod() 调用时的行为
     8  8 divmod(a, b)把除数和余数运算结果结合起来,返回一个包含商和余数的元组(a // b, a % b)。
     9  9 __pow__(self, other[, module])定义当被 power() 调用或 ** 运算时的行为
    10 10 __lshift__(self, other)定义按位左移位的行为:<<
    11 11 __rshift__(self, other)定义按位右移位的行为:>>
    12 12 __and__(self, other)定义按位与操作的行为:&
    13 13 __xor__(self, other)定义按位异或操作的行为:^
    14 14 __or__(self, other)定义按位或操作的行为:|
    class MyClass:
    
        def __init__(self, height, weight):
            self.height = height
            self.weight = weight
    
        # 两个对象的长相加,宽不变.返回一个新的类
        def __add__(self, others):
            return MyClass(self.height + others.height, self.weight + others.weight)
    
        # 两个对象的宽相减,长不变.返回一个新的类
        def __sub__(self, others):
            return MyClass(self.height - others.height, self.weight - others.weight)
    
        # 说一下自己的参数
        def intro(self):
            print("高为", self.height, " 重为", self.weight)
    
    
    def main():
        a = MyClass(height=10, weight=5)
        a.intro()
    
        b = MyClass(height=20, weight=10)
        b.intro()
    
        c = b - a
        c.intro()
    
        d = a + b
        d.intro()
    
    
    if __name__ == '__main__':
        main()
    
    # 高为 10  重为 5
    # 高为 20  重为 10
    # 高为 10  重为 5
    # 高为 30  重为 15

    3.反算术运算符

    反运算魔方方法,与算术运算符保持一一对应,不同之处就是反运算的魔法方法多了一个“r”。当文件左操作不支持相应的操作时被调用

     1 __radd__(self, other)定义加法的行为:+
     2 __rsub__(self, other)定义减法的行为:-
     3 __rmul__(self, other)定义乘法的行为:*
     4 __rtruediv__(self, other)定义真除法的行为:/
     5 __rfloordiv__(self, other)定义整数除法的行为://
     6 __rmod__(self, other) 定义取模算法的行为:%
     7 __rdivmod__(self, other)定义当被 divmod() 调用时的行为
     8 __rpow__(self, other[, module])定义当被 power() 调用或 ** 运算时的行为
     9 __rlshift__(self, other)定义按位左移位的行为:<<
    10 __rrshift__(self, other)定义按位右移位的行为:>>
    11 __rand__(self, other)定义按位与操作的行为:&
    12 __rxor__(self, other)定义按位异或操作的行为:^
    13 __ror__(self, other)定义按位或操作的行为:|
    class Nint(int):
        def __radd__(self, other):
            return int.__sub__(other, self) # 注意 self 在后面
    
    
    a = Nint(5)
    b = Nint(3)
    print(a + b)  # 8
    print(1 + b)  # -2

     4.增量赋值运算符

     1 __iadd__(self, other)定义赋值加法的行为:+=
     2 __isub__(self, other)定义赋值减法的行为:-=
     3 __imul__(self, other)定义赋值乘法的行为:*=
     4 __itruediv__(self, other)定义赋值真除法的行为:/=
     5 __ifloordiv__(self, other)定义赋值整数除法的行为://=
     6 __imod__(self, other)定义赋值取模算法的行为:%=
     7 __ipow__(self, other[, modulo])定义赋值幂运算的行为:**=
     8 __ilshift__(self, other)定义赋值按位左移位的行为:<<=
     9 __irshift__(self, other)定义赋值按位右移位的行为:>>=
    10 __iand__(self, other)定义赋值按位与操作的行为:&=
    11 __ixor__(self, other)定义赋值按位异或操作的行为:^=
    12 __ior__(self, other)定义赋值按位或操作的行为:|=

    5.一元运算符

    1 __neg__(self)定义正号的行为:+x
    2 __pos__(self)定义负号的行为:-x
    3 __abs__(self)定义当被abs()调用时的行为
    4 __invert__(self)定义按位求反的行为:~x

    6.属性访问

    1 __getattr__(self, name): 定义当用户试图获取一个不存在的属性时的行为。
    2 __getattribute__(self, name):定义当该类的属性被访问时的行为(先调用该方法,查看是否存在该属性,若不存在,接着去调用__getattr__)。
    3 __setattr__(self, name, value):定义当一个属性被设置时的行为。
    4 __delattr__(self, name):定义当一个属性被删除时的行为。
    class C:
        def __getattribute__(self, item):
            print('__getattribute__')
            return super().__getattribute__(item)
    
        def __getattr__(self, item):
            print('__getattr__')
    
        def __setattr__(self, key, value):
            print('__setattr__')
            super().__setattr__(key, value)
    
        def __delattr__(self, item):
            print('__delattr__')
            super().__delattr__(item)
    
    
    c = C()
    c.x
    # __getattribute__
    # __getattr__
    
    c.x = 1
    # __setattr__
    
    del c.x
    # __delattr__
  • 相关阅读:
    截取字符
    vue中移动端调取本地的复制的文本
    vue中用 async/await 来处理异步
    vue中子组件调用父组件里面的数据和方法 父组件调用子组件的数据和方法
    spy-debugger 安装以及使用
    vuex用法-新手一
    monent API详解
    原生js标识当前导航位置(给当前导航一个className=active)
    webpack 4.0 配置文件 webpack.config.js文件的放置位置
    移动端部分安卓手机(三星,小米)竖拍上传图片预览的时候发生旋转问题
  • 原文地址:https://www.cnblogs.com/cgmcoding/p/13438628.html
Copyright © 2020-2023  润新知