python基础 (六)面向对象
真心觉得python这门语言是业界良心:
- 面向对象介绍及优点
- 面向对象特性
- 经典类vs新式类
- 静态方法
- 类方法
- 属性方法
- 类的特殊成员方法
- 反射
- 动态导入模块
一、面向对象介绍及优点
面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想。OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。
面向过程的程序设计把计算机程序视为一系列的命令集合,即一组函数的顺序执行。为了简化程序设计,面向过程把函数继续切分为子函数,即把大块函数通过切割成小块函数来降低系统的复杂度。
而面向对象的程序设计把计算机程序视为一组对象的集合,而每个对象都可以接收其他对象发过来的消息,并处理这些消息,计算机程序的执行就是一系列消息在各个对象之间传递。
在Python中,所有数据类型都可以视为对象,当然也可以自定义对象。自定义的对象数据类型就是面向对象中的类(Class)的概念。
无论用什么形式来编程,我们都要明确记住以下原则:
1、写重复代码是非常不好的低级行为
2、你写的代码需要经常变更
二、面向对象特性
1、类
一个类即是对一类拥有相同属性的对象的抽象、蓝图、原型。在类中定义了这些对象的都具备的属性(variables(data))、共同的方法 。
class Dog(object):
print("hello,I am a dog!")
2、对象
一个对象即是一个类的实例化后实例,一个类必须经过实例化后方可在程序中调用,一个类可以实例化多个对象,每个对象亦可以有不同的属性,就像人类是指所有人,每个人是指具体的对象,人与人之前有共性,亦有不同。
d = Dog() #实例化这个类,
#此时的d就是类Dog的实例化对象
#实例化,其实就是以Dog类为模版,在内存里开辟一块空间,存上数据,赋值成一个变量名
3、封装
封装也就是把客观事务封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
4、继承
面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。
通过继承创建的新类称为“子类”或“派生类”。
被继承的类称为“基类”、“父类”或“超类”。
继承的过程,就是从一般到特殊的过程。
要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。
在某些 OOP 语言中,一个子类可以继承多个基类。但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。
继承概念的实现方式主要有2类:实现继承、接口继承。
- 实现继承是指使用基类的属性和方法而无需额外编码的能力;
- 接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力(子类重构父类方法);
三、经典类vs新式类
class A:
def __init__(self):
print("A")
class B(A):
pass
# def __init__(self):
# print("B")
class C(A):
# pass
def __init__(self):
print("C")
class D(B,C):
pass
# def __init__(self):
# print("D")
obj=D()#先找B再找C再找A,广度优先,横向查完再往深
注意:
python2中经典类按深度优先继承,新式类按广度优先继承
python3中经典类和新式类都是统一按广度优先来继承
四、静态方法
通过@staticmethod装饰器可把该方法装饰成一个静态方法,普通的方法,可以在实例化后直接调用,并且在方法里可以通过self.调用实例变量或类变量,但静态方法是不可以访问实例变量或类变量的,一个不能访问实例变量和类变量的方法,其实相当于跟类本身已经没什么关系了,它与类唯一的关联就是需要通过类名来调用这个方法
class Dog(object):
def __init__(self,name):
self.name=name
@staticmethod
def eat(food):
print("%s is eating %s"%("dd",food))
d=Dog("mary")
# d.eat(d)
d.eat("noodle")
#dd is eating noodle
四、类方法
通过装饰器@classmethod装饰器实现,类方法和普通方法的区别是,类方法只能访问类变量,不能访问实例变量。
class Dog(object):
name = "class_variable"
def __init__(self,name):
self.name = name
@classmethod
def eat(self):
print("%s is eating" % self.name)
d = Dog("mary")
d.eat()
#执行结果
#class_variable is eating
五、属性方法
属性方法的作用就是通过@property把一个方法变成一个静态属性
class Dog(object):
def __init__(self,name):
self.name = name
@property
def eat(self):
print(" %s is eating" %self.name)
d = Dog("mary")
d.eat
#mary is eating
很多场景是不能简单通过 定义 静态属性来实现的。
想知道一个航班当前的状态,是到达了、延迟了、取消了、还是已经飞走了, 想知道这种状态你必须经历以下几步:
1. 连接航空公司API查询
2. 对查询结果进行解析
3. 返回结果给你的用户
因此这个status属性的值是一系列动作后才得到的结果,所以你每次调用时,其实它都要经过一系列的动作才返回你结果,但这些动作过程不需要用户关心, 用户只需要调用这个属性就可以
example:
class Flight(object):
def __init__(self,name):
self.flight_name=name
def checking_status(self):
print("checking flight %s status"%self.flight_name)
return 0#由航空系统API返回
@property
def flight_status(self):
status=self.checking_status()
if status==0:
print("flight got canceled")
elif status==1:
print("flight is arrived")
elif status==2:
print("flight has departured already")
else:
print("cannot confirm the flight status...,please check later")
@flight_status.setter
def flight_status(self,status):
print("the status of %s changed that is %s"%(self.flight_name,status))
f=Flight("CA980")
f.flight_status
#结果:checking flight CA980 status
# flight got canceled
f.flight_status="2"
#结果:
#the status of CA980 changed that is 2
六、类的特殊成员方法
1、__doc__:类的描述信息
class Dog(object):
"""这个类是描述构这个对象的"""
def __init__(self,name):
self.name=name
print(Dog.__doc__)#打印类的解释
2、__module__:当前操作的对象在那个模块
__class__:当前操作的对象的类是什么
#libra/aa.py
class C:
def __init__(self):
self.name = 'wupeiqi
from libra.aa import C
obj=C()
print(obj.__module__) #返回当前obj对象所属类来自于哪个模块
print(obj.__class__) #返回当前obj对象所属的类
3、__init__:通过类创建对象时,自动触发执行
4、__del__:析构方法,当对象在内存中被释放时,自动触发执行
5、__call__:对象后面加括号,触发执行。
class Dog(object):
"""这个类是描述构这个对象的"""
def __init__(self,name):
self.name=name
self.__food=None
def __call__(self,*args):
print("running call",args[0])
d=Dog("mary")
Dog("mary")("baby")
#running call baby
6、__dict__:查看类或对象中的所有成员
class Dog(object):
"""这个类是描述构这个对象的"""
def __init__(self,name):
self.name=name
self.__food=None
def __call__(self,*args):
print("running call",args[0])
print(Dog.__dict__)#打印类里的所有属性,不包括实例属性
#{'__weakref__': <attribute '__weakref__' of 'Dog' objects>, '__call__': <function Dog.__call__ at 0x7f59c5d0a268>, '__doc__': '这个类是描述构这个对象的', '__dict__': <attribute '__dict__' of 'Dog' objects>, '__module__': '__main__', '__init__': <function Dog.__init__ at 0x7f59c5d1dc80>}
print(d.__dict__)#打印所有实例属性,不包括类属性
#{'name': 'mary', '_Dog__food': None}
7、__str__:如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。
class Dog(object):
"""这个类是描述构这个对象的"""
def __init__(self,name):
self.name=name
self.__food=None
def __call__(self,*args):
print("running call",args[0])
def __str__(self):
return "<obj:%s>"%self.name
d=Dog("mary")
print(d)#<obj:mary>
8、__getitem__、__setitem__、__delitem__:用于索引操作,如字典。以上分别表示获取、设置、删除数据。
class Foo(object):
def __init__(self):
self.data={}
def __getitem__(self,key):
return self.data[key]
def __setitem__(self,key,value):
self.data[key]=value
def __delitem__(self,key):
del self.data[key]
d=Foo()
d['name']="xzx"
d['name2']="alex"
print(d.data)
print(d['name'])
print(d["name2"])
七、反射
反射:通过字符串映射或修改程序运行时的状态、属性、方法, 有以下4个方法:
- getattr(object, name, default=None)
- hasattr(object,name)
- setattr(x, y, v)
- delattr(x, y)
def talk(self):
print("%s is talking"%self.name)
class Foo(object):
def __init__(self,name):
self.name=name
def eat(self,food):
print("%s is eating %s"%(self.name,food))
d=Foo("xzx")
a=input("输入函数吧:")
if hasattr(d,a):
food=input("参数:")
getattr(d, a)(food)
else:
setattr(d,a,talk)
getattr(d,a)(d)#d.a=talk,仍然要传入obj给self
输出结果:
输入函数吧:eat
参数:baby
xzx is eating baby
输入函数吧:shutup
xzx is talking
八、动态导入模块
import importlib
__import__('import_lib.metaclass') #这是解释器自己内部用的
#importlib.import_module('import_lib.metaclass') #与上面这句效果一样,官方建议用这个