python 面向对象
面向对象
对象:是指现实中的物体实体化,对象有很过属性(名字、年龄..),也有很多行为(学习、吃饭..),实例即对象。对象同时也是通过类定义的数据结构实例,对象包括两个数据成员(类变量和实例变量)和方法。对象可以包含任意数量和类型的数据。
实例化:创建一个类的实例,类的具体对象化,实例就是类的实例化,d1 = gog(),d1即为实例
类:拥有相同属性和方法(行为)的对象划为一组,称为类,类是创建对象的工具
方法:类中定义的函数
类变量:在类中被定义的变量,通常以self.variable的形式被定义,类变量通常不作为实例变量使用
方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行修改,这个过程叫方法的覆盖,也叫方法的重写
继承:及一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。
Python中的类提供了面向对象编程的所有基本功能:类的继承机制允许多个基类,派生类可以覆盖基类中的任何方法,方法中可以调用基类中的同名方法。
类定义 语法格式
class 类名(继承列表):
"""类的文档字符串"""
类变量的定义
实例方法的定义
类方法的定义(@classmethod)
静态方法的定义(@staticmethod)
作用:
创建一个类,类用于描述对象的行为和属性,类用于创建此类的一个或者多个对象(实例)类名实质上是变量,它绑定一个类
类的文档字符串
类内第一个没有赋值给任何变量的字符串为类的文档字符串,类的文档字符串可以用类的 __doc__属性访问
help(Dog) 查看文档字符串
类.__doc__属性用来绑定文档字符串
类变量的定义
类变量就类的属性,此属性属于类,不属于此类的实例
作用:通常用来存储该类创建的对象的共有属性
说明:类变量可以通过该类或该类的实例直接访问;类变量可以通过此类的实例对象的__class__属性间接访问
class Human: total_count = 0 # 类变量 def __init__(self, name): print(name, '对象被创建') print(Human.total_count) # 类直接访问类变量 0 h1 = Human('小张') print(h1.total_count) # 0 用此类的实例可以访问类变量 h1.total_count = 100 # 为对象添加实例变量 print(h1.total_count) # 100, 优先访问对象的实例变量 print(Human.total_count) # 0, 访问类的类变量 print(h1.__class__.total_count) # 0 通过此类的实例对象的__class__属性来访问类变量
初始化方法 __init__()
1、初始化方法__init__()会在构造函数创建实例后自动调用
2、初始化方法如果需要return语句返回,则只能返回None
3、一般类都会倾向于将(实例)对象创建为有初始化状态的
4、实例方法至少有一个形参,第一个形参代表调用这个方法的实例,一般命名为'self',因此类可能会定义一个名为__init__()的特殊方法(构造方法)
5、__init__有形参时,参数会通过__init__()传递到实例化对象上。
class complex: # 构造函数,在实例化时做一些类的初始化工作,__init__用来传参的 def __init__(self, name, age): # 定义类的方法 self.name = name # 实例变量(静态属性) self.age = age x = complex("作者",23) # 类的实例化,变成具体对象 print(x.name,x.age) # 作者 23
类的方法与普通的函数只有一个特殊的区别————他们必须有一个额外的第一参数名称self,按照惯例它的名称是self,谁调用这个类的方法,self就指向谁。self代表类的实例化,而非类
class Test: #定义一个名为Test的类 def prt(self): #定义类的方法prt print(self) print(self.__class__) # self.__class__指向类 t = Test() #类的实例化 t.prt() #访问类的方法 # <__main__.Test object at 0x000001836DFE10B8> # <class '__main__.Test'>
self代表的是类的实例,代表当前对象的地址,而self.__class__则指向类名。
self不是python的关键词,我们把self换成其他的表示符也是可以的(在这里我们把self换成runoob)
class Test: # 定义一个名为Test的类 def prt(runoob): # 定义类的方法prt print(runoob) print(runoob.__class__) t = Test() # 类的实例化 t.prt() # 访问类的方法 # <__main__.Test object at 0x000001836DFE10B8> # <class '__main__.Test'>
类的__slots__列表
作用:限定一个类创建的实例只能有固定属性(实例属性),不允许对象添加列表以外的属性(实例变量)
说明:__slots__列表绑定一个字符串列表,含有__slots__列表的类所创建的实例对象没有__dict__属性,即此实例不用字典来存储对象的属性(实例变量)
__slots__ = [" ", " "]
class Human: # 以下列表限制此类的对象只能有'name' 和'age' 属性 __slots__ = ['name', 'age'] def __init__(self, name, age): self.name, self.age = name, age h1 = Human("Tarena", 15) print(h1.age) # 15 # h1.Age = 18 # 出错,h1对象没有Age属性,也不允许有Age属性 print(h1.age) # 15
类方法 @classmethod
类方法是用于描述类的行为的方法,类方法属于类,不属于类的实例
说明:类方法需要使用@classmethod装饰器定义,
def关键词来定义一个方法,类方法至少有一个形参,第一个参数用于绑定类,约定写为" cls ",类和该类的实例都可以调用类的方法
class people: # 定义一个类 # 定义类的属性 name = '' age = 0 # 定义私有属性,私有属性在类外部无法直接进行访问 _weight = 0 # 定义构造的方法 def __init__(self, n, a, w): # 定义类的初始化属性 self.name = n self.age = a self._weight = w # 定义类的方法 @classmethod def speak(cls): print("%s说:我%d岁" % (self.name, self.age)) # 实例化类 把一个类变成具体对象叫做类的实例化 p = people("作者", 18, 30) p.speak() # 作者说:我18岁
静态方法 @staticmethod
静态方法是定义在类内部的函数,此函数的作用域是类的内部
说明:静态方法需要使用 @staticmethod装饰器定义,
静态方法与普通函数定义相同,不需要传入self实例参数和cls参数,静态方法只能凭借该类或类创建的实例调用,静态方法不能访问类变量和实例变量(属性)
class A: @staticmethod def myadd(a, b): return a + b print(A.myadd(100, 200)) # 300 a = A() # 创建实例 print(a.myadd(300, 400)) # 700
实例方法、类方法、静态方法、函数小结
不想访问类内和实例内的变量,用静态方法
只想访问类内变量,不想访问实例变量,用类方法
即要访问内变量,也想访问实例变量用实例方法
函数与静态方法相同,只是静态方式的作用域定义在类内
class Classname: @staticmethod def fun(): print('静态方法') @classmethod def a(cls): print('类方法') # 普通方法 def b(self): print('普通方法') Classname.fun() # 静态方法 Classname.a() # 类方法 C = Classname() C.fun() # 类方法 C.a() # 类方法 C.b() # 普通方法
类的实例化
类实例化后,可以使用其属性,实际上,创建一个类之后,可以通过类名访问其属性
d1 = dog() # 调用构造函数创建实例化对象
类对象
类对象支持两种操作:属性引用和实例化。
类对象创建后,类命名空间中的所有命名都是有效属性名,类定义如下所示:
class Myclass: # 定义一个自己的类 """一个简单的类实例""" i = 12345 # 类变量 def f(self): # 定义类的方法 return "你好呀" # 类的实例化,用x来绑定以便后面使用,不然用完之后就释放了 x = Myclass() # 把一个类变成具体对象的过程叫做实例化(初始化) # 访问类的属性和方法 print("Myclass类的属性i:", x.i) # 12345 print("Myclass类的方法f:", x.f()) # 你好呀!
python支持 在类的外面 创建类的属性
class Dog: def eat(self, food): # print("小狗正在吃:", food) print(self.color, '的', self.kinds, '正在吃', food) dog1 = Dog() # 类的实例化 dog1.kinds = '京巴' # 为dog1对象添加kinds属性,绑定为'京巴' dog1.color = '白色' # dog1添加属性 为'白色' dog1.color = '黄色' # 改变dog1的color属性 # 访问dog1 的属性 print(dog1.color, "的", dog1.kinds) # 黄色 的 京巴 dog2 = Dog() dog2.kinds = '哈士奇' dog2.color = '黑白相间' print(dog2.color, '的', dog2.kinds) # 黑白相间 的 哈士奇 dog1.eat('骨头') # 黄色 的 京巴 正在吃 骨头 dog2.eat('窝头') # 黑白相间 的 哈士奇 正在吃 窝头
# 定义私有属性,私有属性在类外部无法直接进行访问 __weight = 0,在变量前面加双下划线
删除属性del语句
del 变量名 删除变量
del 列表[整数表达式] 删除列表中的元素
del 字典[键] 删除字典中的键
del 对象.属性 删除对象的属性
析构方法:
class 类名:
def __del__(self):
......
说明:析构方法在对象被销毁时做任何事情,因为销毁的时间难以确定
预置实例属性:
__dict__属性
__dict__属性绑定一个存储此实例自身变量的字典
class Dog: pass dog1 = Dog() print(dog1.__dict__) # {} dog1.kinds = '京巴' print(dog1.__dict__) # {'kinds': '京巴'}
__class__属性:
此属性用于绑定创建此实例的类
作用:可以借助于此属性来访问创建此实例的类
class Dog: pass dog1 = Dog() print(dog1.__class__) # <class '__main__.Dog'> dog2 = dog1.__class__() print(dog2.__class__) # <class '__main__.Dog'>
用于类的函数:
isinstance(obj, class_or_tuple) 返回这个对象obj是否是某个类的对象或某些类中的一个类的对象,如果是则返回True,否则返回False,type(obj) 返回对象的类型
继承/派生
继承是指从已有的类中派生出新的类,新类具有原类的行为,并能扩展新的行为
派生类就是从一个已有类中衍生成新类,在新类上可以添加新的属性和行为
作用:1.用继承派生机制,可以将一些共有功能加在基类中,实现代码的共享
2、在不改变基类的代码的基础上改变原有的功能
名词:基类(base class)/超类(super class)/父类(father class)
派生类(derived class) / 子类(child class)
单继承
单继承:
语法:
class 类名(基累名):
语句块
说明:单继承是指由一个基类衍生出的新的类
class Derived_Class_Name(Base_Class_Name1): <statement-1> . . <statement-N>
单继承实例
class Human: # 人类的共性 def say(self, what): print("say:", what) def walk(self, distance): # 走路 print("走了", distance, '公里') class Student(Human): def study(self, subject): print("正在学习:", subject) class Teacher(Student): '''说话,行走,教学''' def teach(self, subject): print("正在教:", subject) h1 = Human() h1.say('天气晴了') h1.walk(5) print('---------------') s1 = Student() s1.walk(4) s1.say('感觉有点累') s1.study('Python') print('===============') t1 = Teacher() t1.walk(6) t1.say('吃点啥好呢') t1.teach('面向对象') t1.study('转魔方')
继承说明:python3 任何类都直接或间接的继承自object类,object 类是一切类的超类
类的__base__属性:__base__属性用来记录此类的基类
覆盖
覆盖是指在有继承关系的类中,子类中实现了与基类同名的方法,在子类的实例调用该方法时,实际调用的是子类中的覆盖版本
class A: def works(self): print("A.works被调用") class B(A): """B类继承A类""" def works(self): print("B.works被调用") a = A() a.works() # A.works被调用 b = B() b.works() # B方法被调用
用类名显式调用
子类对象显式调用基类(被覆盖)方法的方式:基类名.方法名(实例, 实际调用传参)
class A: def works(self): print("A.works被调用") class B(A): ''' B类继承自A类''' def works(self): print("B.works被调用") b = B() b.works() # B.works被调用 A.works(b) # 用类名显式调用, A.works被调用
super函数
super(cls, obj)返回绑定超类的实例(要求obj必须是cls类型的实例),一般obj就是self。cls一般就是当前类的类名。
super() 返回父类的实例,
常见用法:super(__class__, 实例方法的第一个参数),必须在方法内调用,一般super(class_name, self).父类方法 # 中间参数可以省略,如下例
作用:借助super() 返回的实例间接调用其父类的覆盖方法
super().父类方法()
class A: def works(self): print("A.works被调用") class B(A): """B类继承自A类""" def works(self): print("B.works被调用") def super_work(self): self.works() # B.works被调用 super(B, self).works() # A.works被调用 super().works() # A.works被调用 b = B() b.works() # B.works被调用 super(B, b).works() # A.works被调用 b.super_work() # ... # B.works被调用 # A.works被调用 # A.works被调用 super().works() # 出错,只能在方法内调用
显式调用基类的初始化方法
当子类中实现了 __init__方法,基类的构造方法并不会被调用,def __init__(self, ...)
super().__init__(n,a) # 参数不填的话,默认调用父类的所有初始化参数
class Human: def __init__(self, n, a): self.name, self.age = n, a print("Human的__init__方法被调用") def infos(self): print("姓名:", self.name) print("年龄:", self.age) class Student(Human): def __init__(self, n, a, s=0): super().__init__(n, a) # 显式调用父类的初始化方法 self.score = s # 添加成绩属性 print("Student类的__init__方法被调用") def infos(self): super().infos() # 调用父类的方法 print("成绩:", self.score) s1 = Student('小张', 20, 100) s1.infos()
多继承
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 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 sample(speaker, people): a = '' def __init__(self, n, a, w, t): # 调用父类的构函数 people.__init__(self, n, a, w) speaker.__init__(self, n, t) test = sample('凌逆战', "大学生", 23, 'python') test.speak() # 方法名重复了,默认调用的是括号中排前地父类的方法 # 我叫 凌贤鹏,我是一个演说家,我演讲的主题是 python
方法重写
如果父类方法的功能不能满足需求,可以在子类重写父类的方法
class parent: # 定义父类 def my_method(self): print("调用父类的方法") class child(parent): # 定义子类 def my_method(self): print("调用子类方法") c = child() # 子类实例 # 子类调用重写方法 c.my_method() # 调用子类方法 # 用子类对象调用父类已被覆盖的方法 super(child, c).my_method() # 调用父类的方法
super()函数是用于调用父类(超类)的方法
类属性与方法
类的私有属性
__private_attrs:两个写划线开头,声明该属性为私有类,不能在类地外部被使用或直接访问,在类内部的方法使用时self.private_attrs。
类的方法
在类地内部,使用def关键字来定义一个方法,与一般函数定义不同,类方法必须包含self,且为第一个参数,self代表的是类的实例。
self的名字并不是规定死的,也可以是其他的,但最好按照规定用self
类的私用方法
__private_method:两个下划线开头,声明该方法为私有方法,只能在类的内部调用 ,不能在类地外部调用。self.__private_methods。
类的私有属性
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.__secretCount) # 报错,实例不能访问私有变量 # Traceback (most recent call last): # File "test.py", line 16, in <module> # 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('菜鸟教程', 'www.runoob.com') x.who() # 正常输出 x.foo() # 正常输出 x.__foo() # 报错
类的专有方法
Python除了自定义私有变量和方法外,还可以定义专有方法。专有方法是在特殊情况下或使用特殊语法时由python调用的,而不是像普通方法一样在代码中直接调用。看到形如__XXX__的变量或函数名时就需要注意下,这在python中是有特殊用途的
- __init__:构造函数,在生成对象时调用
- __del__:析构函数,释放对象时使用
- __repr__:打印,转换
- __setitem__ :按照索引赋值
- __getitem__:按照索引获取值
- __len__:获得长度
- __str__:返回用户看到的字符串
- __iter__:返回可迭代对象
- __cmp__:比较运算
- __call__:使类像函数一样调用
- __add__:加运算
- __sub__:减运算
- __mul__:乘运算
- __div__:除运算
- __mod__:求余运算
- __pow__:乘方
__str__
class Student(object): def __init__(self, name): self.name = name print(Student('zth')) # <__main__.Student object at 0x03DFDDB0>
__str__方法必须要return一个字符串类型的返回值,
class Student(object): def __init__(self, name): self.name = name def __str__(self): return "学生的姓名:%s"%self.name print(Student('zth')) # 学生的姓名:zth
__iter__
__iter__() 方法返回一个特殊的迭代器对象, 这个迭代器对象实现了 __next__() 方法并通过 StopIteration 异常标识迭代的完成。__next__() 方法会返回下一个迭代器对象。
如果想要将一个类用于 for ... in 循环,类似 list 或 tuple 一样,就必须实现一个__iter__() 方法。该方法返回一个迭代对象,Python 的 for 循环会不断调用该迭代对象的 __next__() 方法,获得循环的下一个值,直到遇到 StopIteration 错误时退出循环。
class Fib(object): def __init__(self): self.a , self.b = 0,1 # 初始化两个计数器 a、b def __iter__(self): return self # 实例本身就是迭代对象。故返回自己 def __next__(self): self.a ,self.b = self.b ,self.a+self.b # 计算下一个值 if self.a > 100: # 退出循环的条件 raise StopIteration(); return self.a # 返回下一值 for n in Fib(): print(n)
1 1 2 3 5 8 13 21 34 55 89
__getitem__
上面创建的对象虽然能够作用于 for 循环,和 list 有点像,但是不能将它当成 list 使用。比如取第3个元素:
>>> Fib()[3] Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'Fib' object does not support indexing
若要像list一样按照索引来获取元素,需要实现__getitem__()方法
class temp(): def __init__(self): self.a = [1, 2, 3, 4, 5] def __getitem__(self, index): return self.a[index] if __name__ == "__main__": shili = temp() print(shili[3]) # 4
使用 __getitem__ 和 __iter__ 可以使类成为一个迭代器
# -*- coding: utf-8 -*- class Library(object): def __init__(self): self.books = { 'title' : 'a', 'title2' : 'b', 'title3' : 'c', } def __getitem__(self, i): return self.books[i] def __iter__(self): # 方法1 使用生成器 for titles in self.books: yield self.books[titles] # 方法2 使用迭代器 # return self.books.itervalues() library = Library() # 1.普通方法 print library.books['title'] # 2.使用__getitem__ print library['title'] # 3.迭代器 for book in library: print book
__call__
定义一个__call__()方法,就可以直接对实例进行调用
class temp(): def __call__(self, a, b): return a+b if __name__ == "__main__": shili = temp() ab_sum = shili(1,2) print(ab_sum) # 3
参考:https://blog.csdn.net/qq_41573234/article/details/82316207
运算符重载
class Vector: def __init__(self, a, b): self.a = a self.b = b def __str__(self): return 'Vector (%d, %d)' % (self.a, self.b) def __add__(self, other): return Vector(self.a + other.a, self.b + other.b) v1 = Vector(2, 10) v2 = Vector(5, -2) print(v1 + v2) # Vector(7,8)