python面向对象编程
- 什么是面向对象?
类是一类具有同一特征的统称,如人类是一个类,张三、李四就是人类的某个具体对象。
利用(面向)对象(属性和方法)去进行编码的过程,就称为面向对象编程。面向对象编程是把构成事物的整个需求按照特点、功能划分,把这些存在共性的部分封装成对象,创建对象的目的不是为了完成某一个步骤,而是为了描述整个事物在整个解决问题的步骤中的行为。
python 中一切皆对象,比如变量也是对象,包括整型(int
)、浮点型(float
)、字符串(str
)、列表(list
)、元组(set
)、字典和集合(set
)。
面向过程:主要分析出解决问题所需要的步骤,用函数把这些步骤一步一步实现,使用的时候一个一个依次调用即可。
面向对象:主要找出问题中的共性问题,作为对象进行操作。
面向过程是一种以过程为中心的编程思想,面向对象是一类以对象为核心的编程思想。
- 类的定义与调用:
自定义对象数据类型就是面向对象中的类(class
)的概念,通过自定义类,可以实例化出具体的对象,类有自己的属性和方法,实例化出来的对象也具备类的属性和方法。
可以把类理解为一个模板,通过这个模板可以创建出无数个具体的实例。类是抽象的模板,而实例是根据类创建出来的一个个具体的对象,每个对象都拥有相同的方法。
类并不能直接使用,通过类创建出来的实例才能使用。类的所有变量称为属性,类的所有函数称为方法。方法和函数不同的是,方法至少要包含一个 self
参数,且方法无法单独使用,只能和类实例出来的对象一起使用。
python 中,使用关键字 class
来声明类,类的名称首字母大写,多单词情况下每个单词首字母大写,这就是“驼峰命名法”。
用法:
class ClassName(object):
attr = something
def 函数名(self):
函数具体实现代码块
return 返回值
示例:
# coding:utf-8
class Person(object):
name = 'xiaobai'
def sing(self):
print(f'{
self.name} can sing')
xxx = Person() #类的实例化
print(xxx.name) #通过实例化进行属性调用
xxx.sing() #通过实例化进行函数调用
结果:
xiaobai
xiaobai can sing
self
:
self
是一个对象,它代表实例化的变量自身。self
是类方法中的必传参数,且必须放在第一个参数位置。
定义类属性的变量可以不用加上 self
,但在定义类方法中的变量是必须要加上 self
的。self
中的变量与含有 self
参数的函数可以在类中的任何一个函数内随意调用。
如果在类中定义函数时加了 self
参数,那这个函数是类实例的方法,而不是类的方法。反之,如果在类中定义函数时没有加 self
参数,那这个函数就只是类的方法,而不是类实例的方法。
- 类的构造函数:
构造函数,是类中的一种默认函数,用来将类实例化的同时,将参数传入类中。构造函数应该定义在类中所有函数的最上面,作为类的第一个函数。
用法:
class ClassName(object):
def __init__(self, a, b): #构造函数
self.a = a
self.b = b
示例:
# coding:utf-8
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def sing(self):
print(f'{
self.name} can sing')
def study(self):
print(f'{
self.name}\'s age is {
self.age}, so he is an elementary school student')
xiaobai = Person('xiaobai', 10)
print(xiaobai.name)
xiaobai.sing()
xiaobai.study()
结果:
xiaobai
xiaobai can sing
xiaobai's age is 10, so he is an elementary school student
对于一个对象,构造函数 __init__
标志着对象生命的开始,系统会从内存中内配一个内存块给这个对象。析构函数 __del__
标志着对象生命的结束,它会删除对象,系统会从内存中释放这个内存块。
- 私有函数和私有变量:
私有函数与私有变量,就是无法被实例化后的对象调用的类中的函数与变量。
私有函数与私有变量,只希望类内部业务调用使用,不希望被使用者调用。因此,类内部可以调用私有函数与私有变量。
私有函数与私有变量,只需要在变量或函数前添加双下划线 __
来定义。尽量不要在实例化对象中直接调用私有函数和私有变量。
用法:
class ClassName(object):
def __init__(self, a):
self.a = a
self.__b = b #私有变量
def __函数名(self): #私有函数
函数具体实现代码块
return 返回值
示例:
# coding:utf-8
class Person(object):
def __init__(self, name):
self.name = name
self.__age = 10
def __sing(self):
return f'{
self.name} can sing'
def sing(self):
result = self.__sing()
return result
def __study(self):
return f'{
self.name}\'s age is {
self.__age}, so he is an elementary school student'
def study(self):
result = self.__study()
return result
xiaobai = Person('xiaobai')
print(xiaobai.name)
print(xiaobai.sing())
print(xiaobai.study())
结果:
xiaobai
xiaobai can sing
xiaobai's age is 10, so he is an elementary school student
- python 中的封装:
使用类中的非私有函数,来调用类中不对外的私有属性和方法,就称为 python 中的封装。这样做的目的是保护隐私,明确区分内外。
示例:
# coding:utf-8
class Hello(object):
def __init__(self, data):
self.data = data
def __hello(self):
print('hello %s' % self.data)
def hello(self):
self.__hello()
if __name__ == "__main__":
say = Hello('world')
say.hello()
结果:
hello world
- 装饰器:
装饰器也是一种函数,它可以接受函数作为参数,也可以返回一个新的函数。因此,接收一个函数作为参数,在内部对其进行处理,然后返回一个新的函数,动态的增强函数功能,这就是装饰器。
装饰器本质上是一个高阶函数,它接收一个函数作为参数,然后返回一个新的函数,可以让该函数在不改动源代码的情况下增加其他新功能。
当装饰器和被装饰函数在同一个 py
文件时,装饰器需要定义在被装饰函数的前面,python 代码是自上而下依次执行的(从而使得程序在自上而下执行时可以调用上面定义的装饰器)。
用法:
def out(func_args): #外围函数
def inter(*args, **kwargs): #内嵌函数
return func_args(*args, **kwargs)
return inter #外围函数返回内嵌函数
python 通过一个语法糖@
符号来使用装饰器,这样可以避免编写 f = decorate(f)
这样形式的代码。所谓的语法糖便是不使用也可以完成任务,但是使用它可以让代码更简洁。
对于装饰器,需要记住的就是
@decorate
def f():
pass
其中,
@decorate 等价于 f = decorate(f)
示例:
# coding:utf-8
import time
from functools import reduce
def performance(f):
def fn(*args, **kw):
t1 = time.time() #unix时间戳
r = f(*args, **kw)
t2 = time.time()
print('call %s() in %f s' % (f.__name__, t2 - t1))
return r
return fn
@performance
def factorial(n):
return reduce(lambda x, y: x * y, range(1, n+1))
print(factorial(10))
执行结果:
call factorial() in 0.002750 s
3628800
classmethod
装饰器:
classmethod
装饰器的功能是将类函数可以不经过实例化而被直接调用。
用法:
@classmethod
def func(cls,...):
函数具体实现代码块
return 返回值
参数 cls
替代普通类函数中的 self
,代表当前操作的是类。
示例:
# coding:utf-8
class Test(object):
def __init__(self, a):
self.a = a
def run(self):
print('run')
self.dump()
@classmethod
def dump(cls):
print('dump')
t = Test('a')
t.run()
print('-----')
Test.dump()
结果:
run
dump
-----
dump
staticmethod
装饰器:
staticmethod
装饰器的功能是将类函数可以不经过实例化而被直接调用。被该装饰器调用的函数不允许传递 self
或 cls
参数,且无法在该函数内调用其它类函数或类变量。
用法:
@classmethod
def func(...):
函数具体实现代码块
return 返回值
函数体内无 self
或 cls
参数。
示例:
# coding:utf-8
class Test(object):
def __init__(self, a):
self.a = a
def run(self):
print('run')
self.dump()
@staticmethod
def dump():
print('dump')
t = Test('a')
t.dump()
print('-----')
Test.dump()
结果:
dump
-----
dump
property
装饰器:
property
装饰器的功能是将类函数的执行去掉括号,类似于调用属性(类变量)。
用法:
@property
def func(self):
函数具体实现代码块
return 返回值
函数体内只能有 self
参数。
示例:
# coding:utf-8
class Test(object):
def __init__(self, name):
self.__name = name
@property
def name(self):
return self.__name
@name.setter
def name(self, value):
self.__name = value
n = Test('xiaobai')
print(n.name)
n.name = 'xiaohei'
print(n.name)
结果:
xiaobai
xiaohei
- 类的继承:
继承时类与类之间的一种关系,一个类可以通过继承基类来得到基类的功能。所以把被继承的类称为父类或基类,把继承父类的类称为子类。
通过继承,子类可以拥有父类的所有属性和方法,但父类不会拥有子类自有的属性和方法。
用法:
class Parent_ClassName(object): #父类
父类代码实现
class Child_ClassName(Parent_ClassName): #子类
子类代码实现
定义子类时,将父类类名作为参数传入子类,就完成了继承。子类实例化后,可以调用自己与父类的属性和方法。
super
函数:
super
函数的功能是作为 python 子类继承父类的方法而使用的关键字,当子类继承父类后,就可以使用父类的方法。
用法:
class Parent_ClassName(object): #父类
def __init__(self):
...
class Child_ClassName(Parent_ClassName): #子类
def __init__(self):
super(Child_ClassName, self).__init__() #初始化父类的构造函数
示例:
# coding:utf-8
class Person(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender
def speak(self):
print(f'hello!我是{
self.name}')
class Student(Person):
def __init__(self, name, gender, score, major, stu_num='2018014002'):
super().__init__(name, gender)
super().speak()
self.score = score
self.major = major
self.__stu_num = stu_num
def speak(self):
print(f'我的学号为{
self.__stu_num},很高兴认识大家')
def identify(self):
if self.__stu_num == '2018014002':
print('我的分组已完成')
else:
print('请稍后,马上为你自动分组')
def set_num(self, new_num):
self.__stu_num = new_num
def relation(self):
if issubclass(Student, Person):
print('我的父类是Person')
else:
print('父类正在查询中')
if __name__ == '__main__':
stu = Student('小明', '男', 90, '数学')
stu.speak()
stu.identify()
stu.relation()
print('*****************')
stu_2 = Student('小红', '女', 89, '英语')
stu_2.set_num('2018040625')
stu_2.speak()
stu_2.identify()
结果:
hello!我是小明
我的学号为2018014002,很高兴认识大家
我的分组已完成
我的父类是Person
*****************
hello!我是小红
我的学号为2018040625,很高兴认识大家
请稍后,马上为你自动分组
对于 super
函数,super(Child_ClassName, self).__init__()
表示初始化父类的 __init__
函数,也可以初始化父类其它的函数。此外,python3 中,super(Child_ClassName, self).__init__()
可以省略为 super().__init__()
。
- 类的多态:
多态就是一个类继承了父类并重写父类的方法,即一个类的多种状态就是多态。对于父类中不需要的方法,子类可以选择重构。
多态的目的是为了保留子类中和父类名称相同的方法的功能,这样就可以避免全盘接收父类的方法。
示例:
# coding:utf-8
class Person(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender
def speak(self):
print(f'hello!我是{
self.name}')
class Student(Person):
def __init__(self, name, gender, stu_num='2018014002'):
super().__init__(name, gender)
self.__stu_num = stu_num
def speak(self):
print(f'我的学号为{
self.__stu_num},很高兴认识大家')
if __name__ == '__main__':
per = Person('小白', '男')
stu = Student('小明', '男')
per.speak()
stu.speak()
结果:
hello!我是小白
我的学号为2018014002,很高兴认识大家
上例中,父类中的 speak
函数与子类中的 speak
函数名称相同,但功能不一样,这就是类的多态。
- 多重继承:
一个子类继承多个父类,这就是多重继承。
将被继承的父类类名作为参数传入子类,从左到右依次继承。如果多个父类中有名称相同的方法,第一个父类中的该方法会起作用。
多重继承中,继承关系可以顺序延续,后续子类可以继承前驱父类。例如,A类继承B类,B类继承C类,因此A类也继承了C类。
用法:
class Parent1_ClassName(object): #父类1
父类1代码实现
class Parent2_ClassName(object): #父类2
父类2代码实现
class Parent3_ClassName(object): #父类3
父类3代码实现
class Child_ClassName(Parent1_ClassName, Parent2_ClassName, Parent3_ClassName): #子类
子类代码实现
示例:
# coding:utf-8
class Human(object):
def speak(self):
print('human can speak')
class Person(object):
def speak(self):
print('hello world')
def work(self):
print('person work every week')
class Student(Human, Person):
def work(self):
print('student\'s work is study')
if __name__ == '__main__':
stu = Student()
stu.speak()
stu.work()
结果:
human can speak
student's work is study
- 类的高级函数
__str__
:
__str__
函数的功能是,如果定义了 __str__
函数,当 print
当前实例化对象时,会返回该函数的 return
信息。
用法:
def __str__(self):
return str_type
__str__
函数一般返回对于该类的描述信息。
- 类的高级函数
__getattr__
:
__getattr__
函数的功能是,当调用的属性或方法不存在时,会返回该函数定义的信息。
用法:
def __getattr__(self, key):
print(...)
参数 key
表示调用任意不存在的属性名称,返回值可以是任意类型,也可以不返回。
示例:
# coding:utf-8
class Test(object):
def __str__(self):
return 'This is a test class'
def __getattr__(self, item):
print(f'This {
item} is not exists')
t = Test()
print(t)
t.abc
结果:
This is a test class
This abc is not exists
- 类的高级函数
__setattr__
:
__setattr__
函数的功能是拦截当前类中不存在的属性与值。
用法:
def __setattr__(self, key, value):
self.__dict__[key] = value
参数 key
表示当前的属性名,value
表示当前的参数对应的值,无返回值。
- 类的高级函数
__call__
:
__call__
函数的功能是将一个类变成一个函数。
用法:
def __call__(self, *args, **kwargs):
print(...)
可传任意参数,返回值可以是任意类型,也可以不返回。
示例:
# coding:utf-8
class Test(object):
def __str__(self):
return 'This is a test class'
def __getattr__(self, item):
print(f'This {
item} is not exists')
def __setattr__(self, key, value):
self.__dict__[key] = value
print(self.__dict__)
def __call__(self, *args, **kwargs):
print('args is {}'.format(kwargs))
t = Test()
print(t)
t.abc
t.name = 'xiaobai'
print(t.name)
t(name='xiaobai')
结果:
This is a test class
This abc is not exists
{'name': 'xiaobai'}
xiaobai
args is {'name': 'xiaobai'}