面向对象
类和对象
类:定义数据(属性)和行为(方法),
对象:类的实例
## 定义类
class Student:
def __init__(self,name,age):
self.name = name
self.age = age
def show(self):
print ("name:{0},age:{1}".format(self.name,self.age))
## 声明对象
stu = Student('jack','25')
stu.show()
1. 构造函数
构造函数:_init_(),用来初始化对象。创建对象时先调用类的_new_()方法创建对象,然后调用_init_()方法初始化对象。
_init_()函数第一个参数必须是self,self指的就是当前对象。
构造函数没有返回值.
2. 实例属性
实例属性是从属于实例对象的属性,也称为"实例变量"。他的使用有以下几个要点:
- 实例属性一般在__init__()方法中通过如下代码定义:
self.实例属性名=初始值 - 在本类的其他实例方法中,也是通过self进行访问
self.实例属性名 - 创建实例对象后,通过实例对象访问属性
3. 实例方法
定义实例方法时,第一个参数必须是self,self指的是当前实力对象
调用实例方法时,不需要给self传参,self由解释器自动传参。
## 定义类
class Student:
def __init__(self,name,age):
self.name = name
self.age = age
def show(self):
print ("name:{0},age:{1}".format(self.name,self.age))
## 声明对象
stu = Student('jack','25')
stu.show()
## 等价于
Student.show(stu)
4. 其他操作
dir(obj):可以获得对象的所有属性和方法
obj.dict:对象的属性字典
pass : 空语句
isinstance(对象,类):判断对象是不是属于类
class Student:
def __init__(self,name,age):
self.name = name
self.age = age
def show(self):
print ("name:{0},age:{1}".format(self.name,self.age))
## 声明对象
stu = Student('jack','25')
print(dir(stu))
print(stu.__dict__)
print(isinstance(stu,Student))
5. 类对象
类对象:“class 类名”,当解释器执行class语句时,就会创建一个类对象。类对象的类型是type
class Student:
pass
## 声明对象
print(type(Student))
Stu = Student
s1 = Stu() #创建对象
print(id(s1 ))
6. 类属性
类属性:从属于“类对象”的属性,也成为“类变量”。类属性可以被所有实例对象共享。类属性通过以下方式定义
class 类名:类变量名=初始值 在类的外面通过“类名.类属性”方式访问。
class Student:
company = "future"
card_no = 0
def __init__(self,name,age):
self.name = name
self.age = age
Student.card_no +=1
def show(self):
print ("name:{0},age:{1},no:{2}".format(self.name,self.age,Student.card_no))
## 声明对象
stu1 = Student('jack','25')
stu1.show()
stu2 = Student('rose','22')
stu2.show()
print(Student.card_no)
其中对象stu1在内存中的存储如下图所示
7. 类方法
类方法:从属于“类对象”的方法。类方法通过@classmethod来定义,格式如下:
@classmethod
def 类方法名(cls[,形参列表]):
函数体
类方法的定义需要注意以下几点
- @classmethod必须位于方法上面一行
- 第一个cls必须有,cls指的就是“类对象”本身
- 调用类方法格式:“类名.类方法名(参数列表)”,参数列表不需要也不能给cls传值
- 类方法中不能访问实例属性和实例方法
- 子类继承父类时,传入cls是子类对象,而不是父类对象。
class Student:
company = "future"
card_no = 0
def __init__(self,name,age):
self.name = name
self.age = age
Student.card_no +=1
@classmethod
def printCompany(cls):
print (cls.company)
def show(self):
print ("name:{0},age:{1},no:{2}".format(self.name,self.age,Student.card_no))
## 声明对象
stu1 = Student('jack','25')
stu1.show()
stu1.printCompany()
8. 静态方法
静态方法:与“类对象”无关的方法。静态方法通过@staticmethod来定义,不操作类的属性,和普通函数的功能一样,只是定义在了类中。
@staticmethod
def 静态方法名(参数列表):
函数体
类方法的定义需要注意以下几点
- @staticmethod必须位于方法上面一行
- 调用类方法格式:“类名.静态方法名(参数列表)”
- 类方法中不能访问实例属性和实例方法
class Student:
company = "future"
card_no = 0
def __init__(self,name,age):
self.name = name
self.age = age
Student.card_no +=1
@classmethod
def printCompany(cls):
print (cls.company)
@staticmethod
def add(a,b):
sum = a+b
print (sum)
return sum
def show(self):
print ("name:{0},age:{1},no:{2}".format(self.name,self.age,Student.card_no))
## 声明对象
stu1 = Student('jack','25')
stu1.show()
stu1.printCompany()
Student.add(1,2)
9. __call__方法和可调用对象
定义了__call__方法的对象,成为"可调用对象",即该对象像函数一样被调用。
class Student:
company = "future"
card_no = 0
def __call__(self,name,age):
self.name = name
self.age = age
def show(self):
print ("name:{0},age:{1},no:{2}".format(self.name,self.age,Student.card_no))
## 声明对象
stu1 = Student()
stu1('jack','25')
stu1.show()
10. 方法没有重载
Python中没有方法的重载。因为python中参数没有类型,参数数量也由可变参数控制。
class Student:
def show(self):
print ("name:none")
def show(self,name):#覆盖上面的show函数
print ("name:{0}".format(name))
## 声明对象
stu1 = Student()
stu1.show("jack")
stu1.show() #报错
11. 私有属性和方法
Python对于类的成员没有严格的访问限制,私有属性和私有方法有以下要点:
- 通常约定两个下划线开头的属性是私有的(private),其他为公共的(public)
- 类内部可以访问私有属性(方法)
- 类外部不能直接访问私有属性(方法)
- 类外部可以通过“__类名__私有属性(方法)名”访问私有属性(方法)
class Employee:
__company = "future" ##私有属性
def __init__(self,name,age):
self.name = name
self.__age = age #私有属性
def __work(self): #私有方法
print("private function")
print(Employee.__company) #私有方法调用私有属性
## 声明对象
emp1 = Employee('jack',25)
print(emp1.name)
print(emp1._Employee__age)
print(emp1.age) ##报错
e._Employee__work() #调用私有方法
print(Employee._Employee__company)
12. @property装饰器
@property可以将方法转换为属性,转换成属性时不能给该属性赋值
class Employee:
@property
def salary(self):
return 10000
## 声明对象
emp1 = Employee()
#emp1.salary()
print(emp1.salary)
#不能赋值
#emp1.salary = 20000
13. 面向对象的三大特征
13.1 封装
封装:隐藏对象的属性和实现细节,只对外提供必要的方法。相当于将“细节封装起来”,只对外暴露“相关调用方法”。通过“私有对象”、“私有方法”实现“封装”。
13.2 继承
继承:继承可以让子类具有父类的特性,提高了代码的重用性。Python支持多重继承,一个子类可以继承多个父类。继承的语法如下
class 子类类名(父类1[,父类2,...])
类体
子类必须显示继承构造函数
class People():
def __init__(self,age,name):
self.age = age
self.name = name
def say_info(self):
print("age:{0},name:{1}".format(self.age,self.name))
class Student(People):
def __init__(self,age,name,score):
People.__init__(self,age,name) #显示调用父类构造函数
self.score=score
def show_info(self):
print("age:{0},name:{1},score:{2}".format(self.age,self.name,self.score))
stu = Student("lily",20,80)
stu.say_info()
stu.show_info()
13.2.1 成员继承
成员继承:子类继承了父类除构造方法之外的所有成员(包括私有属性),虽然继承了私有属性,但是私有属性不能够直接被子类访问
13.2.2 多重继承
一个子类可以有多个“直接父类”,这样就具备了“多个父类”的特点,多重继承会被“类的整体层次”搞的异常复杂,尽量避免使用。
mro():方法解析顺序。通过mro()方法获得“类的层次结构”,适用于多重继承。
class People():
def __init__(self,age,name):
self.age = age
self.name = name
def say_info(self):
print("age:{0},name:{1}".format(self.age,self.name))
class Chinese():
def __init__(self,id_card):
self.id_card = id_card
def say_info(self):
print("id_card:{0}".format(self.id_card))
class Student(People,Chinese):
def __init__(self,age,name,score,id_card):
People.__init__(self,age,name) #显示调用父类构造函数
Chinese.__init__(self, id_card) # 显示调用父类构造函数
self.score=score
def show_info(self):
print("age:{0},name:{1},score:{2}".format(self.age,self.name,self.score))
stu = Student("lily",20,80,"013234")
stu.say_info()
print(Student.mro())
13.2.3 方法重写
方法重写:子类可以重新定义父类中的方法,这样会覆盖父类的方法,称为“重写”
class People():
def __init__(self,age,name):
self.age = age
self.name = name
def say_info(self):
print("age:{0},name:{1}".format(self.age,self.name))
class Student(People):
def __init__(self,age,name,score):
People.__init__(self,age,name) #显示调用父类构造函数
self.score=score
def say_info(self): #重写父类方法
print("age:{0},name:{1},score:{2}".format(self.age, self.name, self.score))
stu = Student("lily",20,80)
stu.say_info()
13.2.4 super()获取父类定义
super():获取父类定义
class A:
def say(self):
print("A:",self)
class B:
def say(self):
A.say(self)
print("B:",self)
b = B()
b.say()
13.3 多态
多态:多态是指同一个方法由不同的对象调用可能会产生不同的行为。
- 多态是方法的多态,属性没有多态
- 多态的存在有两个必要条件,继承和方法重写
class Man:
def eat(self):
print("去吃饭")
class Chinese(Man):
def eat(self):
print("中国人用筷子吃饭")
class English(Man):
def eat(self):
print("英国人用叉子吃饭")
def gotoEat(m):
if isinstance(m,Man):
m.eat()
else:
print("can't eat")
gotoEat(Chinese())
gotoEat(English())
14. Object根类
object类是所有类的父类,因此所有类都有object类的属性和方法。
14.1 dir()查看对象属性
dir():可以查看一个对象的所有属性
class People():
def __init__(self,age,name):
self.age = age
self.name = name
def say_info(self):
print("age:{0},name:{1}".format(self.age,self.name))
obj = object()
print(dir(obj))
p1 = People("lily",20)
print(dir(p1))
14.2 重写__str__()方法
object有一个__str__()方法,用于返回一个对于“对象的描述”,对应于内置函数str(),经常用于print()方法,帮助我们查看对象的信息。str()可以重写。
class People():
def __init__(self,age,name):
self.age = age
self.name = name
def __str__(self):
return "age:{0},name:{1}".format(self.age,self.name)
p1 = People("lily",20)
print(p1)
15. 特殊方法
Python中包含很多双下划线开始和结束的方法,这些是特殊属性。Python中主要有以下特殊属性
方法 | 说明 |
---|---|
obj._dict_ | 对象的属性字典 |
obj._class_ | 对象所属的类 |
class._bases_ | 类的基类元组(多继承) |
class._bases_ | 类的基类 |
class._mro_ | 类的层次结构 |
class._subclasses_() | 子类列表 |