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

class Dog:#定义一个类,类名为Dogpass
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...):
                    '''实例方法的的文档字符串'''
                    语句块
        作用:用于描述一个对象的行为,让此类型的全部对象都拥有相同的行为
        说明:
            1、实例方法实质是函数,是定义在类内的函数
            2、实例方法至少有一个形参,第一个形参代表调用这个方法的实例,一般命名为”self“
        实例方法的调用语法:
            1、实例.实例方法名(调用传参)
            2、类名.实例方法名(实例,调用传参)

#此实例示意如何用实例方法(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(也叫实例变量)
        每个实例都可以有自己的变量,此变量称为实例变量(也叫属性)
        属性的使用语法:实例名.属性名
        赋值规则:
            1、首次为属性赋值,则创建此属性
            2、再次为属性赋值,则必改变属性的绑定关系
        作用:用来记录对象自身的数据

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[,形参列表]):
                    语句块
        说明:
            1、初始化方法名必须为__init__不可改变
            2、初始化方法会在构造函数创建实例后自动调用,且将实例自身通过第一个参数self传入__init__方法
            3、构造函数的实参将通过__init__方法的形参传入__init__方法中
            4、初始化方法内部如果需要返回,则只能返回None

class Car():def __init__(self,c,b,m):#此方法只能怪返回Noneprint("__init__方法被调用")self.color = cself.brand = bself.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()
     面向对象的综合示例
         有两个人:
             1、姓名:张三  年龄:35
             2、姓名:李四  年龄:38
         行为:
             1、交别人学东西teach
             2、赚钱
             3、借钱
         事情:
             张三 教 李四 学 python
             李四 教 张三 学 跳皮筋
             张三 上班赚了 1000 元钱
             李四 向 张三 借了 200 元钱

class Person():'''人类,用于描述人的行为和属性'''def __init__(self,name,age):self.name = nameself.age = ageself.money = 0def teach(self,other,things):print(self.name,"教",other.name,"学",things)def make_money(self,money):self.money+=moneyprint(self.name,"上班赚了",money,"元钱")def borrow_money(self,other,money):if other.money > money:#
            print(self.name,"向",other.name,"借了",money,"元钱")other.money -= moneyself.money  += moneyprint(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(也叫类属性):
    类变量是类的属性,此属性属于类
    作用:用来记录类的相关数据
    说明:
        1、类变量可以通过类直接访问
        2、类变量可以通过类的实例直接访问
        3、类变量可以通过类的实例的__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 = 0def __init__(self,info):#创建类变量,用来记录汽车对象的总数print(info,"被创建")self.data = info#记录传入的数据self.__class__.count +=1 #让车的总数加1def __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

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

class Student:__slots__ = ["name","score","aa"]#此处表示该实例对象最多只能有两个实例变量def __init__(self,name,score):self.name = nameself.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
    类方法是描述类的行为的方法,类方法属于类
    说明:
        1、类方法需要用@classmethod装饰器定义
        2、类方法至少有一个形参,第一个形参用于绑定类,约定写为‘cls’
        3、类和该类的实例都可以调用类方法
        4、类方法不能访问此类创建的实例的属性(只能访问类变量)

class Car:count =0 #类变量
    @classmethoddef getTotalCount(cls):'''此方法为类方法,第一个参数cls,代表调用此方法的类'''return cls.count@classmethoddef 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

问题:
    1、类方法属于类
    2、实例方法属于该类的实例
    3、类内能不能有函数,既不属于类又不属于类的实例?
静态方法 @staticmethos
    静态方法不属于类,也不属于类的实例,它相当于定义在类内的普通函数,只是它的作用域属于类

class A:@staticmethoddef 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
    什么是继承/派生
        1、继承是指从已有的类中衍生出新类,新类具有原有类的行为和属性,并能扩展新的行为和属性
        2、派生就是从一个已有类中衍生(创建)新类,在新类上可以添加新的属性和行为
    继承和派生的目的:
        1、继承是延续旧类的功能
        2、派生是为了在旧类的基础上添加新的功能
    作用:
        1、用继承派生机制,可以将一些共有功能加在基类中,实现代码的共享
        2、在不改变基类的基础上改变原有的功能
    继承/派生的名词:
        基类(base class),超类(super class),父类(father class)
        派生类(derived class),子类(child class)
    单继承:
        语法:class 类名( 基类名):
                语句块
        说明:单继承是指派生类由一个基类衍生出来的类
    继承说明:
        1、任何类都直接或间接的继承自object类
        2、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 = nself.age = adef 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 = ss1 = Student("小张",20,100)
s1.infos()

View Code

用于类的函数:
    issubclass(cls,class_or_tuple):
        判断一个类是否继承自其它的类,如果此类cls是class或tuple中的一个派生子类则返回True,否则返回False
    说明:cls是class的子类的子类...也返回True
查看python内建类的继承关系的方法:
    help(__bulitins__)
封装 enclosure
    1、封装是指隐藏类的实现细节,让使用者不用关心这些细节
    2、封装的目的是让使用者尽可能少的使用实例变量(属性)进行操作
私有属性:
    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....):
            语句块
    说明:
        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 = valuedef __str__(self):return "数字:%d" % self.datadef __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 人能看懂的字符串
    说明:
        1、str(obj)函数优先调用obj.__str__()方法返回字符串
        2、如果obj没有__str__()方法,则调用obj.__repr__()方法返回的字符串
        3、如果obj没有__repr__()方法,则调用object类的__repr__()实例方法显示<XXXXX>格式的字符串

   4、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 = valuedef __repr__(self):print("__repr__被调用")return "MyNumber(%d)"% self.datadef __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.datadef __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):
               ....
    作用:
        1、用于bool(obj)函数取值
        2、用于if语句真值表达式中
        3、用于while语句真值表达式中
    说明:
        1、优先调用__bool__方法取值
        2、如果不存在__bool__方法,则用__len__()方法取值,后判断是否为零值,如果不为零返回True,否则返回False
        3、如果再没有__len__方法,则直接返回True

class MyList():def __init__(self,iterator=[]):self.data = [x for x in iterator]def __repr__(self):return "MyList(%r)" % self.datadef __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__,再没有直接返回Truepass
while myl2:#在此处会查找__bool__,如果没有再查找__len__,再没有直接返回Truepass

View Code

迭代器(高级):
    什么是迭代器
        可以通过next(it)函数取值的对象就是迭代器
    迭代器协议:
        迭代器协议是指对象能够使用next函数获取下一项数据,在没有下一项数据是触发StopIterator来终止迭代的约定
    实现方法:
        类内需要有__next__(self)方法来实现迭代器协议
    语法形式:
        class MyIterator:
            def __next__(self):
                迭代器协议的实现
                return 数据
什么是可迭代对象:
    1、是指能用iter(obj)函数返回迭代器的对象(实例)
    2、可迭代对象内部一定要定义__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.datadef __iter__(self):'''有此方法就是可迭代对象,但要求必须返回迭代器'''print("__iter__方法被调用")return MyListIterator(self.data)
class MyListIterator:'''此类用来创建一个迭代器对象,用此迭代器对象可以迭代访问MyList类型的数据'''def __init__(self,iter_data):self.cur = 0 #设置迭代器的初始值为0代表列表下标self.iter_data = iter_datadef __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

对象的属性管理函数:
    1、getattr(obj,name[,dafault])    从一个对象得到对象的属性;gettattr(x,'y')等同于x.y;当属性y不存在时,如果有default参数,则返回default,如果没有给出default则产生一   个AttributeError错误
    2、hasattr(obj,name)     用给定的name返回obj是否有属性,如果有返回True,否则返回False,此种做法可以避免在getattr(obj,name)时引发错误
    3、setattr(obj,name,value)  给对象obj的名为name的属性设置相应的值value,setattr(x,'y',v)等同于x.y = v
    4、delattr(obj,name) 删除对象obj中的name属性,delattr(x,'y')等同于del x.y

class Car:def __init__(self,c,b):self.color = cself.brand = bdef 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

运算符重载:
    什么是运算符重载
        让自定义的类生成的对象(实例)能够使用运算符进行操作
    作用:
        1、让自定义的类的实例像內建对象一样运行运算符操作
        2、让程序简洁易读
        3、对自定义的对象,将运算符赋予新的运算规则

算术运算符的重载:
    __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 = vdef __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.datareturn MyNumber(v)def __sub__(self,other):v = self.data - other.datareturn 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 = iterabledef __repr__(self):return 'MyList(%s)' % self.data  def __mul__(self,rhs):v = self.data * rhsreturn MyList(v)def __add__(self,other):v = self.data +other.datareturn MyList(v)def __rmul__(self,lhs):return MyList(self.data*lhs)def __iadd__(self,other):self.data.extend(other.data)#此出是改变self本身,返回值为Nonereturn 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 = iterabledef __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 = iterabledef __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 Truereturn 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 = iterabledef __repr__(self):return 'MyList(%r)' % self.data  def __getitem__(self,i):print("__getitem__被调用,i=",i)if type(i) is not int:raise TpyeErrorreturn 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 = iterabledef __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 KeyErrorreturn 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

类的特殊成员

  1、__call__()方法

class Foo:def __init__(self):print("init")def __call__(self):print("call")Foo()()#首先会执行__init__()方法,再执行__call__()方法
obj = Foo()#执行__init__()方法
obj()#执行__call__()方法

metaclass(类的祖宗)

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

  2、class Foo:

      pass

    obj = Foo()

    #obj是对象,Foo类的对象

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

  3、类都是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__方法

  

转载于:https://www.cnblogs.com/xdl-smile/p/9346948.html

python_面向对象相关推荐

  1. Python_面向对象_类1

    面向对象:减少重复代码,提高效率,比函数式编程更高效 类的创建: 实例属性又称:成员变量,成员属性(或者字段) 面向对象的三大特性: 一.封装 把客观事物封装为抽象的类,并对外只暴露一个可用接口 使用 ...

  2. python_面向对象编程

    一.面向对象编程 # 1.什么是面向对象 面向过程与面向对象面向过程编程:解决问题从过程出发,解决问题步骤化面向对象编程:解决问题从对象出发,解决问题找对象对象与类类:对象的类型 => 数字具有 ...

  3. 什么是继承python_面向对象继承

    Python 面向对象继承 一 什么是面向对象的继承 比较官方的说法就是: 继承(英语:inheritance)是面向对象软件技术当中的一个概念.如果一个类别A"继承自"另一个类别 ...

  4. python_面向对象的各种实现对比介绍

    一.面向过程VS面向对象 1.面向过程: 面向过程是一开始要着手解决一个大问题,然后分解成一个个小问题, 直到小问题能够很好地解决, 但是小问题之间可能存在依赖性,仅仅适合进行简单脚本的编写, 不适合 ...

  5. python_面向对象进阶之元类

    1:在一个py文件中,创建一个类 在另外一个py文件中,引用这个类 创建一个Person类的实例是在第6行 类是在第4行创建的** from引入模块之后,则动态的创建一个Person类(因为引入时,会 ...

  6. python_面向对象进阶之slots

    slots:限制类动态的增加属性 slots = ('name','sex'):只允许当前Student拥有name和age属性

  7. python_面向对象进阶之属性值的限制

    需求:限制属性值age范围在0~88 代码如下: 装饰器@property:把age属性暴漏出去,函数名字就是属性名字 假设只暴露@property下的函数,没有暴露@age.setter下的函数:表 ...

  8. python_面向对象进阶之多继承

    例如1 如果多个父类中有相同的函数,按照优先级来调用 通过Child.__mro__可以查看Child的继承优先级 继承优先级为: (<class 'main.Child'>, <c ...

  9. Python_面向对象_递归

    --递归本质 函数调用是通过栈(stack)这种数据结构实现的 每当进入一个函数调用,栈区就会加一层栈帧, 每当函数返回,栈区就会减一层栈帧,但栈区空间有限,要注意防止栈溢出 # 递归函数:在函数内部 ...

最新文章

  1. .Net 转战 Android 4.4 日常笔记(7)--apk的打包与反编译
  2. cProfile——Python性能分析工具
  3. 用聪明的方式学习Vim,不再死记硬背,复杂命令一学就会 | GitHub 2200星
  4. vscode 加参数运行_VSCode 调试 Webpack 指南
  5. Servlet到底是个什么东西???【【博采众长】】
  6. Servlet3 -- Servlet异步处理
  7. 终结“永恒之蓝”后,再战“永恒之黑”
  8. 测试自己幸运数字的软件,心理测试:选一个你的幸运数字,测一下你最近会有什么好事发生?...
  9. java 怎样 thread dump_怎样分析 JAVA 的 Thread Dumps
  10. .net Remoting学习笔记(二)
  11. 30 System类
  12. windows批处理bat脚本实现微信告警——监控系统WGCLOUD
  13. <数据结构> 顺序表
  14. 当浏览器是ie11以前版本的,跳转到ie升级页
  15. 新手自己搭建服务器步骤
  16. 西门子官网下载Eplan部件库
  17. Could not connect to archive.ubuntukylin.com:10006 (120.240.95.35), connection timed out
  18. 解决Invalid HTTP_HOST header: 'xxx.xx.xxx.xxx:8000'. You may need to add 'xxx.xx' to ALLOWED_HOSTS!
  19. 保持程序员的健康—请练八段锦
  20. 运维系统常用健康度模型浅析

热门文章

  1. Lintcode 988解题思路和c++代码
  2. 全面对比 MATLAB、Julia、Python,谁在科学计算中更胜一筹?
  3. 机器人也是“艺术家”!上海世界移动大会聚焦5G时代
  4. mongodb java 学习_MongoDB学习(四):通过Java使用MongoDB
  5. redis的持久化方式有哪些?
  6. 010_jQuery获取和设置内容属性
  7. sqoop同步hdfs与mysql端口_使用Sqoop将数据在HDFS与MySQL互导
  8. 用动态数组模拟双向循环链表
  9. Kotlin极简教程:第4章 基本数据类型与类型系统
  10. LinkedList源码剖析