#面向对象 (解决问题的思路)
def 函数名(): #定义一个函数的方式
xxxx
class 类名(object): #定义一个类的方式
xxxxx
1、类名命名规则 :大驼峰 定义类时有2种:新式类和经典类,上面的Car为经典类,如果是Car(object)则为新式类
2、类包含三部分 (类名 、 属性(修饰及信息 ) 、方法(可以干什么(行为/功能)) )
3、创建对象:对象名 = 类名()
4、设置或获取属性值,要重新定义一个方法 这样安全些
5、获取这个对象的属性,2种方法:
01. 对象.属性
02. 定义一个方法,这个方法中,使用 self.属性
6、调用对象的方法(实例方法):对象名.方法()
7、__init__()方法:
1. 是python自动调用的方法,调用的时间为:创建完对象之后,立马自动调用
2. 不需要开发者调用,即 对象名.__init__()
3. 这个方法一般情况下会完成一些默认的事情,比如添加一些属性
class Xxxx:
def __init__(self, new_a, new_b):
self.a = new_a
self.b = new_b
注意:new_a、new_b 是局部变量,并不是对象的属性,如果想在__init__方法中添加属性的话,需要使用类似
self.属性名 = 值的格式,此时self.a = new_a表示的是给对象添加一个属性,这个属性名为a,这个属性的值为局部变量new_a里面的值
__init__(self)
中,默认有1个参数名字为self,如果在创建对象时传递了2个实参,那么__init__(self)
中出了self作为第一个形参外还需要2个形参,例如__init__(self,x,y)
__init__(self)
中的self参数,不需要开发者传递,python解释器会自动把当前的对象引用传递进去
8、__str__() :
return 我们想要打印的东西 #打印的东西 不是地址 而是我们想要打印的东西
在python中方法名如果是__xxxx__()
的,那么就有特殊的功能,因此叫做“魔法”方法
当使用print输出对象的时候,只要自己定义了__str__(self)
方法,那么就会打印从在这个方法中return的数据
def __str__(self):
msg = "嘿。。。我的颜色是" + self.color + "我有" + int(self.wheelNum) + "个轮胎..."
return msg
如果一个对象保存了另一个对象以及另一个对象的引用,可以调用另一个对象所有的属性和方法
为了更好的保存属性安全,即不能随意修改,一般的处理方式为
- 将属性定义为私有属性
- 添加一个可以调用的方法,供调用
Python中没有像C++中public和private这些关键字来区别公有属性和私有属性
它是以属性命名方式来区分,如果在属性名前面加了2个下划线'__',则表明该属性是私有属性,否则为公有属性(方法也是一样,方法名前面加了2个下划线的话表示该方法是私有的,否则为公有的)。
9、 __del__() 当删除一个对象时,python解释器也会默认调用一个方法,这个方法为__del__()方法
- 当有1个变量保存了对象的引用时,此对象的引用计数就会加1
- 当使用del删除变量指向的对象时,如果对象的引用计数不会1,比如3,那么此时只会让这个引用计数减1,即变为2,当再次调用del时,变为1,如果再调用1次del,此时会真的把对象进行删除
10、继承 (单继承 、多继承)
注意点:
子类在继承的时候,在定义类时,小括号()中为父类的名字
父类的属性、方法,会被继承给子类(隐私属性和隐私方法无法调用)
私有的属性,不能通过对象直接访问,但是可以通过方法访问
私有的方法,不能通过对象直接访问
私有的属性、方法,不会被子类继承,也不能被访问
一般情况下,私有的属性、方法都是不对外公布的,往往用来做内部的事情,起到安全的作用
所谓多继承,即子类有多个父类,并且具有它们的特征
11、重写父类方法与调用父类方法
01. 重写父类方法 所谓重写,就是子类中,有一个和父类相同名字的方法,在子类中的方法会覆盖掉父类中同名的方法
02. 调用父类的方法
# 调用父类的__init__方法
super().__init__(name)
super().父类的方法名() Python3用这种
多态:所谓多态:定义时的类型和运行时的类型不一样,此时就成为多态
Python是弱类型语言 多态不明显
12、面向对象编程三种特性 :封装(类) 继承(相同的类) 多态(定义和调用的方法可能不一样)
13、类属性、实例属性 (类属性(跟着类走,在方法外面,类里面) 实例属性(跟着实例走))
公有的类属性,在类外可以通过类对象
和实例对象
访问
class People(object):
name = 'Tom' #公有的类属性
__age = 12 #私有的类属性
p = People()
print(p.name) #正确
print(People.name) #正确
print(p.__age) #错误,不能在类外通过实例对象访问私有的类属性
print(People.__age) #错误,不能在类外通过类对象访问私有的类属性
如果需要在类外修改
类属性
,必须通过类对象
去引用然后进行修改。(通过 类名.类属性= * 可以修改类属性的值 )如果通过实例对象去引用,会产生一个同名的实例属性
,这种方式修改的是实例属性
,不会影响到类属性
,并且之后如果通过实例对象去引用该名称的属性,实例属性会强制屏蔽掉类属性,即引用的是实例属性
,除非删除了该实例
属性
。
class People(object):
country = 'china' #类属性
print(People.country)
p = People()
print(p.country)
p.country = 'japan'
print(p.country) #实例属性会屏蔽掉同名的类属性
print(People.country)
del p.country #删除实例属性
print(p.country)
14、静态方法和类方法
01. 类方法
类方法是类对象所拥有的方法,需要用修饰器{ @classmethod } 来标识其为类方法 ,对于类方法,第一个参数必须是类对象, 一般以cls ,作为第一个参数 ,能够通过实例对象和类对象去访问。
class People(object):
country = 'china'
#类方法,用classmethod来进行修饰
@classmethod
def getCountry(cls):
return cls.country
p = People()
print p.getCountry() #可以用过实例对象引用
print People.getCountry() #可以通过类对象引用
用类方法对类属性修改之后,通过类对象和实例对象访问都发生了改变
02. 静态方法
需要通过修饰器@staticmethod来进行修饰,静态方法不需要多定义参数
class People(object):
country = 'china'
@staticmethod
#静态方法
def getCountry():
return People.country
print People.getCountry()
注意点: 用类名 调用 类方法和静态方法 可读性更高
不允许 使用类名访问实例属性 、实例方法
15、工厂模式
01、简单工厂方法: 解耦 模块化 使功能更加单一
Python3创建一个类的时候要明确(object)
02、工厂方法:基类不实现 通过子类重写部分代码实现
16、__new__方法
class A(object):
def __init__(self):
print("这是 init 方法")
def __new__(cls):
print("这是 new 方法")
return object.__new__(cls)
A()
__new__(cls) 完成对象的创建
01 __new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供
02 __new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例
return object.__new__(cls) 或者是return super().__new__(cls)
03 __init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值
04 我们可以将类比作制造商,__new__方法就是前期的原材料购买环节,__init__方法就是在有原材料的基础上,加工,初始化商品环节。
17、单例模式
通过 对__new__()以及 __init()修改 达到创建的对象指向同一片区域
cls =“类名”
18、异常 异常就是程序崩了
01、捕获异常: try... except ....
try:
可能出现异常的代码
except 异常1:
处理的方式1
except 异常2:
处理的方式2
except (异常1,异常2):
捕获多个异常同一个处理的方式
except 异常 as result:
print("产生了一个异常...%s"%result) #打印系统默认捕获的异常的信息
except (异常1,异常2) as result:
print("产生了一个异常...%s"%result) #打印系统默认捕获的异常的信息
02、捕获所有异常并打印系统默认提示异常信息:
try:
可能出现异常的代码
except Exception as result:
处理的方式
03、try ...else :
try:
可能出现异常的代码
except 异常:
处理的方式
else:
如果try里没有产生异常执行的事情
04、try ...finally :
try:
可能出现异常的代码
except 异常:
处理的方式
finally :
任何情况下,不管有没有异常都要做的事情
05、异常的传递:
如果一个异常是在一个函数中产生的,例如函数A---->函数B---->函数C,而异常是在函数C中产生的,那么如果函数C中没有对这个异常进行处理,那么这个异常会传递到函数B中,如果函数B有异常处理那么就会按照函数B的处理方式进行执行;如果函数B也没有异常处理,那么这个异常会继续传递,以此类推。。。如果所有的函数都没有处理,那么此时就会进行异常的默认处理,即通常见到的那样
06、异常处理中抛出异常 (利用一个变换的变量,先保存异常然后把异常抛出)
07、抛出自定义异常
raise 继承Exception创建的类(自定义的异常) 从键盘获取一个值,根据值的长度是否符合要求而选择是否抛出异常
class ShortInputException(Exception):
'''自定义的异常类'''
def __init__(self, length, atleast):
super().__init__()
self.length = length
self.atleast = atleast
try:
s = input('请输入 --> ')
if len(s) < 3:
# raise引发一个你定义的异常
raise ShortInputException(len(s), 3)
except EOFError:
print("你输入了一个结束标记EOF")
except ShortInputException as result:#x这个变量被绑定到了错误的实例
print('ShortInputException: 输入的长度是 %d,长度至少应是 %d'% (result.length, result.atleast))
else:
print('没有异常发生.')
注意
- 以上程序中,关于代码
#super().__init__()
的说明这一行代码,可以调用也可以不调用,建议调用,因为
__init__
方法往往是用来对创建完的对象进行初始化工作,如果在子类中重写了父类的__init__
方法,即意味着父类中的很多初始化工作没有做,这样就不保证程序的稳定了,所以在以后的开发中,如果重写了父类的__init__
方法,最好是先调用父类的这个方法,然后再添加自己的功能
19、模块 (具有特殊功能的代码块(.py文件))
--------01>导入模块: 引用方式为:模块名.函数名(模块.功能)
01、import 模块的名称 demo: import random
02、from ....import..... demo: from random import randint 不会把整个random模块导入到当前的命名空间中,它只会将模块里randit的单个引入
03、from … import * demo: from random import * 这提供了一个简单的方法来导入一个模块中的所有项目。然而这种声明不该被过多地使用。
模块测试+调用代码:
自己测试的时候执行 if后面的代码 (打出来是__main__) 别人调用的时候(打出来是导入的模块的名字)不执行if后面的代码
if __name__ == "__main__":
main()
import导入模块时,生成pycache
20、模块中的__all__
1. 没有__all__
2. 模块中有__all__ __all__ =[导入的内容] 后期别的程序调用的时候只能调用导入的内容
21、Python中的包:
将有联系的模块组织在一起,即放到同一个文件夹下,并且在这个文件夹创建一个名字为__init__.py 文件,不管__init__.py 文件是否为空,整个文件夹称之为包
(一般文件夹内含有 __init__.py 文件 且__init__.py 文件内写入变量---->__all__ =[“模块名”] 内容,如果__init__.py 文件为空,仅仅是把这个包导入,不会导入包中的模块,之所以定义一个__all__
变量,因为它控制着 from 包名 import *时导入的模块)
有效避免模块名称冲突问题,让应用组织结构更加清晰
set 是集合 里面的值不允许相同
b=set(a) 使用set,可以快速的完成对list中的元素去重复的功能
给程序传参数
import sys
print(sys.argv)
sys.argv[]说白了就是一个从程序外部获取参数的桥梁,这个“外部”很关键,所以那些试图从代码来说明它作用的解释一直没看明白。因为我们从外部取得的参数可以是多个,所以获得的是一个列表(list),也就是说sys.argv其实可以看作是一个列表,所以才能用[]提取其中的元素。其第一个元素是程序本身,随后才依次是外部给予的参数。
sys.argv[ ]其实就是一个列表,里边的项为用户输入的参数,关键就是要明白这参数是从程序外部输入的,而非代码本身的什么地方,要想看到它的效果就应该将程序保存了,从外部来运行程序并给出参数。
列表推导式: 所谓的列表推导式,就是指的轻量级循环创建列表
a=[x for x in range(1,11)] 生成一个1-10的列表
a=[x for x in range(1,11) if x%2==0 ] 生成一个1-10 偶数的列表
a=[(x,y) for x in range(1,4) for y in range(1,3) ] 生成 [(1, 1), (1, 2), (2, 1), (2, 2), (3, 1), (3, 2)] 的列表
字典推导式 (更换key value值)
mcase = {'a': 10, 'b': 34}
mcase_frequency = {v: k for k, v in mcase.items()}
print mcase_frequency
# Output: {10: 'a', 34: 'b'}