python_面向对象

面向对象编程
    object(对象)
    什么是对象
        对象是指现实中的物体或实物
    什么是面向对象
        把一切当作对象(实例),让对象和对象之间创建关联关系
    对象都有什么特征
        对象有不少属性(名词),用变量记录属性
            姓名,年龄,性别等
        对象有不少行为(动做,动词),用函数(方法)表示行为
            学习,吃饭,睡觉,踢球,工做
    什么是类class:
        拥有相同属性和行为的对象分为一组,即为一个类
        类是用来描述对象的工具,用类能够建立同类对象
    类的建立语句:
        语法:class 类名(继承列表):
                '''类的文档字符串'''
                实例方法定义(类内的函数称为方法method)
                类变量定义
                类方法定义
                静态方法定义
        做用:
            一、建立一个类
            二、用于描述此类对象的行为和属性
            三、类用于建立此类的一个或多个对象(实例)python

class Dog:#定义一个类,类名为Dog
    pass
dog1 = Dog()#建立Dog类的一个对象
print(id(dog1))#140399880349568
dog2 = Dog()#建立Dog类的另外一个对象
print(id(dog2))#140399880349848
#相似于以下语句:
int1 = int()
int2 = int ()
View Code

    类 和 对象
        类   |      对象      实例
      class  |  object   instance
    构造函数
        表达式:类名([建立传参列表])
        做用:建立这个类的实例对象,并返回此实例对象的引用关系
    实例(对象)说明
        实例有本身的做用域和名字空间,能够为该实例添加实例变量(属性)
        实例能够调用类方法和实例方法
        实例能够访问类变量和实例变量
    实例方法:
        语法:calss 类名(继承列表):
                def 实例方法名(self,参数1,参数2...):
                    '''实例方法的的文档字符串'''
                    语句块
        做用:用于描述一个对象的行为,让此类型的所有对象都拥有相同的行为
        说明:
            一、实例方法实质是函数,是定义在类内的函数
            二、实例方法至少有一个形参,第一个形参表明调用这个方法的实例,通常命名为”self“
        实例方法的调用语法:
            一、实例.实例方法名(调用传参)
            二、类名.实例方法名(实例,调用传参)编程

#此实例示意如何用实例方法(method)来描述Dog类的行为
class Dog():
    def eat(self,food):
        '''此方法用来描述小狗吃东西的行为'''
        print("小狗正常吃:",food)
    def sleep(self,hour):
        print("小狗睡了",hour,'小时')
dog1 = Dog()#建立一个Dog的类的实例
dog1.eat("狗粮")
dog1.sleep(1)
Dog.eat(dog1,"狗粮")#第二种方法调用实例方法
#对象不能调用类内没有的方法
View Code

    属性 attribute(也叫实例变量)
        每一个实例均可以有本身的变量,此变量称为实例变量(也叫属性)
        属性的使用语法:实例名.属性名
        赋值规则:
            一、首次为属性赋值,则建立此属性
            二、再次为属性赋值,则必改变属性的绑定关系
        做用:用来记录对象自身的数据less

class Dog:
    pass
#建立第一个对象
dog1 = Dog()
dog1.kinds = '京巴' #添加属性kinds
dog1.color = '白色' #添加属性color
dog1.color = '京巴' #改变属性的绑定关系
View Code

    实例方法和实例变量(属性)结合使用编程语言

class Dog:
    def eat(self,food):
        print("%s的%s正在吃%s"%(self.color,self.kinds,food))
dog1 = Dog()
dog1.kinds = '京巴' #添加属性kinds
dog1.color = '白色' #添加属性color
dog1.eat("狗粮")#该语句不能放在kinds和color属性被添加以前
dog2 = Dog()
dog2.kinds = '哈士奇' #添加属性kinds
dog2.color = '黑色' #添加属性color
dog2.eat("包子")
View Code

    删除属性
        用del语句能够删除一个对象的实例变量
        语法:
            del 对象.实例变量名
        示例:
            class Cat:
                pass
            c1 = Cat()        #建立实例对象
            c1.color = "白色"#添加属性
            del c1.color       #删除属性
            print(c1.color)#属性错误

    初始化方法:
        做用:对新建立的对象添加实例变量(属性)或相应的资源
        语法:
            class 类名(继承列表):
                def __init__(self[,形参列表]):
                    语句块
        说明:
            一、初始化方法名必须为__init__不可改变
            二、初始化方法会在构造函数建立实例后自动调用,且将实例自身经过第一个参数self传入__init__方法
            三、构造函数的实参将经过__init__方法的形参传入__init__方法中
            四、初始化方法内部若是须要返回,则只能返回Noneide

class Car():
    def __init__(self,c,b,m):#此方法只能怪返回None
        print("__init__方法被调用")
        self.color = c
        self.brand = b
        self.model = m
        #return 1  #TypeError: __init__() should return None, not 'int'
car = Car("红色","奥迪","A4")#Car()构造函数首先建立一个空的(没有属性的对象),而后把这个对象传递给__init__方法
View Code

  析构方法:
        语法:class 类名(继承列表):
            def __del__(self):
                语句块
        说明:析构方法在对象销毁时被自动调用
        做用:清理此对象所占用的资源
        python不建议在析构方法中作任何事情,由于对象销毁的时间难以肯定
    预置实例属性:
        __dict__属性:
            此属性绑定一个存储此实例自身实例变量(属性)的字典,也能够存储类中的变量,文档字符串,方法
        示例:
            class Dog():
                pass
            dog = Dog()
            print(dog.__dict__)#{}
            dog.kinds = "aa"
            print(dog.__dict__)#{"kinds":"aa"}
            dog.__dict__["color"]= "red"
        __class__属性:
            此属性用来绑定建立此实例的类
            做用:能够借助此属性来访问建立此实例的类
            示例:
                class Dog()
                    pass
                dog1=Dog()
                dog2 = dog1.__class__()#等同于dog2 = Dog()
     面向对象的综合示例
         有两我的:
             一、姓名:张三  年龄:35
             二、姓名:李四  年龄:38
         行为:
             一、交别人学东西teach
             二、赚钱
             三、借钱
         事情:
             张三 教 李四 学 python
             李四 教 张三 学 跳皮筋
             张三 上班赚了 1000 元钱
             李四 向 张三 借了 200 元钱函数

class Person():
    '''人类,用于描述人的行为和属性'''
    def __init__(self,name,age):
        self.name = name
        self.age = age
        self.money = 0
    def teach(self,other,things):
        print(self.name,"",other.name,"",things)
    def make_money(self,money):
        self.money+=money
        print(self.name,"上班赚了",money,"元钱")
    def borrow_money(self,other,money):
        if other.money > money:#
            print(self.name,"",other.name,"借了",money,"元钱")
            other.money -= money
            self.money  += money
        print(other.name,"没有钱借给",self.name)
    def show_info(self):
        print(self.age,"岁的",self.name,"存有",self.money,"元钱")
p1 = Person("张三",35)
p2 = Person("李四",38)
p1.teach(p2,"python")
p2.teach(p1,"跳皮筋")
p1.make_money(1000)
p2.borrow_money(p1,200)
p1.show_info()
p2.show_info()
# 张三 教 李四 学 python
# 李四 教 张三 学 跳皮筋
# 张三 上班赚了 1000 元钱
# 李四 向 张三 借了 200 元钱
# 张三 没有钱借给 李四
# 35 岁的 张三 存有 800 元钱
# 38 岁的 李四 存有 200 元钱
View Code

     用于判断类的函数:
         isinstance(obj,class_or_tuple)返回一个对象obj是否为某个类class或某些类的实例,若是是返回True,不然返回False
         type(obj)    返回对象的类型
     示例:
             class Dog:
                 pass
             class Cat:
                 pass
             animal = Dog()
             isinstance(animal,Dog) #True
             isinstance(animal,Cat) #False
             isinstance(animal,(Cat,int,list)) #False
             isinstance(animal,(Cat,int,list,Dog)) #True工具

类变量 class variable(也叫类属性):
    类变量是类的属性,此属性属于类
    做用:用来记录类的相关数据
    说明:
        一、类变量能够经过类直接访问
        二、类变量能够经过类的实例直接访问
        三、类变量能够经过类的实例的__class__属性访问
    实例:
        class Human:
            count = 0 #建立类变量学习

class Human:
    count =0 #建立一个类变量
print("Human的类变量count=",Human.count)#0
h1 = Human()
print("用h1对象访问Human的count变量",h1.count)#0
print("用h1对象的__class__属性访问Human的count变量",h1.__class__.count)#0
h1.count = 100 #此处hi建立实例变量,经过实例不能经过这样的方式修改类变量,能够经过__class__属性来修改
print(h1.count)  #100,会优先寻找实例变量,若是没有实例变量才会访问到类变量
print(Human.count) #0
print(h1.__class__.count) #0
View Code

    类变量的应用案例:
        用类变量来记录对象的个数测试

class Car:
    count = 0
    def __init__(self,info):#建立类变量,用来记录汽车对象的总数
        print(info,"被建立")
        self.data = info#记录传入的数据
        self.__class__.count +=1 #让车的总数加1
    def __del__(self):
        print(self.data,"被销毁")
        self.__class__.count -=1#让车的总数减1
print("当前汽车总数是",Car.count)
car1 = Car("奥迪")
print(Car.count)
car2 = Car("奔驰")
car3 = Car("大众")
print(Car.count)
View Code

类的文档字符串:
    类内的一个没有赋值给任何变量的字符串是类的文档字符串
    说明:
        一、类的文档字符串用类的__doc__属性能够访问
        二、类的文档字符串能够用help()函数查看
类的__slots__列表:
    做用:限定一个类的实例只能有固定的属性(实例变量),一般为了防止错写属性名而发生运行时错误
    说明:含有__slots__列表的类建立的实例对象没有__dict__属性,即此实例不用字典来保存对象的属性(实例变量)spa

class Student:
    __slots__ = ["name","score","aa"]#此处表示该实例对象最多只能有两个实例变量
    def __init__(self,name,score):
        self.name = name
        self.score = score
s1 = Student("小张",58)
print(s1.score)
s1.socre = 100 #此处写错了属性名,但在运行时不会报错 ,若是添加了__slots__变量后就会产生AttributeError: 'Student' object has no attribute 'socre'
print(s1.score)
View Code

类方法 @classmethod
    类方法是描述类的行为的方法,类方法属于类
    说明:
        一、类方法须要用@classmethod装饰器定义
        二、类方法至少有一个形参,第一个形参用于绑定类,约定写为‘cls’
        三、类和该类的实例均可以调用类方法
        四、类方法不能访问此类建立的实例的属性(只能访问类变量)

class Car:
    count =0 #类变量
    @classmethod
    def getTotalCount(cls):
        '''此方法为类方法,第一个参数cls,表明调用此方法的类'''
        return cls.count
    @classmethod
    def updateCount(cls,number):
        cls.count += number
print(Car.getTotalCount())#用类来调用类方法
#Car.count += 1 #面向对象思想不提倡直接操做属性
Car.updateCount(2)
print(Car.getTotalCount())

c1 = Car()
c1.updateCount(100)#类的实例能够访问类方法,是把c1.__class__传给cls
print(c1.getTotalCount())    
View Code

问题:
    一、类方法属于类
    二、实例方法属于该类的实例
    三、类内能不能有函数,既不属于类又不属于类的实例?
静态方法 @staticmethos
    静态方法不属于类,也不属于类的实例,它至关于定义在类内的普通函数,只是它的做用域属于类

class A:
    @staticmethod
    def myadd(x,y):
        '''此方法为静态方法,此方法的形参不须要传入类或实例'''
        return x+y
print("1+2=",A.myadd(1,2))
a = A()
print("100+200=",a.myadd(100,200))
print(myadd(10,20))#NameError: name 'myadd' is not defined
View Code

 继承 inheritance 和  派生  derived
    什么是继承/派生
        一、继承是指从已有的类中衍生出新类,新类具备原有类的行为和属性,并能扩展新的行为和属性
        二、派生就是从一个已有类中衍生(建立)新类,在新类上能够添加新的属性和行为
    继承和派生的目的:
        一、继承是延续旧类的功能
        二、派生是为了在旧类的基础上添加新的功能
    做用:
        一、用继承派生机制,能够将一些共有功能加在基类中,实现代码的共享
        二、在不改变基类的基础上改变原有的功能
    继承/派生的名词:
        基类(base class),超类(super class),父类(father class)
        派生类(derived class),子类(child class)
    单继承:
        语法:class 类名( 基类名):
                语句块
        说明:单继承是指派生类由一个基类衍生出来的类
    继承说明:
        一、任何类都直接或间接的继承自object类
        二、object类是一切类的超类(祖类)
    类的__base__属性:
        __base__属性用来记录此类的基类
        说明:类名.__base__ 返回的是继承的第一个类
    覆盖 override:
        什么是覆盖:
            覆盖是指在有继承关系的类中,子类中实现了与基类同名的方法,在子类实例调用该方法时,实例调用的是子类中的覆盖版本的方法,这种现象叫作覆盖
    问题:当覆盖发生时,子类对象可否访问父类中的方法?
        子类对象显式调用基类方法的方式:
            基类名.方法名(实例,实际调用传参)
        super 函数:
            super(type,obj) 返回绑定超类的实例
            super() 返回绑定超类的实例,等同于:super(__class__,实例方法的第一个参数,必须在方法内调用)

    def work(self):
        print("A.walk()被调用")
class B(A):
    def work(self):
        print("B.walk()被调用")
    def super_work(self):
        #此处能调用超类的work方法
        #super(B,self).work() #A.walk()
        #super(__class__,self).work() #A.walk()被调用,在一个类内有一个__class__属性,
        super().work() #A.walk(),在一个实例方法中__class__和self 都是已知的能够省略
b = B()
b.work() # B.walk()被调用
b.__class__.__base__.work(b) #A.walk()被调用,使用显式的方法调用超类的方法
super(B,b).work()#A.walk()被调用,super(B,b)返回的是B类的超类的对象实例
b.super_work()
View Code

    显示调用基类的初始化方法:
        当子类中实现了__init__方法时,基类的__init__方法并不会被调用,此时须要显式调用

class Human():
    def __init__(self,n,a):
        self.name = n
        self.age = a
    def infos(self):
        print("姓名:",self.name)
        print("年龄",self.age)
class Student(Human):
    def __init__(self,n,a,s):
        super().__init__(n,a)#使用超类中的__init__方法给name,age赋值
        self.score = s

s1 = Student("小张",20,100)
s1.infos()
View Code

用于类的函数:
    issubclass(cls,class_or_tuple):
        判断一个类是否继承自其它的类,若是此类cls是class或tuple中的一个派生子类则返回True,不然返回False
    说明:cls是class的子类的子类...也返回True
查看python内建类的继承关系的方法:
    help(__bulitins__)
封装 enclosure
    一、封装是指隐藏类的实现细节,让使用者不用关心这些细节
    二、封装的目的是让使用者尽量少的使用实例变量(属性)进行操做
私有属性:
    python类中,以双下划线“__”开头的,不以双下划线结尾的标识符为私有成员,在类的外部没法直接访问

class A:
    def __init__(self):
        self.__p1 = 100#__p1为私有属性,在类的外部不能调用
    def test(self):
        print(self.__p1)#在类内能够调用私有属性
        self.__m1()   #A类的方法能够调用私有方法
    def __m1(self):
        '''我是私有方法,只有我本身的类的方法才能调用我'''
        print("我是A类的__m1方法")
a = A()
#print(a.__p1)#在类外看不到__p1属性,访问失败
a.test()
#a.__m1() #出错,没法调用私有方法
View Code

多态 polymorphic
    字面意思:“多种状态”
    多态是指在继承/派生关系的类中,调用基类对象的方法,实际能调用子类的覆盖版本方法的现象叫多态
    说明:
        多态调用的方法与对象相关,不与类型相关
        Python的所有对象都只有“运行时状态(动态)”,没有“C++/Java”里的“编译时状态(静态)”

class Shape():
    def draw(self):
        print("Shape.draw被调用")
class Point(Shape):
    def draw(self):
        print("正在画点")
class Circle(Point):
    def draw(self):
        print("正在画圆")
def my_draw(s):
    s.draw() #  此处会调用谁的方法,此处显示多态中的动态
s1 = Circle()
s2 = Point()
s3 = Shape()
my_draw(s1)#正在画圆
my_draw(s2)#正在画点
my_draw(s3)#Shape.draw被调用
View Code

面向对象的编程语言的特征:
    继承
    封装
    多态
    如:C++(支持多继承)/ Java /Python(支持多继承)/Swift /C#
多继承 multiple inheritance
    多继承是指一个子类继承自两个或两个以上的基类
    语法:
        class 类名(基类名1,基类名2....):
            语句块
    说明:
        一、一个子类同时继承自多个父类,父类中的方法能够同时被继承下来
        二、若是两个父类中有同名的方法,而在子类中又没有覆盖此方法时,调用结果难以肯定
    多继承的问题(缺陷):
        标识符(名字空间冲突的问题)
            要谨慎使用多继承

class Car:
    def run(self,speed):
        print("汽车以",speed,"千米/小时的速度行驶")
class Plane:
    def fly(self,height):
        print("飞机以海拔",height,"的高度飞行")
class PlaneCar(Car,Plane):
    pass
p1 = PlaneCar()
p1.fly(10000)
p1.run(300)
View Code

多继承的MRO(Method Resolution Order)问题:
    类内的__mro__属性用来记录继承方法的查找顺序

class A:
    def m(self):
        print("A.m()被调用")
class B:
    def m(self):
        print("B.m()被调用")
class AB(A,B):
    pass
ab = AB()#多继承的调用方法,从左至右,,能够根据AB.__mro__来查看继承的顺序
ab.m()
View Code
class A:
    def m(self):
        print("A.m()")
class B(A):

    def m(self):
        print("B.m()")
class C(A):
    def m(self):
        print("C.m()")
class D(B,C):
    def m(self):
        print("D.m()")
d = D()
print(D.__mro__)#(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

d.m()

############################################################################################################################################
class A:
    def m(self):
        print("A.m()")
class B(A):
    def m(self):
        print("B.m()")
        super().m()# 此处调用的是C类的方法,在多继承中super()的窒执行顺序是按照__mro__的顺序来查找的
class C(A):
    def m(self):
        print("C.m()")
class D(B,C):
    def m(self):
        print("D.m()")
        super().m()#此处调用B类的m方法
d = D()
d.m()
print(D.__mro__)
# D.m()
# B.m()
# C.m()
# (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

函数重写 override:
    重写是在自定义的类内添加相应(內建函数的方法)的方法,让自定义的类生成的对象(实例)像内建对象同样进行內建的函数操做

class MyNumber:
    pass
n1 = MyNumber()
x = len(n1)
print(x) #TypeError: object of type 'MyNumber' has no len()
###################################################################################
class MyNumber:
    def __len__(self):#重写了len方法,重写的必须是内建函数的方法
        return 10
n1 = MyNumber()
x = len(n1)  #至关于x = n1.__len__()
print(x) #10
View Code

  对象转化为字符串函数重写
        repr(obj)返回一个表明此对象的表达式字符串,一般:eval(repr(obj)) == obj
        str(obj)经过给定的对象返回一个字符串(这个字符串一般是给人看的)

class MyNumber:
    def __init__(self,value):
        self.data = value
n1 = MyNumber(100)
print(str(n1))#<__main__.MyNumber object at 0x7f676201cfd0>,至关于调用n1.__str__(self)
print(repr(n1))#<__main__.MyNumber object at 0x7f676201cfd0>,至关于调用n1.__repr__(self)
#########################################################################################
class MyNumber:
    def __init__(self,value):
        self.data = value
    def __str__(self):
        return "数字:%d" % self.data
    def __repr__(self):
        return "MyNumber(%d)"% self.data
n1 = MyNumber(100)
print(str(n1))#数字:100,至关于调用n1.__str__(self)
print(repr(n1))#MyNumber(100),至关于调用n1.__repr__(self)
#n2 = eval(str(n1))#SyntaxError: invalid character in identifier
n2 = eval(repr(n1))#能够建立n2对象实例
View Code

对象转字符串函数的重写方法:
    repr()函数的重写方法:
        def __repr__(self):
            return 可以表达self内容的字符串(能够经过eval()方法反推)
    str()函数的重写方法:
        def __str__(self):
            return 人能看懂的字符串
    说明:
        一、str(obj)函数优先调用obj.__str__()方法返回字符串
        二、若是obj没有__str__()方法,则调用obj.__repr__()方法返回的字符串
        三、若是obj没有__repr__()方法,则调用object类的__repr__()实例方法显示<XXXXX>格式的字符串

   四、print(对象)至关于print(str(对象)),一个对象(实例)就是首先寻找__str__方法,在寻找__repr__方法
数值转换函数的重写:
    def __complex__(self)          complex(obj)函数调用
    def __int__(self)                   int(obj)函数调用
    def __float__(self)                float(obj)函数调用
    def __bool__(self)                bool(obj)函数调用

class MyNumber:
    def __init__(self,value):
        self.data = value
    def __repr__(self):
        print("__repr__被调用")
        return "MyNumber(%d)"% self.data
    def __int__(self):
        '''此方法int(obj)函数重载,必须返回整数,此方法一般用于制定自定义对象如何转为整数的规则'''
        return self.data
n1 = MyNumber(100)
print(type(n1))#<class '__main__.MyNumber'>
n = int(n1)  #至关于n1.__int__(self)
print(type(n))#<class 'int'>
print(n)
View Code

內建函数的重写:
    __abs__                             abs(obj)
    __len__                              len(obj)
    __reversed__                     reversed(obj)
    __round__                          round(obj)

'''自定义一个MyList类,与系统內建的类同样,用来保存有前后顺序关系的数据'''
class MyList():
    def __init__(self,iterator=[]):
        self.data = [x for x in iterator]
    def __repr__(self):
        return "MyList(%r)" % self.data
    def __abs__(self):
        #return MyList([abs(x) for  x in self.data])
        #上一句语句能够用以下生成器表达式代替以防止过多的占用内存
        return  MyList((abs(x) for  x in self.data))
    def __len__(self):
        return len(self.data)
myl = MyList([1,-2,3,-4])
print(myl)#MyList([1, -2, 3, -4])
print(abs(myl))#MyList([1, 2, 3, 4])
print("原来的列表:",myl)#原来的列表: MyList([1, -2, 3, -4]),原来的列表
myl2 = MyList(range(10))
print("myl2的长度是:",len(myl2))#10
print("myl的长度是:",len(myl))  #4
View Code

布尔测试函数的重写:
    格式:def  __bool__(self):
               ....
    做用:
        一、用于bool(obj)函数取值
        二、用于if语句真值表达式中
        三、用于while语句真值表达式中
    说明:
        一、优先调用__bool__方法取值
        二、若是不存在__bool__方法,则用__len__()方法取值,后判断是否为零值,若是不为零返回True,不然返回False
        三、若是再没有__len__方法,则直接返回True

class MyList():
    def __init__(self,iterator=[]):
        self.data = [x for x in iterator]
    def __repr__(self):
        return "MyList(%r)" % self.data
    def __abs__(self):
        #return MyList([abs(x) for  x in self.data])
        #上一句语句能够用以下生成器表达式代替以防止过多的占用内存
        return  MyList((abs(x) for  x in self.data))
    def __len__(self):
        print("__len__方法被调用")
        return len(self.data)
myl = MyList([1,-2,3,-4])
myl2 = MyList([])
print(bool(myl))# True
print(bool(myl2))# False
if myl2:#在此处会查找__bool__,若是没有再查找__len__,再没有直接返回True
    pass
while myl2:#在此处会查找__bool__,若是没有再查找__len__,再没有直接返回True
    pass
View Code

迭代器(高级):
    什么是迭代器
        能够经过next(it)函数取值的对象就是迭代器
    迭代器协议:
        迭代器协议是指对象可以使用next函数获取下一项数据,在没有下一项数据是触发StopIterator来终止迭代的约定
    实现方法:
        类内须要有__next__(self)方法来实现迭代器协议
    语法形式:
        class MyIterator:
            def __next__(self):
                迭代器协议的实现
                return 数据
什么是可迭代对象:
    一、是指能用iter(obj)函数返回迭代器的对象(实例)
    二、可迭代对象内部必定要定义__iter__(self)方法来返回迭代器
可迭代对象的语法形式:
    class MyIterable:
        def __iter__(self):
            语句块
            return 迭代器

class MyList:
    def __init__(self,iterator):
        '''自定义列表的初始方法,此方法建立一个data实例变量来绑定一个用来存储数据的列表'''
        self.data =  list(iterator)
    def __repr__(self):
        '''此方法为了打印此列表的数据'''
        return 'MyList(%r)' % self.data
    def __iter__(self):
        '''有此方法就是可迭代对象,但要求必须返回迭代器'''
        print("__iter__方法被调用")
        return MyListIterator(self.data)
class MyListIterator:
    '''此类用来建立一个迭代器对象,用此迭代器对象能够迭代访问MyList类型的数据'''
    def __init__(self,iter_data):
        self.cur = 0 #设置迭代器的初始值为0表明列表下标
        self.iter_data = iter_data
    def __next__(self):
        '''有此方法的对象才叫迭代器',此方法必定要实现迭代器协议'''
        print("__next__方法被调用")
        if  self.cur >= len(self.iter_data):
            raise StopIteration
        #不然还没有迭代完成,须要返回数据
        r = self.iter_data[self.cur]# 拿到要送回去的数据
        self.cur +=1 #将当前值向后移动一个单位
        return r 

myl = MyList([2,3,5,7])
print(myl)
for x in myl:
    print(x)
View Code

 对象的属性管理函数:
    一、getattr(obj,name[,dafault])    从一个对象获得对象的属性;gettattr(x,'y')等同于x.y;当属性y不存在时,若是有default参数,则返回default,若是没有给出default则产生一   个AttributeError错误
    二、hasattr(obj,name)     用给定的name返回obj是否有属性,若是有返回True,不然返回False,此种作法能够避免在getattr(obj,name)时引起错误
    三、setattr(obj,name,value)  给对象obj的名为name的属性设置相应的值value,setattr(x,'y',v)等同于x.y = v
    四、delattr(obj,name) 删除对象obj中的name属性,delattr(x,'y')等同于del x.y

class Car:
    def __init__(self,c,b):
        self.color = c
        self.brand = b
    def get_car_attr(self,attr_name):
        '''此方法用于获取对象的属性,若是属性在次对此对象中返回该属性,若是不在时返回None'''
        return getattr(self,attr_name,None)
c1 =Car("黑色",'Benz')
v = c1.get_car_attr('color')
if v is None:
    print("没有颜色属性")
else:
    print("颜色是",v)
View Code

运算符重载:
    什么是运算符重载
        让自定义的类生成的对象(实例)可以使用运算符进行操做
    做用:
        一、让自定义的类的实例像內建对象同样运行运算符操做
        二、让程序简洁易读
        三、对自定义的对象,将运算符赋予新的运算规则


算术运算符的重载:
    __add__(self, rhs)            self +  rhs             加法
    __sub__(self, rhs)            self -  rhs             减法
    __mul__(self, rhs)            self *  rhs             乘法
    __truediv__(self, rhs)        self /  rhs             除法
    __floordiv__(self, rhs)        self // rhs             地板出法
    __mod__(self, rhs)            self %  rhs             求余
    __pow__(self, rhs)            self ** rhs             幂运算
    注意:rhs(right hands side )右手边

class MyNumber:
    def __init__(self,v):
        self.data = v
    def __repr__(self):
        return "MyNumber(%)" % self.data
    # def myadd(self,other):
    #     v = self.data + other.data
    #     return MyNumber(v)
    def __add__(self,other):
        v = self.data + other.data
        return MyNumber(v)
    def __sub__(self,other):
        v = self.data - other.data
        return MyNumber(v)
n1 = MyNumber(100)
n2 = MyNumber(200)
#n3 = n1.myadd(n2)
n3 = n1 + n2 # 等同于n1.__add__(n2)
print(n3)#MyNumber(300)
n4 = n3 - n2  #等同于n3.__sub__(n2)
print(n4) #MyNumber(100)
View Code

反向算数运算符的重载:
    当左手边的类型为內建类型,右手边为自定义类型时,要实现运算必须用如下方法重载
    __radd__(self, lhs)            lhs +  self             加法
    __rsub__(self, lhs)            lhs -  self             减法
    __rmul__(self, lhs)            lhs *  self             乘法
    __rtruediv__(self, lhs)        lhs /  self             除法
    __rfloordiv__(self, lhs)    lhs // self             地板出法
    __rmod__(self, lhs)            lhs %  self             求余
    __rpow__(self, lhs)            lhs ** self             幂运算

'''实现两个自定义列表相加'''
class MyList():
    def __init__(self,iterable):
        self.data = iterable
    def __repr__(self):
        return 'MyList(%s)' % self.data  
    def __mul__(self,rhs):
        v = self.data * rhs
        return MyList(v)
    def __add__(self,other):
        v = self.data +other.data
        return MyList(v)
    def __rmul__(self,lhs):
        return MyList(self.data*lhs)
    def __iadd__(self,other):
        self.data.extend(other.data)#此出是改变self自己,返回值为None
        return self
L1 = MyList([1,2,3])
L2 = MyList([4,5,6])
L3 = L1 + L2 #等同于L1.__add__(L2)
print(L3)#MyList([1, 2, 3, 4, 5, 6])
L4 = L2 + L1
print(L4)#MyList([4, 5, 6, 1, 2, 3])
L5 = L1 * 2 #等同于L1.__mul__(2)
print(L5)#MyList([1, 2, 3, 1, 2, 3])
#(反方算数运算符)当左手边的类型为內建类型,右手边为自定义类型时,要实现运算必须用一下方法重载
L6 = 2* L1 
print(L6)#MyList([1, 2, 3, 1, 2, 3])
#符合算数运算符:
L1 += L2 #当没有__iadd__方法时,等同于调用L1 = L1 + L2,在这里又从新建立了一个MyList类的对象
print(L1)#当有__iadd__方法时,在这里不会从新建立了一个MyList类的对象,而是在L1实例上改变
View Code

符合赋值运算符的重载:
    __iadd__(self, rhs)            self +=  rhs             加法
    __isub__(self, rhs)            self -=  rhs             减法
    __imul__(self, rhs)            self *=  rhs             乘法
    __itruediv__(self, rhs)        self /=  rhs             除法
    __ifloordiv__(self, rhs)    self //= rhs             地板出法
    __imod__(self, rhs)            self %=  rhs             求余
    __ipow__(self, rhs)            self **= rhs             幂运算
比较运算符的重载:
    __lt__(self,rhs)            self <   rhs             小于
    __le__(self,rhs)            self <=  rhs             小于等于
    __gt__(self,rhs)            self >   rhs             大于
    __ge__(self,rhs)            self >=  rhs             大于等于
    __eq__(self,rhs)            self ==  rhs             等于
    __ne__(self,rhs)            self !=  rhs             不等于
    注:比较运算符一般返回True 或 False
        lt:less than        le:less or equal
        gt:greater than        gt:gerater or equl
        eq:equal            ne:not equal
位运算符重载:
    __invert__(self)            ~ self                    取反(一元运算符)
    __and__(self,rhs)            self  & rhs                位与
    __or__(self,rhs)            self  | rhs                位或
    __xor__(self,rhs)            self  ^ rhs                位异或
    __lshift__(self,rhs)        self  << rhs            左移
    __rshift__(self,rhs)        self  >> rhs            右移
反向位运算符重载:
    __rand__(self,lhs)            lhs  & self                位与
    __ror__(self,lhs)            lhs  | self                位或
    __rxor__(self,lhs)            lhs  ^ self                位异或
    __rlshift__(self,lhs)        lhs << self                左移
    __rrshift__(self,lhs)        lhs >> self                右移
    注:当左手边的类型为內建类型,右手边为自定义类型时,使用反向位运算符重载
复合赋值位运算符:
    __iand__(self,lhs)            lhs  &= self                位与
    __ior__(self,lhs)            lhs  |= self                位或
    __ixor__(self,lhs)            lhs  ^= self                位异或
    __ilshift__(self,lhs)        lhs <<= self                左移
    __irshift__(self,lhs)        lhs >>= self                右移
一元运算符的重载:
    __neg__(self)                - self                        负号
    __pos__(self)                + self                        正号
    __invert__(self)            ~ self                        取反
    一元运算符的重载方法:
        class 类名:
            def __XXX__(self):
                ....

class MyList():
    def __init__(self,iterable):
        print("__init__被调用")
        self.data = iterable
    def __repr__(self):
        return 'MyList(%r)' % self.data  

    def __neg__(self):
        '''此方法用来制定 - self 返回的规则'''
        L = (-x for x in self.data)
        return MyList(L)
L1 = MyList([1,-2,3,-4])
L2 = -L1
print(L2)#MyList([-1, 2, -3, 4])
View Code

运算符重载说明:
    运算符重载不能改变运算符的优先级
python类名最好用驼峰命名法:
    MyList   MyRange        大驼峰(全部单词首字母大写,其他小写)
    getStudentAge            小驼峰(第一个单词首字母小写,其余首字母大写)


in /not in 运算符的重载:
    重载方法:
        def __contanins__(self,e)        e in self     成员运算

class MyList():
    def __init__(self,iterable):
        self.data = iterable
    def __repr__(self):
        return 'MyList(%r)' % self.data  
    def __contains__(self,e):
        '''此方法用来实现 in /not in 运算符的重载'''
        print("__contains__被调用")
        for x in self.data:
            if x == e:
                return True
        return False
L1 = MyList([1,-2,3,-4])
if -2 in L1:
    print("-2在L1中")
else:
    print("-2不在L中")
#当MyList的类内重载了__contains__方法,则not in 也同时可使用(将__contains__方法的返回值取反)
if 5 not in L1:
    print("5不在L1中")
else:
    print("-5在L中")    
View Code

索引和切片运算符的重载:
    __getitem__(self,i)        x = self[i]        索引和切片取值
    __setitem__(self,i,v)    self[i] = v     索引和切片赋值
    __delitem__(self,i)        del self[i]        del 语句删除索引
    做用:让本身定义的类型的对象可以支持索引和切片操做
slice函数:
    做用:用于建立一个Slice切片对象,此对象存储一个切片的起始值,终止值和步长信息
    slice(start,stop=None,step=None) 建立一个切片对象
    slice的对象的属性:
        s.start                切片的起始值,默认为None
        s.stop                切片的终止值,默认为None
        s.step                切片的步长,默认为None

class MyList():
    def __init__(self,iterable):
        print("__init__被调用")
        self.data = iterable
    def __repr__(self):
        return 'MyList(%r)' % self.data  
    def __getitem__(self,i):
        print("__getitem__被调用,i=",i)
        if type(i) is not int:
            raise TpyeError
        return self.data[i]
    def __setitem__(self,i,v):
        self.data[i] = v
L1 = MyList([1,-2,3,-4])
v = L1[1]
print(v)#-2
L1[1] = 2
print(L1)#MyList([1, 2, 3, -4])
View Code
class MyList():
    def __init__(self,iterable):
        print("__init__被调用")
        self.data = iterable
    def __repr__(self):
        return 'MyList(%r)' % self.data  
    def __getitem__(self,i):
        print("__getitem__被调用,i=",i)
        if type(i) is int:
            print("正在作索引操做")
        elif type(i) is slice:
            print("正在作切片操做")
            print("起始值:",i.start)
            print("终止值:",i.stop)
            print("步长:",i.step)
        else:
            raise KeyError
        return self.data[i]

L1 = MyList([1,-2,3,-4,5,-6])

print(L1[::2])#等同于调用L1[slice(None,None,2)]
# __init__被调用
# __getitem__被调用,i= slice(None, None, 2)
# 正在作切片操做
# 起始值: None
# 终止值: None
# 步长: 2
# [1, 3, 5]
View Code

 类的特殊成员

  一、__call__()方法

class Foo:
    def __init__(self):
        print("init")
    def __call__(self):
        print("call")

Foo()()#首先会执行__init__()方法,再执行__call__()方法
obj = Foo()#执行__init__()方法
obj()#执行__call__()方法

 metaclass(类的祖宗)

  一、Python中一切事物都是对象

  二、class Foo:

      pass

    obj = Foo()

    #obj是对象,Foo类的对象

    #Foo类也是一个对象,type的对象

  三、类都是type类的对象,type(...)

def function(self):
    print("hello world")
#建立一个Foo类继承object,含有func()方法
Foo = type("Foo",(object,),{'func':function})
obj = Foo()

obj.func()

 

class MyType(type):
    def __init__(self,*args,**kwargs):
        super().__init__(*args,**kwargs)#执行父类type的__init__方法
        print("MyType的__init__")

    def __call__(self):
        print("MyType的__call__")
        obj = self.__new__(self)#self表明Foo,第三步调用Foo中的new方法,返回Foo的对象
        self.__init__(obj)#第四步调用Foo中的__init__方法


class Foo(object,metaclass=MyType):#第一步,编译器执行到此处是会调用MyType的__init__方法
    def __init__(self):
        print("Foo的__init__")

    def __new__(cls,*args,**kwargs):
        print("Foo中的__new__方法")
        return object.__new__(cls,*args,**kwargs)#真正建立Foo类的对象的地方

obj = Foo()#第二步,在Foo类(MyTpye类的对象)加(),会执行MyType中的__call__方法
相关文章
相关标签/搜索