一、私有化
xx
: 公有变量_x
:单前置下划线,私有化属性或方法,from somemodule import *
禁止导入,类对象和子类可以访问__xx
: 双前置下划线,避免与子类中的属性命名冲突,无法外部直接访问(名字重整所以访问不到)__xx__
: 双前后下划线,用户名字空间的魔法对象或属性。例如:__init__
,__
不要自己发明这样的名字xx_
: 单后置下划线,用于避免与 Python 关键字的冲突
通过 name mangling (名字重整(目的就是防子类以重写基类的方法或者属性)如:_Class__object
)机制就可以访问 private
了
class Person(object): def __init__(self,name,age,taste): self.name = name self._age = age self.__taste = taste def showperson(self): print(self.name) print(self._age) print(self.__taste) def dowork(self): self._work() def _work(self): print("my _work") def __away(self): print("my __away") class Student(Person): def construction(self,name,age,taste): self.name = name self._age = age self.__taste = taste def showstudent(self): print(self._age) print(self.name) print(self.__taste) @staticmethod def testbug(): _Bug.showbug() class _Bug(object): @staticmethod def showbug(): print("showbug") s1 = Student('jack', 25, 'football') s1.showperson() print('*'*20) # 无法访问__taste,导致报错 # s1.showstudent() s1.construction('rose', 30, 'basketball') s1.showperson() print('*'*20) s1.showstudent() print('*'*20) Student.testbug()
- 总结
- 父类中属性名为
__名字
的,子类不继承,子类不能访问 - 如果在子类中向
__名字
赋值,那么会在子类中定义的一个与父类相同名字的属性
_名
的变量、函数、类在使用from xxx import *
时都不会被导入
二、import 导入模块
- 2.1、常见的导入方式
from xxx import yyy import xxx from xxx import * import xxx,yyy from xxx import zzz,nnn import xxx as bbb
- 2.2、
import xxx as bbb
给模块起别名
- 给模块起别名的好处:(1)、可以简化模块名太长的问题;(2)、解决引用的模块有和模块名一样的变量名
- 举个例子:如果你导入一个模块aa,模块里面有一个属性 name,你在当前的模块又定义了一个变量aa,那么你再调用模块aa的name赋值的时候就会报错
import aa aa = 100 aa.name = "Jack"
- 运行结果:
AttributeError: 'int' object has no attribute 'name'
如果我们给aa模块起个别名bb,如:import aa as bb
就不会报错了
import aa as bb aa = 100 bb.name = "Jack"
- 2.3、import 搜索路径
import sys print(sys.path)
- 路径搜索
- 从上面列出的目录里依次查找要导入的模块文件
''
表示当前路径- 列表中的路径的先后顺序代表了python解释器在搜索模块时的先后顺序
- 程序执行时添加新的模块路径
sys.path.append('/home/itcast/xxx') sys.path.insert(0, '/home/itcast/xxx') # 可以确保先搜索这个路径
- .4、重新导入模块
模块被导入后,import module不能重新导入模块,重新导入需用reload,也就是当你在一个模块内导入了一个import module
,接不管i导入多少次import module
都不起作用,只有第一句导入有效
三、多个模块 import 导入注意点(也就是公共模块的问题)
- 3.1、我们定义4个模块:
main
、Test1
、Test2
、Common
- Common 模块里面定义一个变量 HANDLE,初始值 FALSE
HANDLE = FALSE
- Test1 模块
from Common import HANDLE def change1(): HANDLE = True if HANDLE: print("在 Test 里面修改HANDLE为:True") else: print("在 Test 里面没有修改HANDLE的值") print("*"*20)
- Test2 模块
from Common import HANDLE def change2(): print(HANDLE) if HANDLE: print("在Test2里面 HANDLE 变为 True") else: print("在Test2里面 HANDLE 变为 False") print("*" * 20)
- main 模块
import Common import Test1 import Test2 if __name__ == "__main__": if Common.HANDLE: print("HANDLE在Common里面最初的值为 True") else: print("HANDLE在Common里面最初的值为 False") print("*"*20) Test1.change1() Test2.change2() if Common.HANDLE: print("HANDLE为 True") else: print("HANDLE为 False")
- main模块的打印结果:
HANDLE在Common里面最初的值为 False ******************** 在 Test 里面修改HANDLE为:True ******************** False 在Test2里面 HANDLE 变为 False ******************** HANDLE为 False
- 分析:在 Test1 里面把
HANDLE
修改为True
后,为什么在 Test2 里面HANDLE
的值不是True
,还有就是 Common里面也没有变为 True; - 原因:在其他模块 使用
from Common import HANDLE
,仅仅是HANDLE
指向了 Common 里面HANDLE
的 值,在其他模块不会在对HANDLE
赋值的时候,仅仅是HANDLE
的引用指向发生了变化,并没有修改 Common 里面HANDLE
的 值,说简单了:在其他模块导入from Common import HANDLE
,仅仅是定义了 一个HANDLE
变量;如果你在 Common 里面定义一个列表list()
,在其他模块导入列表的时候,在使用上是 使用列表的一些方法 对列表进行增加与减少,那么在其他模块 列表是会发生变化的 - 解决办法:在其他模块
import Common
导入就不会有问题了,再使用HANDLE
就是Common. HANDLE
,指向的是 Common 这个模块 - 效果:在Test1与Test2 使用
import Common
导入,Common. HANDLE
调用
HANDLE在Common里面最初的值为 False ******************** 在 Test 里面修改HANDLE为:True ******************** True 在Test2里面 HANDLE 变为 True ******************** HANDLE为 True
四、再议 封装、继承、多态
- 4.1、为啥要封装?
- 好处
- 1、在使用面向过程编程时,当需要对数据处理时,需要考虑用哪个模板中哪个函数来进行操作,但是当用面向对象编程时,因为已经将数据存储到了这个独立的空间中,这个独立的空间(即对象)中通过一个特殊的变量(
__class__
)能够获取到类(模板),而且这个类中的方法是有一定数量的,与此类无关的将不会出现在本类中,因此需要对数据处理时,可以很快速的定位到需要的方法是谁 这样更方便- 2、全局变量是只能有1份的,多很多个函数需要多个备份时,往往需要利用其它的变量来进行储存;而通过封装 会将用来存储数据的这个变量 变为了对象中的一个“全局”变量,只要对象不一样那么这个变量就可以再有1份,所以这样更方便
- 3、代码划分更清晰
- 4.2、为啥要继承
- 说明:
1、能够提升代码的重用率,即开发一个类,可以在多个子功能中直接使用
2、继承能够有效的进行代码的管理,当某个类有问题只要修改这个类就行,而其继承这个类的子类往往不需要就修改
- 4.3、怎样理解多态
class MiniOS(object): """MiniOS 操作系统类 """ def __init__(self, name): self.name = name self.apps = [] # 安装的应用程序名称列表 def __str__(self): return "%s 安装的软件列表为 %s" % (self.name, str(self.apps)) def install_app(self, app): # 判断是否已经安装了软件 if app.name in self.apps: print("已经安装了 %s,无需再次安装" % app.name) else: app.install() self.apps.append(app.name) class App(object): def __init__(self, name, version, desc): self.name = name self.version = version self.desc = desc def __str__(self): return "%s 的当前版本是 %s - %s" % (self.name, self.version, self.desc) def install(self): print("将 %s [%s] 的执行程序复制到程序目录..." % (self.name, self.version)) class PyCharm(App): pass class Chrome(App): def install(self): print("正在解压缩安装程序...") super().install() linux = MiniOS("Linux") print(linux) pycharm = PyCharm("PyCharm", "1.0", "python 开发的 IDE 环境") chrome = Chrome("Chrome", "2.0", "谷歌浏览器") linux.install_app(pycharm) linux.install_app(chrome) linux.install_app(chrome) print(linux)
- 运行结果
Linux 安装的软件列表为 [] 将 PyCharm [1.0] 的执行程序复制到程序目录... 正在解压缩安装程序... 将 Chrome [2.0] 的执行程序复制到程序目录... 已经安装了 Chrome,无需再次安装 Linux 安装的软件列表为 ['PyCharm', 'Chrome']
- 提示:
在理解多态的时候,相比前两者有点困难,我们可以简单的理解为,我们继承父类之后就拥有了父类的方法,如果父类的方法不能满足的时候,我们可以重写父类的方法,那么父类的方法就不会走了;如果你还想用父类的方法,那么久需要在重写父类的方法下面调用父类的方法,具体是先调用父类的方法,还是后调用父类的方法,那要看我们的处理了