Python基础理论 - 面向对象
一 面向对象基本理论 |
面向过程:核心是过程,过程就是解决问题的步骤,即先干什么,再干什么
基于面向过程设计程序,就好比在设计一条流水线,是一种机械思维方法
优点:复杂的问题简单化
缺点:可扩展性差(牵一发而动全身)
应用场景:扩展性低的场合,如linux内核,httpd,git
面向对象:核心是对象,要理解对象应该把自己当成上帝,在上帝眼中一切存在的事物都是对象,不存在也可以创建出来
优点:可扩展性强
缺点:无法像面向过程一样准确地知道什么阶段发生什么事,会有什么结果
应用场景:与用户交互多的,公司内部的软件,游戏,互联网软件
特征与技能的结合体就是一个对象,一系列对象共有的特征(变量的定义)与技能(函数的定义)的结合体就是类
在Python中,用变量表示特征,用函数表示技能,因而类是变量与函数的结合体,对象是变量与方法(指向类的函数)的结合体
类的定义:类是一系列对象共有的特征(变量的定义)与技能(函数的定义)的结合体
PS:在Python3中统一了类型与类的概念
定义类语法:
class 类名:
'''注释'''
类体(可以是任意代码,在定义阶段就执行,产生了作用域的概念)
类的使用:
1. 属性的引用,定义类会执行,生成名称空间
- 数据属性:Chinese.country
- 函数属性:Chinese.talk('123') # 需要几个参数,就得传几个参数,如self
2. 实例化,类是抽象的,实例化后变为对象
- p = Chinese()
对象的使用:只有一种,就是属性引用
- p.country
- p.talk() # 会把p当为一个参数传入talk(self)
对象可以有自己的特征值
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
类实例化本质
p1 = Chinese('Linda', 18, 'female') # Chinese.__init__(p1, 'Linda', 18, 'female')
self=p1, p1.name=name, p1.age=age, p1.sex=sex
类名称空间
- print(Chinese.__dict__) # 属性字典
对象名称空间
- print(p1.__dict__) # 属性字典
print(p1.name) # 等价于 p1.__dict__['name'],本质以变量名的字符串作为key,去调用__dict__,取得值
print(p1.__dict__['name'])
对象使用属性时,先在自己对象的名称空间,再找所属类的名称空间
小结:
1. 类具有数据属性和函数属性,而对象只有数据属性;但是对象可以调用类的方法
- Chinese.talk(123) # 类调用时,和普通方法一样,需几个参数,就传几个参数
- p1.talk() # 绑定方法,绑定的含义就是p1默认作为一个参数传入,Chinese.talk(p1)
谁来用,就是谁的效果,p1.talk()就是p1的效果,self,__main__.Chinese object
2. 定义在类内部的变量,是所有对象共有的,id全一样
3. 定义在类内部的函数,是绑定到所有对象的,是给对象来用,obj.func()会把obj本身当做一个参数
二 封装、继承、多态 |
什么是继承?
继承是一种创建新类的方式,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类
class ParentClass(object):
pass
class SubClass(ParentClass):
pass
print(SubClass.__bases__)
抽象即抽取类似或者说比较像的部分
抽象分成两个层次:
1. 将奥巴马和梅西这俩抽象比较像的部分抽取成类;
2. 将人、猪、狗这三个类比较像的部分抽取成父类。
抽象最主要的作用是划分类别(可以隔离关注点,降低复杂度)
继承:是基于抽象的结果,通过编程语言去实现它,肯定先经历抽象这个过程,
才能通过继承的方式去表达抽象的结构。
继承的好处一:减少冗余代码
class People(Animal):
def __init__(self, name, age, sex, education):
Animal.__init__(self, name, age, sex)
self.education = education
在子类定义新的属性,覆盖掉父类的属性,称为覆盖,override
s.bar(), 顺序:对象自己的__dict__,类的__dict__,父类的__dict__,....
继承反映的是 一种什么是什么的关系
组合反映的是 一种什么有什么的关系
继承的实现原理 - Python3
'''
E D
A B C
F
Python3 广度优先:F - A - E - B - D - C
'''
在子类调用父类的方法
super(自己类名, self).__init__() # 父类的__init__()
使用super()调用的所有属性,都是从MRO列表当前的位置往后找。
多态
同一种事物的多种形态,指的是父类
people_obj1.talk()
pig_obj1.talk()
dog_obj1.talk()
def func(obj):
obj.talk()
好处:同一种调用方式,传入不同的对象,实现不同功能
封装不是单纯的隐藏
封装数据的主要原因:保护隐私
封装方法的主要原因:隔离复杂度
封装其实分为两个层面,但无论那种层面的封装,都要对外界提供访问你内部隐藏内容的接口
第一层面的封装(什么都不用做):创建类和对象分别创建二者的名称空间,我们只能用类名.或者obj.的方式访问里面的名字,这本身就是一种封装
第二个层面的封装:类中把某些属性和方法隐藏起来(或者说定义成私有的),只能在类的内部使用、外部无法访问,或者留下少量(函数)供外部访问
在Python中用双下划线的方式实现隐藏属性(设置成私有的)
语法层面,定义__x时,自动变为_People__x,这种自动变形的特点:
1. 类中定义的__x只能在内部使用,如self.__x,引用的是变形后的结果
2. 这种变形其实是针对外部的变形,在外部是无法通过__x这个名字访问到的
3. 在子类定义的__x不会覆盖父类定义的__x
property 作为类函数的装饰器,把类的函数属性,变为数据属性
class Foo(object):
@property
def test(self):
print('from Foo.test') obj = Foo()
obj.test
也是一种封装,当test为名词时,更适合作为属性,而不是方法
被@property装饰的函数,是不能直接赋值的,得通过@test.setter定义单独函数来设置
class People(object):
def __init__(self, name):
self.__name =name @property
def name(self):
return self.__name @name.setter
def name(self,value):
self.__name = value @name.deleter
def name(self):
del self.__name p1 = People('Linda')
print(p1.name) p1.name = 'Alex'
print(p1.name) del p1.name
print(p1.name) # 报错
绑定方法与非绑定方法
在类内部定义的,只要没有装饰器,就是绑定到对象的方法,给对象用的,对象默认作为第一个参数传入
在类内部定义的,有@classmethod装饰器,是绑定到类的方法,给类用的,类默认作为第一个参数传入
class Foo(object):
@classmethod
def test(cls):
print(cls) f = Foo()
Foo.test() # 类作为第一个参数传进去,结果为:<class '__main__.Foo'>
f.test() # 即使是对象调用,也是把所属类传进去,结果为:<class '__main__.Foo'>
在类的定义定义的,有@staticmethod装饰器,就不是绑定方法了,不存在默认传值的问题,定义几个参数,就传几个参数即可
class Foo(object):
@staticmethod
def test():
print('from Foo.test') Foo.test() # from Foo.test
f = Foo()
f.test() # from Foo.test
分析小结:
class Foo(object):
def test1(self):
pass @classmethod
def test2(cls):
pass @staticmethod
def test3():
pass f = Foo()
print(f.test1) # <bound method Foo.test1 of <__main__.Foo object at 0x000000D539EB55F8>>
print(Foo.test2) # <bound method Foo.test2 of <class '__main__.Foo'>>
print(f.test3) # <function Foo.test3 at 0x000000D539EA6D08>
print(Foo.test3) # <function Foo.test3 at 0x000000D539EA6D08>
小例子:
import settings
import hashlib
import time class MySQL(object):
def __init__(self, host, port):
self.id = self.create_id() # create_id()具有生成唯一id的功能,普通工具包而已
self.host = host
self.port = port
print('connecting...') @classmethod
def from_conf(cls):
return cls(settings.HOST, settings.PORT) # MySQL('127.0.0.1', 3306),cls功能:实例化,得到对象 @staticmethod # 非绑定方法,普通工具包,不需传入self或者cls
def create_id():
m = hashlib.md5(str(time.clock()).encode('utf-8'))
return m.hexdigest() def select(self):
print('select...') conn1 = MySQL('192.168.0.1', 3306) # 第一种初始化,用户输入
conn2 = MySQL.from_conf() # 第二种初始化,从配置文件读取
面向对象高级部分 |
1. isinstance(obj, cls)与issubclass(sub, super)
isinstance(obj, cls)检查obj是否是类cls的对象
issubclass(sub, super)检查sub是否是类super的子类
2. 反射
反射主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)
Python面向对象的反射:通过字符串的形式操作对象相关属性。Python中一切事物都是对象(都可以使用发射)
四个可以实现自省的函数,下列方法适用于类和对象
# 判断object中有没有一个name字符串对应的方法或属性
hasattr(object,name)
# name作为字符串,获取object的属性或方法
getattr(object, name, default=None)
# 设置对象x的属性y=v
setattr(x, y, v)
# 删除对象x的属性y
delattr(x, y)
class Chinese(object):
country = 'China'
def __init__(self, name, age):
self.name = name
self.age = age p = Chinese('Linda', 18)
print(p.name) # p.__dict__('name')
# p.x # 报错 'Chinese' object has no attribute 'x'
print(hasattr(p, 'x')) # False # 设置
setattr(p, 'x', 112233) # {'name': 'Linda', 'x': 112233, 'age': 18}
print(p.__dict__) # 检测、获取
if hasattr(p, 'x'):
res = getattr(p, 'x')
print(res) # # 删除
delattr(p, 'x')
print(p.__dict__) # {'name': 'Linda', 'age': 18}
四个方法的使用演示
class Foo(object):
static_field = "static_filed" def __init__(self):
self.name = 'Linda' def func(self):
return 'func' @staticmethod
def bar():
return 'bar' print(getattr(Foo, 'static_field'))
print(getattr(Foo, 'func'))
print(getattr(Foo, 'bar'))
类也是对象
import sys def s1():
print('s1') def s2():
print('s2') this_module = sys.modules[__name__] print(hasattr(this_module, 's1'))
print(getattr(this_module, 's2'))
反射模块当前成员
"""
程序目录:
module_test.py
index.py 当前文件:
index.py
""" import module_test as obj # obj.test() print(hasattr(obj, 'test')) getattr(obj,'test')()
导入其他模块,利用反射查找该模块是否存在某个方法
反射的好处,可以事先定义好接口,接口只有在被完成后才会真正执行
程序员A开发了一个ftp客户端,但是没有实现get方法,程序员B得调用这个客户端
# ftpclient.py
class FtpClient(object):
def __init__(self, addr):
self.addr = addr
print('正在连接[%s]...' % self.addr) # def get(self):
# print('正在下载...')
ftpclient.py
import ftpclient
f1 = ftpclient.FtpClient('192.168.0.1') if hasattr(f1, 'get'):
func = getattr(f1, 'get')
func()
print('其他程序1')
print('其他程序2')
print('其他程序3')
print('其他程序4')
引用ftpclient.py
类基于用户输入的字符串,反射自己是否有相应的方法,从而自动执行
class FtpClient(object):
def __init__(self, addr):
self.addr = addr
print('正在连接[%s]....' % self.addr) def get(self, arg):
print('正在下载[%s]....' % (arg[1])) def run(self):
while True:
inp = input('>>: ').strip()
inp_list = inp.split()
if hasattr(self, inp_list[0]):
func = getattr(self, inp_list[0])
func(inp_list) f1 = FtpClient('192.168.0.1')
f1.run()
交互式反射应用
反射另外好处,动态导入模块(基于反射当前模块成员)
m = __import__('sys')
print(m.path) import importlib
m2 = importlib.import_module('sys')
print(m2.path)
动态导入模块
3. __str__()
print(obj) 调用obj.__str__()
det __str__(self):
# 必须有返回值,且必须返回字符串类型
return 'xxxxxxx'
4. __del__()
析构函数,对象被删除的时候,立刻执行obj.__del__(),自动回收内存等,也可以写一些清除数据库连接等操作
class Foo(object):
def __init__(self, name, age):
self.name = name
self.age = age def __del__(self): # 析构函数
print('del---->') obj = Foo('Linda', 18)
# del obj
print('=========>')
5. __setitem__(), __getitem__(), __delitem__()
把对象模拟成字典形式操作,和字典就可以统一处理了
class Foo(object):
def __init__(self, name, age):
self.name = name
self.age = age def __getitem__(self, item):
print('from __getitem__()')
return self.__dict__[item] def __setitem__(self, key, value):
print('from __setitem__')
self.__dict__[key] = value def __delitem__(self, key):
print('from __delitem__')
self.__dict__.pop(key) obj = Foo('Linda', 18)
print(obj['name']) # 触发self.__getitem__()执行 obj['name'] = 'Jonathan' # 触发self.__setitem__()执行
print(obj.name) del obj['name']
print(obj.name) # 'Foo' object has no attribute 'name'
6. __setattr__(), __getattr__(), __delattr__()
对象操作属性时,触发相应函数
class Foo(object): def __setattr__(self, key, value):
print('form __setattr__')
self.__dict__[key] = value def __getattr__(self, item):
print('from __getattr__') def __delattr__(self, item):
print('from __delattr__') obj = Foo()
obj.x = 1 # 设置属性时,会触发执行__setattr__()执行
print(obj.__dict__)
print(obj.yyyyy) # 没有属性yyyyy的时候才会触发 __getatrr__()执行
del obj.x # 删除属性时,会触发执行__delattr__()执行
7. 加工标准类型
继承 class List(list):pass
授权 class Open(object):pass 关键点 def __getattr__():pass
class Open(object):
def __init__(self, file_path, mode='r', encoding='utf-8'):
self.file_path = file_path
self.mode = mode
self.encoding = encoding
self.f = open(self.file_path, mode=self.mode, encoding=self.encoding) def __getattr__(self, item):
print(item, type(item))
return getattr(self.f, item) obj = Open('a.txt',mode='r')
obj.seek # seek <class 'str'>
8. __next__() 和 __iter__()实现迭代器协议
class Foo(object):
def __init__(self, n, stop):
self.n = n
self.stop = stop def __next__(self):
if self.n >= self.stop:
raise StopIteration
x = self.n
self.n += 1
return x def __iter__(self):
return self obj = Foo(0, 100)
print(next(obj))
print(next(obj)) from collections import Iterator
print(isinstance(obj, Iterator)) for i in obj:
print(i)
9. __doc__()
class Foo:
'我是描述信息'
pass print(Foo.__doc__)
它类的描述信息
class Foo:
'我是描述信息'
pass class Bar(Foo):
pass
print(Bar.__doc__) #该属性无法继承给子类
该属性无法被继承
10. __module__(), __class__()
__module__ 表示当前操作的对象在那个模块
__class__ 表示当前操作的对象的类是什么
11. __enter__(), __exit__()
我们知道在操作文件对象的时候可以这么写
with open('a.txt') as f:
'代码块'
上述叫做上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法
class Foo(object):
def __enter__(self):
print('__enter__')
return 'aaaa' def __exit__(self, exc_type, exc_val, exc_tb):
print('__exit__') with Foo() as f: # f = Foo(),触发def__enter__()执行
print(f)
print('----->')
print('----->')
print('----->')
pass # 最后触发 __exit__()执行
__exit__()中的三个参数分别代表异常类型,异常值和追溯信息,with语句中代码块出现异常,则with后的代码都无法执行
class Open:
def __init__(self,name):
self.name=name def __enter__(self):
print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量') def __exit__(self, exc_type, exc_val, exc_tb):
print('with中代码块执行完毕时执行我啊')
print(exc_type)
print(exc_val)
print(exc_tb) with Open('a.txt') as f:
print('=====>执行代码块')
raise AttributeError('***着火啦,救火啊***')
print(''*100) #------------------------------->不会执行
如果__exit()返回值为True,那么异常会被清空,就好像啥都没发生一样,with后的语句正常执行
class Open:
def __init__(self,name):
self.name=name def __enter__(self):
print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量') def __exit__(self, exc_type, exc_val, exc_tb):
print('with中代码块执行完毕时执行我啊')
print(exc_type)
print(exc_val)
print(exc_tb)
return True with Open('a.txt') as f:
print('=====>执行代码块')
raise AttributeError('***着火啦,救火啊***')
print(''*100) #------------------------------->会执行
class Open:
def __init__(self,filepath,mode='r',encoding='utf-8'):
self.filepath=filepath
self.mode=mode
self.encoding=encoding def __enter__(self):
# print('enter')
self.f=open(self.filepath,mode=self.mode,encoding=self.encoding)
return self.f def __exit__(self, exc_type, exc_val, exc_tb):
# print('exit')
self.f.close()
return True
def __getattr__(self, item):
return getattr(self.f,item) with Open('a.txt','w') as f:
print(f)
f.write('aaaaaa')
f.wasdf #抛出异常,交给__exit__处理
练习:模拟Open
用途或者说好处:
使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须手动干预
在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制,你无须再去关系这个问题,这将大有用处
12. __call__()
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
class Foo:
def __init__(self):
pass def __call__(self, *args, **kwargs):
print('__call__') obj = Foo() # 执行 __init__
obj() # 执行 __call__
Python基础理论 - 面向对象的更多相关文章
- python基础——面向对象编程
python基础——面向对象编程 面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想.OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的 ...
- Python的面向对象3
接下来,我们接着讲Python的面向对象,在上一次的博客中,我们详细介绍了类与对象的属性,今天,我们来详细介绍一下面向对象中的方法! 1.定义实例方法 一个实例的私有属性就是以__开头的属性,无法被外 ...
- Python的面向对象2
我们接着讲解Python的面向对象 1.初始化实例属性 在现实生活中,一种类型的实例会具有相同的某些属性,把这些实例划分为一个类型,则这些实例必然有相似的部分.但是,在创建实例之后,我们一个一个的为实 ...
- Python的面向对象1
今天,我们来介绍Python的面向对象编程,其实面向对象并不陌生,在C++ ,Java ,PHP中也有大量使用! 好了,我们来步入正题! 那什么是面向对象编程呢? 1. 面向对象编程是一种程序设计 ...
- My way to Python - Day05 - 面向对象-思维导图
My way to Python - Day05 - 面向对象 思维导图
- Python进阶---面向对象的程序设计思想
Python的面向对象 一.面向过程与面向对象的对比 面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. 优 ...
- Python之面向对象一
引子 小游戏:人狗大战 角色:人和狗 角色属性:姓名,血量,战斗力和性别(种类) 技能:打/咬 用函数实现人打狗和狗咬人的情形 def Dog(name,blood,aggr,kind): dog = ...
- python基础——面向对象进阶下
python基础--面向对象进阶下 1 __setitem__,__getitem,__delitem__ 把对象操作属性模拟成字典的格式 想对比__getattr__(), __setattr__( ...
- python基础——面向对象进阶
python基础--面向对象进阶 1.isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的对象 ...
随机推荐
- eleTree树形插件引入
先放一个效果 @eleTree插件官网 刚开始用的xtree,不知为何总是达不到效果,不得已从layui官网插件中寻得这个eleTree插件,看着还不错,用法也简单.不过还是有点坑需要大家注意 开始使 ...
- xp密钥-资源分享
xp-密钥:QC986-27D34-6M3TY-JJXP9-TBGMD ftp-资源地址: ftp://10.10.31.2/?tdsourcetag=s_pctim_aiomsg
- ReentrantLock示例说明
1.ReentrantLock锁 import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; impor ...
- nginx新增tcp模板
最近在装nginx时,发现新增了tcp模板,装了一遍,现记录下来过程. 1.下载nginx源码包,并解压 2.下载tcp模板压缩包https://github.com/yaoweibin/nginx_ ...
- 使用串口安装centos操作系统
https://linuxconfig.org/how-to-force-text-mode-installation-of-redhat-linux https://www.centos.org/f ...
- 【aardio】如何让edit控件只能输入数字、小数点及 - 号
import win.ui; /*DSG{{*/ var winform = win.form(parent=...; text="aardio Form";right=349;b ...
- yarn查询/cluster/nodes均返回localhost
背景: 1.已禁用ipv6. 2.所有节点的/etc/hosts正确配置,任务在ResourceManager提交. 3.yarn-site.xml中指定了 yarn.resourcemanager. ...
- TCP两次握手
TCP的三次握手已经说烂了,TCP为何要三次握手?为何不两次握手也有很多说法.对于这些类似的问题,最好的办法是看RFC 常规思路,由面到点 两军问题 在不可靠通信下,两军想要达到状态一致是无解的.因为 ...
- java画按钮的边框
import javax.swing.*;import java.awt.*;public class demo_4{ public static void main(String [] arg ...
- [入门]在Mac OS X下使用和配置Android Studio
Android Studio可谓是安卓开发的XCode,流畅的速度+顺眼的UI足以秒杀Eclipse.在Mac OS X可以通过如下的途径获得Android Studio 最新版本的Android ...