python_面向对象
面向对象编程
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_面向对象相关推荐
- Python_面向对象_类1
面向对象:减少重复代码,提高效率,比函数式编程更高效 类的创建: 实例属性又称:成员变量,成员属性(或者字段) 面向对象的三大特性: 一.封装 把客观事物封装为抽象的类,并对外只暴露一个可用接口 使用 ...
- python_面向对象编程
一.面向对象编程 # 1.什么是面向对象 面向过程与面向对象面向过程编程:解决问题从过程出发,解决问题步骤化面向对象编程:解决问题从对象出发,解决问题找对象对象与类类:对象的类型 => 数字具有 ...
- 什么是继承python_面向对象继承
Python 面向对象继承 一 什么是面向对象的继承 比较官方的说法就是: 继承(英语:inheritance)是面向对象软件技术当中的一个概念.如果一个类别A"继承自"另一个类别 ...
- python_面向对象的各种实现对比介绍
一.面向过程VS面向对象 1.面向过程: 面向过程是一开始要着手解决一个大问题,然后分解成一个个小问题, 直到小问题能够很好地解决, 但是小问题之间可能存在依赖性,仅仅适合进行简单脚本的编写, 不适合 ...
- python_面向对象进阶之元类
1:在一个py文件中,创建一个类 在另外一个py文件中,引用这个类 创建一个Person类的实例是在第6行 类是在第4行创建的** from引入模块之后,则动态的创建一个Person类(因为引入时,会 ...
- python_面向对象进阶之slots
slots:限制类动态的增加属性 slots = ('name','sex'):只允许当前Student拥有name和age属性
- python_面向对象进阶之属性值的限制
需求:限制属性值age范围在0~88 代码如下: 装饰器@property:把age属性暴漏出去,函数名字就是属性名字 假设只暴露@property下的函数,没有暴露@age.setter下的函数:表 ...
- python_面向对象进阶之多继承
例如1 如果多个父类中有相同的函数,按照优先级来调用 通过Child.__mro__可以查看Child的继承优先级 继承优先级为: (<class 'main.Child'>, <c ...
- Python_面向对象_递归
--递归本质 函数调用是通过栈(stack)这种数据结构实现的 每当进入一个函数调用,栈区就会加一层栈帧, 每当函数返回,栈区就会减一层栈帧,但栈区空间有限,要注意防止栈溢出 # 递归函数:在函数内部 ...
最新文章
- .Net 转战 Android 4.4 日常笔记(7)--apk的打包与反编译
- cProfile——Python性能分析工具
- 用聪明的方式学习Vim,不再死记硬背,复杂命令一学就会 | GitHub 2200星
- vscode 加参数运行_VSCode 调试 Webpack 指南
- Servlet到底是个什么东西???【【博采众长】】
- Servlet3 -- Servlet异步处理
- 终结“永恒之蓝”后,再战“永恒之黑”
- 测试自己幸运数字的软件,心理测试:选一个你的幸运数字,测一下你最近会有什么好事发生?...
- java 怎样 thread dump_怎样分析 JAVA 的 Thread Dumps
- .net Remoting学习笔记(二)
- 30 System类
- windows批处理bat脚本实现微信告警——监控系统WGCLOUD
- <数据结构> 顺序表
- 当浏览器是ie11以前版本的,跳转到ie升级页
- 新手自己搭建服务器步骤
- 西门子官网下载Eplan部件库
- Could not connect to archive.ubuntukylin.com:10006 (120.240.95.35), connection timed out
- 解决Invalid HTTP_HOST header: 'xxx.xx.xxx.xxx:8000'. You may need to add 'xxx.xx' to ALLOWED_HOSTS!
- 保持程序员的健康—请练八段锦
- 运维系统常用健康度模型浅析
热门文章
- Lintcode 988解题思路和c++代码
- 全面对比 MATLAB、Julia、Python,谁在科学计算中更胜一筹?
- 机器人也是“艺术家”!上海世界移动大会聚焦5G时代
- mongodb java 学习_MongoDB学习(四):通过Java使用MongoDB
- redis的持久化方式有哪些?
- 010_jQuery获取和设置内容属性
- sqoop同步hdfs与mysql端口_使用Sqoop将数据在HDFS与MySQL互导
- 用动态数组模拟双向循环链表
- Kotlin极简教程:第4章 基本数据类型与类型系统
- LinkedList源码剖析