什么是对象?
对象是内存中专门用来存储数据的一块区域。
对象中可以存放各种数据(比如:数字、布尔值、代码)
对象由三部分组成:
1. 对象的标示(id)
2. 对象的类型(type)
3. 对象的值(value)
面对对象
-python是一门面对对象的编程语言
-所谓面向对象的语言,简单理解就是语言中的所有操作都是通过对象来进行的
-面向过程的编程语言
指将我们程序的逻辑分成一个一个的步骤,通过对每个步骤的抽象来完成程序
-面向过程的编程思想将一个功能分解为一个一个小的步骤,我们通过完成一个一个小的步骤来完成一个程序
-这种编程思路符合人类思维,编写起来相对比较简单,但是这种方式编写代码往往只适用于一个功能,即使功能相差极小,也往往需要重新编写代码,所以她的可复用性比较低,并且难于维护
-面向对象的编程语言
-面向对象的编程语言,关注的是对象,而不关注于过程
eg:孩她妈起床叫孩子上学
类(class)
我们目前所学习的对象都是python内置的对象
但是内置对象不能满足所有需求,所以我们在开发中经常需要定义一些对象
类,简单理解它就相当于一个图纸,在程序中我们需要根据类来创建对象
类就是对象的图纸
-我们也称对象是类的实例(instance)
-如果多个对象是通过一个类创建的,我们称这些对象都是一类对象
-像:int() float() bool() str() list() dict().....这些都是类
a=int(10) 创建一个int
定义一个简单的类
使用class关键字来定义类,语法和函数很像
class 类名([父类]):
代码块
类,也是一个对象,是一个用来创建对象的对象
类是type类型的对象,定义类实际上就是定义了一个type类型的对象
-使用类创建对象的流程
1.创建一个变量mc
2.在内存中创建一个新对象
3.将对象的id赋值给变量
#定义类必须用大驼峰命名法
class MyClass():
pass
#使用MyClass创建一个对象
#使用类来创建一个对象,就像调用一个函数一样
mc=MyClass()
print(type(mc))
#mc就是通过MyClass创建的对象,mc是MyClass的实例
#isinstance()用来检查一个对象是否是一个类的实例
r=isinstance(mc,MyClass)
print(r)
print(id(MyClass),type(MyClass))
#类也是一个对象
#现在我们通过MyClass这个类创建的对象都是一个空对象
#也就是对象实际上什么都没有,就相当于一个空盒子
#可以向对象中添加变量,对象中的变量称为属性
#语法:对象.属性名=属性值
mc.name='js'
print(mc.name)
ma=MyClass()
print(ma,mc)
类的定义
-类和对象都是对现实生活的事物或程序中的内容的抽象
-实际上所有的事物都是由两部分构成:
1,数据(属性)
2. 行为(方法)
1. 在类的代码块中我们可以定义变量和函数,变量会成为该类实例都可以通过 对象.属性名。 的方式访问
2. 函数会成为该类实例的公共方法,所有该类实例都可以通过。 对象.方法名()的形式调用方法
注意:
方法调用时,第一个参数由解析器自动传递,所以定义方法时要至少定义一个形参
class Person():
#在类的代码块中,我们可以定义变量和函数
#在类中我们定义的变量,将会称为所有实例的公共属性
#所有实例都可以访问这些变量
high=170
name='js'
def fn(a):
print('hello')
#创建person的实例
p1=Person()
p2=Person()
#调用方法,对象.方法名()
#如果是函数调用,则调用时传几个参数,就会有几个实参
#但如果是方法调用,默认传递一个参数,所以方法中至少要定义一个形参
p2.fn()
实例为什么可以访问到类中的属性和方法?
类中定义的属性和方法都是公共的,任何该类实例都可以
- 属性和方法查找的流程
当我们调用一个对象的属性时,解析器会先在当前对象中寻找是否含有该属性,如果有则直接返回当前对象的属性值
如果没有,则去当前对象的类对象中去寻找
-类对象和实例对象中都可以保存属性(方法)
-如果这个属性(方法)是所有的实例共享的,则应该将其保存到类对象中
-如果这个属性(方法)是某个实例独有,则应该保存到实例对象中
-一般情况下,属性保存到实例对象中
-方法保存到类对象中
class Person():
name='js'
def fn(self):
print('hello我是%s'% self.name)
p1=Person()
p2=Person()
p1.name='js'
p2.name='ky'
p2.fn()
print(p2)
#方法每次被调用时,解析器都会自动传递第一个实参
#p1调的,则第一个参数就是p1对象
#p2调的,则第一个参数就是p2对象
类的特殊方法init
目前来说,对于person类来说name是必须的,我们希望在创建对象时必须设置name属性,如果不设置对象将无法创建,而且属性的创建是自动完成的,而不是在创建对象以后手动完成的!
class Person():
#特殊方法不需要自己调用,不要尝试去调用特殊方法
#学习特殊方法:
# 1.特殊方法什么时候调用
# 2.特殊方法有什么用
#创建对象的流程
# 1.创建一个变量
# 2.在内存中创建一个新对象
# 3._执行类代码块中的代码(只在类定义的时候执行一次)
# 4.__init__(self)方法执行
# 5.将对象id赋值给变量
#init会在对象创建以后立刻执行
#init可以用来向新创建的对象中初始化属性
#调用类创建对象时,类否遍的所有参数会依次传递到init()中
def __init__(self,name):
self.name=name
#通过self向新建的对象中初始化属性
name='js'
def fn(self):
print('hello我是%s'% self.name)
p1=Person('jess')
p2=Person('kyle')
p1.fn()
p2.fn()
创建对象的流程:
p1=Person()的运行流程
1.创建一个变量
# 2.在内存中创建一个新对象
# 3._执行类代码块中的代码(只在类定义的时候执行一次)
# 4.__init__(self)方法执行
# 5.将对象id赋值给变量
类的基本结构:
class类名([父类]):
公共属性... ...
#对象的初始化方法
def__init__(self,...):
... ...
#其他的方法
def method_1(self,...):
... ...
def method_1(self,...):
... ...
练习:
#练习:
#尝试定义一个表示狗的类(Dog)
#属性:
#name
#age
#gender
#height
#方法:
#jiao()
#yao()
#run()
class Dog():
def __init__(self,name,age,gender):
self.name=name
self.age=age
self.gender=gender
def yao(self):
print('%s咬我了'%self.name)
def jiao(self):
print('%s在叫'%self.name)
def run(self):
print('%s的%s在跑'%(self.age,self.name))
n1=Dog('八月','1岁','boy')
n2=Dog('pipi','6个月','girl')
n1.yao()
n1.jiao()
n1.run()
n2.yao()
n2.jiao()
n2.run()
封装:是面向对象的三大特征
封装指的是隐藏对象中一些不希望被外部锁访问到的属性或方法
1. 如何隐藏一个对象中的属性?
-将对象的属性名,修改为一个外部不知道的名字
2. 如何获取(修改)对象中的属性?
-需要提供一个getter和setter方法使外部可以访问到属性
-getter获取对象中的指定属性(get_属性名)
-setter用来设置对象的指定属性(get_属性名)
使用封装增加了类的定义的复杂程度,但他也确保了数据的安全性
1. 隐藏了属性名,使调用者无法随意的修改对象中的属性
2.增加了getter和setter方法,很好的控制属性是否是只读的
如果希望属性是只读的,则可以直接去掉setter方法
如果希望属性不能被外部访问,则可以直接去掉getter方法
3.使用setter方法设置属性,可以增加数据的验证,确保数据的值是正确的
4.使用getter方法获取属性,使用setter方法设置属性
可以在读取属性和修改属性的同时做一些其他处理
class Dog():
def __init__(self,name):
self.hidden_name=name
def yao(self):
print('%s咬我了'%self.hidden_name)
def get_name(self):
return self.hidden_name
def set_name(self,name):
self.hidden_name=name
n1=Dog('八月')
print(n1.get_name())
n1.set_name('77')
print(n1.get_name())
隐藏类中的属性
一般使用_的属性都是私有属性,没有特殊需求不要修改私有属性
#可以为对象的属性使用双下划线开头<__xxx
#双下划线开头的属性,是对象的隐藏属性,隐藏属性只能在类的内部访问无法通过对象访问
#其实隐藏属性只不过是python自动为属性改了一个名字,eg:__name -> _类名__name
class Dog():
def __init__(self,name):
self.__name=name
def yao(self):
print('%s咬我了'%self.hidden_name)
def get_name(self):
return self.__name
def set_name(self,name):
self.__name=name
n1=Dog('八月')
print(n1.get_name())
n1.set_name('77')
print(n1.get_name())
#使用__开头的属性,实际上依然可以在外部访问,所以这种方式我们一般不用
#一般我们会将一些私有属性(不希望被外部访问的属性)以_开头
class Dog():
def __init__(self,name):
self._name=name
def yao(self):
print('%s咬我了'%self.hidden_name)
def get_name(self):
return self._name
def set_name(self,name):
self._name=name
n1=Dog('八月')
print(n1.get_name())
n1.set_name('77')
print(n1.get_name())
property装饰器
property装饰器,用来将一个get方法转换为对象的属性
添加property装饰器以后我们就可以像调用属性一样使用get方法
使用property装饰的方法,必须和属性名是一样的
setter方法的装饰器:@属性名.setter
class Dog():
def __init__(self,name):
self._name=name
def yao(self):
print('%s咬我了'%self.hidden_name)
@property
def name(self):
print('get函数')
return self._name
@name.setter
def name(self,name):
print('set函数')
self._name=name
n1=Dog('八月')
#直接打印属性名,不需要调用函数
print(n1.name)
n1.name='77'
print(n1.name)
继承
有一个类,能够实现我们需要的大部分功能,但是不能实现全部功能
如何能让这个类来实现全部的功能呢?
1.直接修改这个类,在这个类中添加我们需要的功能
- 修改起来会比较麻烦,并且会违反ocp原则
2.直接创建一个新的类
-创建一个新的类比较麻烦,并且需要大量的进行复制粘贴,胡出现大量的重复性代码
3.直接从Animal类中来继承他的属性和方法
-继承是面向对象的三大特征之一
-通过继承我们可以使一个类获取到其他类中的属性和方法
-定义类时,可以在类名后的括号中指定当前类的父类(超类、基类、super)子类(衍生类)可以直接继承父类中的所有属性和方法
#定义一个 Animal 中需要两个方法:run() bark()
#又定义了Dog 中需要三种方法:run() bark() yao()
class Animal():
def run(self):
print('它在跑')
def bark(self):
print('汪汪汪')
#Animal是 Dog的父类
class Dog(Animal):
def yao(self):
print('%s咬我了'%self.name)
class 柯基(Dog):
def sleep(self):
print('%s睡着了'%self.name)
n1=Dog()
n1.name='88'
n1.run()
n2=柯基()
n2.name='11'
n2.sleep()
#判断是不是该类的实例
print(isinstance(n1,Animal))
print(isinstance(n2,Animal))
#判断一个类是不是另一个类的子类
print(issubclass(Dog,Animal))
print(issubclass(柯基,Animal))
print(issubclass(柯基,object))
在创建类时,如果省略了负累,则默认父类为object
object是所有类的父类,所有类都继承自object
如果在子类中如果有和父类同名的方法,则通过子类实例去调用方法时,会调用子类方法而不是父类的方法,这个特点我们称为叫做方法的重写(覆盖,override)
当我们调用一个对象的方法时,会优先去当前对象中寻找是否具有该方法,如果有则直接调用,如果没有,则去当前对象的父类中寻找,以此类推,直到找到object,如果依然没有找到则会报错
class Animal():
def run(self):
print('它在跑')
def bark(self):
print('汪汪汪')
class Dog(Animal):
def bark(self):
print('他在汪汪的叫')
n1=Dog()
n1.name='88'
n1.bark()
父类中的所有方法都会被子类继承,包括特殊方法“__init__”也可以重写特殊方法
super()可以用来获取当前类的父类
class Animal():
def __init__(self,name,age):
self._name=name
self._age=age
def run(self):
print('它在跑')
def bark(self):
print('汪汪汪')
class 柯基(Animal):
def __init__(self,name,age,gender):
#希望可以直接调用父类的__init__来初始化父类中定义的属性
#super()可以用来获取当前类的父类
#并且通过super()返回对象调用父类方法时,不需要传递self
super().__init__(name,age)
self._gender=gender
def bark(self):
print('他在汪汪的叫')
n1=柯基('88','9','male')
n1.name='88'
n1.bark()
类名.__bases__ 这个属性可以用来获取当前类的所有父类
class A(object):
def test1(self):
print('aaa')
class B(object):
def test2(self):
print('bbb')
#python中是支持多重继承的,也就是我们可以为一个类同时指定多个父类
#可以在类名()后边添加多个类,来实现多重继承
#多重继承,会使子类同时拥有多个父类,并且会获取到所有父类中的方法
#在开发中没有特殊情况,应该尽量避免使用多重继承,因为多重继承会让我们的代码过#于复杂
class C(A,B):
def test3(self):
print('ccc')
print(A.__bases__)
print(C.__bases__)
如果多个父类中有同名的方法,则会先在第一个父类中寻找,然后找第二个,然后找第三个... ... 前边父类的方法会覆盖后边父类的方法
多态