Python之面向对象编程(1)
⾯向过程
:根据业务逻辑从上到下写代码 ⾯向对象:将数据与函数绑定到⼀起,进⾏封装,这样能够更快速的开 发程序,减少了重复代码的重写过程
⾯向对象(object-oriented ;简称: OO)
⾄今还没有统⼀的概念 我这⾥把它 定义为: 按⼈们 认识客观世界的系统思维⽅式,采⽤基于对象(实体) 的概 念建⽴模型,模拟客观世界分析、设 计、实现软件的办法。
⾯向对象编程(Object Oriented Programming-OOP)
是⼀种解决软件复 ⽤的设计和编程⽅法。 这种⽅法把软件系统中相近相似的操作逻辑和操 作 应⽤数据、状态,以类的型式描述出来,以对象实例的形式在软件系统 中复⽤,以达到提⾼软件开发效率的作⽤。
类和对象
类是抽象的,在使⽤的时候通常会找到这个类的⼀个具体的存在,使⽤这个具体 的存在。⼀个类可以找到多个对象
对象:某⼀个具体事物的存在 ,在现实世界中可以是看得⻅摸得着的。可以是直接使⽤的
类和对象的关系:类就是创建对象的模板
定义类:
'''
class 类名:
方法列表
'''
class Car:
def getCarInfo(self):
print('信息')
def move(self):
print('移动')
- 定义类时有2种:新式类和经典类,上⾯的Car为经典类,如果是 Car(object)则为新式类
- 类名的命名规则按照"⼤驼峰"
创建对象
class Car:
def getCarInfo(self):
print('信息')
def move(self):
print('移动')
# # 创建⼀个对象,并⽤变量aodi来保存它的引⽤
aodi=Car()
aodi.color='black'
aodi.wheelNum=4
aodi.move() # 移动
print(aodi.color) # black
print(aodi.wheelNum) # 4
print(aodi) # <__main__.Car object at 0x00000221DE9FA508>
第⼀次使⽤audi.color ='⿊⾊’表示给BMW这个对象添加属性,
如果后面再次出现audi.color=xxx表示对属性进⾏修改
aodi是⼀个对象,它拥有属性(数据)和⽅法(函数)
当创建⼀个对象时,就是⽤⼀个模⼦,来制造⼀个实物
python
__init__()
方法
通过该方法可以使得在创建对象的时候,就可以设置对象的属性
'''
__init__()
def 类名:
# 初始化函数,用来完成一些默认的设定
def __init__():
pass
'''
class Car:
def __init__(self):
self.wheelNum=4
self.color='blue'
def getCarInfo(self):
print('信息')
def move(self):
print('移动')
dazhong = Car()
print(dazhong.color) #bule
print(dazhong.wheelNum) #4
可以通过init函数传递参数,其中参数可以有默认值(有默认值的一定放在最后面)
#coding=utf-8
class Car:
def __init__(self,newWheelNum=4,newColor='blue'):
self.wheelNum=newWheelNum
self.color=newColor
def move(self):
print('move')
biyadi=Car()
print(biyadi.wheelNum) #4
print(biyadi.color) #blue
sanlun=Car(3,'black')
print(sanlun.wheelNum) #3
print(sanlun.color) #black
__init__()
⽅法,在创建⼀个对象时默认被调⽤,不需要⼿动调⽤
__init__(self)
中,默认有1个参数名字为self,如果在创建对象时传 递了2个实参,那么__init__(self)
中出了self作为第⼀个形参外还需 要2个形参,例如__init__(self,x,y)
__init__(self)
中的self参数,不需要开发者传递,python解释器会 ⾃动把当前的对象引⽤传递进
魔法方法
如果把对象使用print输出的话,会输出其地址<__main__.Car object at 0x00000221DE9FA508>
定义__str__()
方法
class Car:
def __init__(self,newWheelNum=4,newColor='blue'):
self.wheelNum=newWheelNum
self.color=newColor
def __str__(self):
msg ="嘿。。。我的颜⾊是"+self.color +"我有"+ str(self.wheelNum)
return msg
def move(self):
print('move')
biyadi=Car()
print(biyadi.wheelNum) #4
print(biyadi) # 嘿。。。我的颜⾊是blue我有4
print(biyadi.color) #blue
- 在python中⽅法名如果是
__xxxx__()
的,那么就有特殊的功能,因此 叫做“魔法”⽅法 - 当使⽤print输出对象的时候,只要⾃⼰定义了
__str__(self)
⽅法,那 么就会打印从在这个方法中return的数据
self
- 所谓的self,可以理解为⾃⼰
- 可以把self当做C++中类⾥⾯的this指针⼀样理解,就是对象⾃身的意思
- 某个对象调⽤其⽅法时,python解释器会把这个对象作为第⼀个参数传递给self,所以开发者只需要传递后⾯的参数即可
保护对象的属性(私有属性私有方法)
查看或者修改对象的属性有两种方法
- 对象名.属性名=数据---->直接修改
- 对象名.⽅法名()---->间接修改
为了更好的保存属性安全,即不能随意修改,⼀般的处理⽅式为
- 将属性定义为私有属性
- 添加⼀个可以调⽤的⽅法,供调⽤
Python中没有像C++中public和private这些关键字来区别公有属性和私有 属性
它是以属性命名⽅式来区分,如果在属性名前⾯加了2个下划线’__’,则 表明该属性是私有属性,否则为公有属性(⽅法也是⼀样,⽅法名前⾯ 加了2个下划线的话表示该⽅法是私有的,否则为公有的)。
class Car:
def __init__(self,newWheelNum=4,newColor='blue'):
self.__wheelNum=newWheelNum # 前面加__表示私有属性
self.__color=newColor
def __str__(self):
msg="嘿。。。我的颜⾊是"+self.__color+"我有"+str(self.__wheelNum)
return msg
def getWheelNum(self):
return self.__wheelNum
def getColer(self):
return self.__color
def setWheelNum(self,wheelNum):
self.__wheelNum = wheelNum
def setColor(self,color):
self.__color=color
def __private(self):
print('我是私有方法')
def move(self):
self.__private() #自己的方法中可以调用私有方法
print('move')
biyadi=Car()
print(biyadi) # 嘿。。。我的颜⾊是blue我有4
print(biyadi.getColer())
biyadi.setColor('red')
print(biyadi.getColer())
结果
嘿。。。我的颜⾊是blue我有4
blue
red
__del__()
方法
创建对象后,python解释器默认调⽤ init() ⽅法;
当删除⼀个对象时,python解释器也会默认调⽤⼀个⽅法,这个⽅法 为 del() ⽅法删除一个对象使用
del obj
class Test:
def __init__(self):
print('我是__init__方法')
def __del__(self):
print('我的__del__方法')
test=Test() # 我是__init__方法
test1 =test
test2 = test
del test2
del test1
del test # 我的__del__方法
- 当有1个变量保存了对象的引⽤时,此对象的引⽤计数就会加1
- 当使⽤del删除变量指向的对象时,如果对象的引⽤计数不会1,⽐如3, 那么此时只会让这个引⽤计数减1,即变为2,当再次调⽤del时,变为 1,如果再调⽤1次del,此时会真的把对象进⾏删除
单继承
虽然⼦类没有定义 init ⽅法,但是⽗类有,所以在⼦类继承⽗类 的时候这个⽅法就被继承了,所以只要创建Bosi的对象,就默认执⾏了 那个继承过来的 init ⽅法
class Cat(object):
def __init__(self,name,color='白色'):
self.name=name
self.color=color
def run(self):
print('%s再跑'%self.name)
class JuCat(Cat):
def setNewName(self,newName):
self.name=newName
def eat(self):
print('%s is eating'%self.name)
jucat=JuCat('Ruby')
print(jucat.name) # Ruby
print(jucat.color) # 白色
jucat.eat() # Ruby is eating
jucat.setNewName('Bob')
jucat.run() # Bob再跑
⼦类在继承的时候,在定义类时,⼩括号()中为⽗类的名字
⽗类的属性、⽅法,会被继承给⼦类
注意私有性
- 私有的属性,不能通过对象直接访问,但是可以通过⽅法访问
- 私有的⽅法,不能通过对象直接访问
- 私有的属性、⽅法,不会被⼦类继承,也不能被访问
- ⼀般情况下,私有的属性、⽅法都是不对外公布的,往往⽤来做内部的 事情,起到安全的作⽤
多继承
多继承,即⼦类有多个⽗类,并且具有它们的特征
Python中多继承的格式如下:
class A:
def printA(self):
print('A')
class B:
def printB(self):
print('B')
class C(A,B):
def printC(self):
print('C')
objC=C()
objC.printA() #A
objC.printB() #B
python中是可以多继承的 ⽗类中的⽅法、属性,⼦类会继承
如果父类AB中有一个同名的方法
class A:
def print(self):
print('A')
class B:
def print(self):
print('B')
class C(B,A):
def printC(self):
print('C')
objC=C()
objC.print() #B
class A:
def print(self):
print('A')
class B:
def print(self):
print('B')
class C(A,B):
def printC(self):
print('C')
objC=C()
objC.print() #A
class A:
def print(self):
print('A')
class B:
def print(self):
print('B')
class C(B,A):
def print(self):
print('C')
objC=C()
objC.print() #C
print(C.__mro__) # 可查看搜索函数的顺序 (<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
重写与调用父类方法
多态
多态的概念是应⽤于Java和C#这⼀类强类型语⾔中,⽽Python崇尚“鸭⼦类 型”。
所谓多态:定义时的类型和运⾏时的类型不⼀样,此时就成为多态
类属性、实例属性
类属性有点像C中的静态成员变量
类属性
类属 性就是类对象
所拥有的属性,它被所有类对象
的实例对象
所共有,在内存中只存在⼀个副本,这个和C++中类的静态成员变量有点类似。对于公有 的类属性,在类外可以通过类对象
和实例对象
访问
class People(object):
name = 'Tom' #公有属性
__age=13 #私有属性
p=People()
print(p.name)
print(People.name)
实例对象(对象属性)
class People(object):
name = 'Tom' #公有的类属性
__age=13 #私有的类属性
def __init__(self):
self.address = '美国' #实例属性
self.school='TJU' #实例属性
self.__pri='hhh'
p=People()
print(p.name)
print(People.name)
# print(p.__age) # 错误 不能在类外通过实例对象访问私有的类属性
# print(People.__age) # 错误 不能在类外通过实例对象访问私有的类属性
print(p.address)
print(p.school)
# print(p.__pri) 错误
# print(People.address) # 错误
通过实例(对象)去修改类属性
class People(object):
country = 'China'
p=People()
p.country='US'
print(p.country) #US
print(People.country) #China
p.country='Japan'
print(p.country) # Japan
del p.country
print(p.country) #China
People.country = 'UK'
print(p.country) #UK
print(People.country) #UK
如果需要在类外修改类属性,必须通过类对象去引⽤然后进⾏修改。 如果通过实例对象去引⽤,会产⽣⼀个同名的实例属性,这种⽅式修改 的是实例属性,不会影响到类属性,并且之后如果通过实例对象去引 ⽤该名称的属性,实例属性会强制屏蔽掉类属性,即引⽤的是实例属 性,除⾮删除了该实例属性 。
静态方法和类方法
self指的是对象
cls指的是类
类方法
是类对象所拥有的⽅法,需要⽤修饰器@classmethod来标识其为类⽅法, 对于类⽅法,第⼀个参数必须是类对象,⼀般以cls作为第⼀个参数(当然 可以⽤其他名称的变量作为其第⼀个参数,但是⼤部分⼈都习惯以’cls’作为第 ⼀个参数的名字,就最好⽤’cls’了),能够通过实例对象和类对象去访问。
class People(object):
country='China' # 类属性
#类方法,用classmethod来修饰
@classmethod
def getCountry(cls):
return cls.country
pass
p=People()
print(p.getCountry()) #可以通过实例对象引用
print(People.getCountry()) #可以通过类对象引用
类⽅法还有⼀个⽤途就是可以对类属性进⾏修改:
class People(object):
country='China'
#类方法,用classmethod来修饰
@classmethod
def getCountry(cls):
return cls.country
def setCountry(self):
self.country='UK'
@classmethod
def setCountryClass(cls):
cls.country='Japan'
pass
p=People()
print(p.getCountry()) #可以通过实例对象引用 China
print(People.getCountry()) #可以通过类对象引用 China
p.setCountry()
print(p.country) #UK
print(People.country) #China 使用普通的方法,只能改对象的属性,无法改类属性
p.setCountryClass()
print(p.country) # UK 由此可得,当对象属性和类属性冲突时,对象属性还是对象属性
print(People.country) # Japan 在⽤类⽅法对类属性修改之后,通过类对象和实例对象访问都会发生改变
静态方法
需要通过修饰器 @staticmethod 来进⾏修饰,静态⽅法不需要多定义参数
class People(object):
country='China'
@staticmethod
def getCountry():
return People.country
print(People.getCountry())
从类⽅法和实例⽅法以及静态⽅法的定义形式就可以看出来,
- 类⽅法的第⼀个参数是类对象cls,那么通过cls引⽤的必定是类对象的属性和⽅法;
- ⽽实例⽅法的第⼀个参数是实例对象self,那么通过self引⽤的可能是类属性、也有可能是实例属性(这个需要具体分析),
- 不过在存在相同名称的类属性和实例属性的情况下,实例属性优先级更⾼。
- 静态⽅法中不需要额外定义参数, 因此在静态⽅法中引⽤类属性的话,必须通过类对象来引⽤