本系列主要学习Python的基本使用和语法知识,后续可能会围绕着AI学习展开。
Python3 (1) Python语言的简介
Python3 (2) Python语法基础
Python3 (3) Python函数
Python3 (4) Python高级特性
Python3(5) Python 函数式编程
Python3(6) Python 模块
Python3(7) Python 面向对象编程
面向对象编程是一种编程思想,主要与面向过程编程比较学习,在经历了 C++、C#、Java 的面向对象的学习,相信学习 Python 的面向对象会让自己对 OOP 有更深的理解。
面向对象与面向过程的比较
面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想。OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。
面向过程编程——面向过程的程序设计把计算机程序视为一系列的命令集合,即一组函数的顺序执行。为了简化程序设计,面向过程把函数继续切分为子函数,即把大块函数通过切割成小块函数来降低系统的复杂度。
#面向对象
class Student(object):
def __init__(self, name, age):
self.name = name
self.age = age
def print_age(self):
print('%s: %s' % (self.name, self.age))
bart = Student('张三', 15)
lisa = Student('李四', 16)
bart.print_age()
lisa.print_age()
#面向过程
def print_age(std):
print('%s: %s' % (std['name'], std['age']))
std1 = { 'name': '张三', 'age': 17 }
std2 = { 'name': '李四', 'age': 18 }
print_age(std1)
print_age(std2)
输出结果:
张三: 15
李四: 16
张三: 17
李四: 18
在Python中,所有数据类型都可以视为对象,当然也可以自定义对象。Student
的实例就是一个个对象。
类与实例
类与实例与java相同,就是普通的 Class 和 Class的实例化 ,类可以看成一个模板,可以实例出不用的对象。
下面我们分析一下上面面向对象的 示例:
-
class Student(object)
Student 类的定义,继承自object -
def __init__(self, name, age)
含义跟java构造函数相同,创建了实例时可以绑定一些数据。 - 创建实例 在类名后+
()
即可,没有new
关键字跟kotlin
使用一致。 - 在类中定义的函数有个共同的特点就是第一个参数是
self
。 - Python允许对实例变量绑定任何数据,与静态语言不同。
数据封装
数据的封装,其实就是定义一些函数,来实现特定的功能,类的实例调用对应的方法就可以实现对应的功能,不需要关注函数的具体实现和数据的具体传递。
访问限制
在前面我们已经学习过,除特殊的变量,以
_xxx
和__xxx
命名的变量是私有的,我们可以通过设置get、set来访问私有变量。这就体现了代码的封装性,可以使我们的程序更加的安全,规范,健壮。但是不是设置成私有的就一定不能被外界直接访问只是不符合编码规则,例如:__name
python解释器会编译成_Student__name
不同的版本也可能有不同的编译方式,所以尽量不要这样使用。
继承
OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)。继承的作用就是子类可以继承到父类的所有功能。也可以重写对应的功能。
多态
多态的概念其实是在继承,重写的应用,我们可以通过继承派生出不同的子类,重写子类的具体实现,在调用时用他们的共同基类做参数,这样基类派生出的各种子类都可以传递进去,系统会根据传入的具体类型实现具体的功能。
开闭原则
多态的设计采用的就是开闭原则:调用方只管调用,不管细节,不需要任何更改。
1. 对扩展开放:允许新增子类;
2. 对修改封闭:不需要修改用基类作为参数的方法
鸭子类型
这是Python强大之处,决定了继承不像静态语言那样是必须的。
鸭子类型:不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子,具体讲就是传入的对象,有需要的方法就可以传入并使用,不需要严格的来自它的继承。
下面通过一个示例来演示继承、多态、鸭子类型:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#基类
class Car(object):
def run(self):
return "car running...."
#子类
class SmallCar(Car):
def run(self):
return 'small car running...'
#子类
class BigCar(Car):
def run(self):
return 'bag car running...'
#子类的子类
class PoliceCar(SmallCar):
def run(self):
return 'police car running...'
def stop(self):
return 'police car stopped...'
#鸭子类型
class SchoolCar(object):
def run(self):
return 'school car running...'
#方法的调用
def look(car):
print('I look a ',car.run())
#多态的使用场景
look(Car())
look(SmallCar())
look(BigCar())
look(PoliceCar())
#鸭子类型的调用
look(SchoolCar())
输出结果:
I look a car running....
I look a small car running...
I look a bag car running...
I look a police car running...
I look a school car running...
获取对象信息
python中内置了各种函数,方便我们获取对象的信息。如
type()
、isinstance()
、dir()
、getattr()
、setattr()
以及hasattr()
下面是对获取对象信息 内置函数的使用示例:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#基类
import types
class Car(object):
weight = 2000
def run(self):
return "car running...."
#子类
class SmallCar(Car):
def run(self):
return 'small car running...'
#子类
class BigCar(Car):
def run(self):
return 'bag car running...'
#子类的子类
class PoliceCar(SmallCar):
def run(self):
return 'police car running...'
def stop(self):
return 'police car stopped...'
#鸭子类型
class SchoolCar(object):
def run(self):
return 'school car running...'
#方法的调用
def look(car):
print('I look a ',car.run())
#type()的使用
s = SmallCar()
s1 = SmallCar()
p = PoliceCar()
c = Car()
print(type(s),type(s1))
print(type(s)==SmallCar)
print(type(s)==type(c))
print("---------------------------")
#type的高级使用
print(type(look)==types.FunctionType)
print(type(abs)==types.BuiltinFunctionType)
print(type(lambda x: x)==types.LambdaType)
print(type((x for x in range(10)))==types.GeneratorType)
print("---------------------------")
#isinstance()的使用
print(isinstance(s,SmallCar))
print(isinstance(s,Car))
print(isinstance(s,PoliceCar))
print(isinstance(s,(SmallCar,PoliceCar)))#括号中是或的关系
print("---------------------------")
#dir() 的使用
print(dir(p))
print("---------------------------")
#getattr()、setattr()、hasattr() 的使用
#属性
print(hasattr(p,'weight'))
print(getattr(p,'weight'))
setattr(p,'weight',3000)
print(getattr(p,'weight'))
print(getattr(p,'height',404))
#方法
print(hasattr(p,'run'))
print(getattr(p,'run'))
setattr(p,'run',123456)
print(getattr(p,'run'))
#attr正确用法,去阻止鸭式类型之外的对象
def look(car):
if hasattr(car, 'run'):
print('I look a ', car.run())
return None
class Ambulance(object):
def shop(self):
return 'ambulance car stopped...'
print(look(Ambulance()))
输出结果:
<class '__main__.SmallCar'> <class '__main__.SmallCar'>
True
False
---------------------------
True
True
True
True
---------------------------
True
True
False
True
---------------------------
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'run', 'stop', 'weight']
---------------------------
True
2000
3000
404
True
<bound method PoliceCar.run of <__main__.PoliceCar object at 0x0000020D453CC0F0>>
123456
None
实例属性和类属性
这里主要强调一下实例属性与类属性的区别,由于Python是动态语言,根据类创建的实例可以任意绑定属性。包括类的属性
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
class Car(object):
name = 'car'
def __init__(self, name,weight):
self.name = name
self.weight = weight
c = Car('small car',2000);
print(Car.name)
print(c.name)
print(c.weight)
del c.name,c.weight
print(c.name)
print(getattr(c,'weight',3000))
输出结果:
car
small car
2000
car
3000
从上面可以看出如果删除了实例的属性,实例的属性会自动访问类的属性。所以一定要注意实例的属性名与类的属性名不要重复。
网友评论