1.面向对象三大特性:封装、继承、多态
<1>封装:
将属性和方法放到一起(类里面)做为一个整体,使用方法封装功能实现的具体步骤,然后通过实例化对象来访问属性和方法
隐藏内部实现细节,只需要和对象及其属性和方法交互就可以了;
对类的属性和方法增加 访问权限控制。
<2>继承:
子类需要使用父类的功能,如果父类的方法不能满足子类的需要还可以重写
<3>多态:
无参数函数 -> 有参数函数 -> 提高无参数函数的复用性
有参数函数 -> 多态设计模式 -> 提高有参数函数的复用性
所谓多态:定义时的类型和运行时的类型不一样,此时就称为多态 ,
同一个方法不同对象调用会出现不同的表现形式
多态的概念是应用于Java和C#(只能传指定类型的对象或者其子类的对象)这一类强类型语言中,而Python崇尚“鸭子类型”。
鸭子类型:虽然我想要一只"鸭子",但是你给了我一只鸟。 但是只要这只鸟走路像鸭子,叫起来像鸭子,游泳也像鸭子,我就认为这是鸭子。
Python的多态,就是弱化类型,重点在于对象参数是否有指定的属性和方法,如果有
就认定合适,而不关心对象的类型是否相同,同一个方法不同对象调用会出现不同的表现形式
总结:
多态中看的是函数和方法的形参(定义时的类型和运行时类型不同)
不同的对象做相同的事情有不同的结果
2.私有权限:
(1)_xxx "单下划线 " 开始的成员变量叫做保护变量,意思是只有类对象(即类实例)和子类对象自己能访问到这些变量,需通过类提供的接口进行访问;不能用'from module import *'导入
(2)__xxx 类中的私有变量/方法名 (Python的函数也是对象,所以成员方法称为成员变量也行得通。)," 双下划线 " 开始的是私有成员,意思是只有类对象自己能访问,连子类对象也不能访问到这个数据。
(3)__xxx__ 系统定义名字,前后均有一个“双下划线” 代表python里特殊方法专用的标识,叫做魔法方法,如 __init__() 代表类的构造函数。
1):单下划线_开头:只是告诉别人这是私有属性,外部依然可以访问更改
2):双下划线__开头:外部不可通过instancename.propertyname来访问或者更改,实际将其转化为了_classname__propertyname
<1>格式:在属性名和方法名 前面 加上两个下划线 __
类的私有属性 和 私有方法,都不能通过这个类创建的对象直接访问,但是可以在本类内部通过self访问和修改;
类的私有属性 和 私有方法,都不会被子类继承,子类也无法访问;
私有属性 和 私有方法 往往用来处理类的内部事情,不通过对象处理,起到安全作用。
总结:
私有属性和方法 只能在类的内部使用 不能再类的外部使用
Python中没有像C++中 public 和 private 这些关键字来区别公有属性和私有属性。
Python是以属性命名方式来区分,如果在属性和方法名前面加了2个下划线'__',则表明该属性和方法是私有权限,否则为公有权限
扩展:
在python中,只是对私有属性和私有方法名进行了伪装,改成了其他名字而已,一般是原来的名字前加了_类名
查看一个类或者对象都有那些属性和方法(包括私有属性和私有方法)
list = dir(类名或对象名) # 列表类型
查看一个类或者对象都有那些属性(包括私有属性)
list = 类名或对象名.__dict__ # 列表类型
<2>修改私有属性的值
如果需要修改一个对象的属性值,通常有2种方法
a. 对象名.属性名 = 数据 ----> 直接修改(不是修改了私有属性,而是添加了一个新的对象属性)
b. 对象名.方法名() ----> 间接修改
私有属性不能直接访问,所以无法通过第一种方式修改,一般的通过第二种方式修改
现代软件开发中,通常会定义get_xxx()方法和set_xxx()方法来获取和修改私有属性值
a. 对象可以通过访问公有方法来修改私有属性的值
对象.set_xxx(参数)
b. 对象可以通过访问公有方法来获取私有属性的值
print(对象.get_xxx())
3.类属性和实例属性
实例属性(对象属性): 描述一个对象的特征,在__init__方法中定义的属性
实例属性只能实例访问和修改,不能用类
类属性:描述一个类特征和通过这个类创建出来的所有对象的特征,定义在类里面、方法的外面,类属性就是类对象所拥有的属性,它被所有类对象的实例对象所共有,在内存中只存在一个副本,这个和C++中类的静态成员变量有点类似。
类属性分为私有类属性和公有类属性
公有的类属性:在类外可以通过类对象和实例对象访问
只能通过类对类属性修改和赋值,不能通过对象对类属性修改和赋值
类属性的取值
■ 类名.类属性名
■ 对象名.类属性名
类属性的赋值
■ 类名.类属性名 = 数值
■ 不能通过实例(对象)(对象名.类属性名= 数值)给类属性赋值,相当于在类的外部通过对象名给对象添加了一个与类属性名相同的实例属性
私有的类属性:不能在类外通过类对象实例对象访问
总结:
如果需要在类外修改类属性,必须通过类对象去引用然后进行修改。如果通过实例对象去引用,会产生一个同名的实例属性,这种方式修改的是实例属性,不会影响到类属性,并且之后如果通过实例对象去引用该名称的属性,实例属性会强制屏蔽掉类属性,即引用的是实例属性,除非删除了该实例属性。
4. 类方法和静态方法
<1>类方法
是类对象所拥有的方法,需要用修饰器@classmethod来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls(当前类)作为第一个参数(当然可以用其他名称的变量作为其第一个参数,但是大部分人都习惯以'cls'作为第一个参数的名字,就最好用'cls'了),能够通过实例对象和类对象去访问。
定义类方法的目的就是通过类方法可以访问修改类属性
一般类方法也就是配合类属性(私有)使用 进行取值和赋值
实例(对象)方法的调用方式
对象名.实例方法名()
类名.实例方法名(对象名)
类也可以调用对象方法,但是需要传入对象参数
类方法的调用方式
类名.类方法名()
对象名.类方法名()
# 重新赋值
@classmethod
def get_country(cls):
return cls.__country
# 重新赋值
@classmethod
def set_country(cls, new_country):
cls.__country = new_country
通过对象获取对象的类
ret = 对象名.__class__
print(ret)
<2> 静态方法
需要通过修饰器@staticmethod来进行修饰,静态方法不需要对象方法里的self参数也不需要类方法里的cls参数,可以通过对象和类来访问,可以把静态方法通俗理解为把函数放在类里面。
注意:
静态方法不能使用self对象,不能修改对象属性。可以访问和修改类属性
静态方法的调用
01: 类名.静态方法名()
Person.hello()
02: 对象名.静态方法名()
Person().hello()
总结
类方法:使用@classmethod关键字修改的方法就是类方法,类方法只能修改类属性
对象方法:在方法的参数里面如果有self对象参数那么可以认为是对象方法,对象方法可以修改对象属性和类属性
静态方法:使用@staticmethod关键字修饰,在方法的参数的里面不需要使用self和cls参数就可以称为是静态方法,静态方法可以修改类属性。
1. 从类方法和实例方法以及静态方法的定义形式就可以看出来,类方法的第一个参数是类对象cls,那么通过cls引用的必定是类对象的属性和方法;
2. 实例方法的第一个参数是实例对象self,那么通过self引用的可能是类属性、也有可能是实例属性(这个需要具体分析),不过在存在相同名称的类属性和实例属性的情况下,实例属性优先级更高。
3. 静态方法中不需要额外定义参数,因此在静态方法中引用类属性的话,必须通过类实例对象来引用
5. __new__方法
__new__(cls, *args, **kwargs)监听对象创建并返回
__init__(self)监听对象创建成功后 给对象添加属性并赋值
__str__(self)监听对象的属性值变化
__del__(self)监听内存地址的引用计数为0(监听对象销毁的)
总结
__new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供
__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例
__init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值
我们可以将类比作制造商,__new__方法就是前期的原材料购买环节,__init__方法就是在有原材料的基础上,加工,初始化商品环节
6.单例模式
<1> 单例是什么
确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,单例模式是一种对象创建型模式。
单例模式: 自定义一个类 通过这个类创建出来的对象 地址都是一样的,单例可以完成不同模块之间的数据的共享
<2> 创建单例-保证只有1个对象切属性只初始化一次
定义变量或者属性 不想开辟内存 可以使用空值None类型(节约内存)
7.time模块
import time
接收当前时间 t = time.time() 或 t = time.ctime()
程序在此处暂停s秒 time.sleep(s)
在Python中,与时间处理有关的模块就包括:time,datetime以及calendar。
在开始之前,首先要说明这几点:
1. 在Python中,通常有这几种方式来表示时间:1)时间戳 2)格式化的时间字符串 3)元组(struct_time)共九个元素。由于Python的time模块实现主要调用C库,所以各个平台可能有所不同。
2. UTC(Coordinated Universal Time,世界协调时)亦即格林威治天文时间,世界标准时间。在中国为UTC+8。DST(Daylight Saving Time)即夏令时。
3. 时间戳(timestamp)的方式:通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。我们运行“type(time.time())”,返回的是float类型。返回时间戳方式的函数主要有time(),clock()等。
4. 元组(struct_time)方式:struct_time元组共有9个元素,返回struct_time的函数主要有gmtime(),localtime(),strptime()。下面列出这种方式元组中的几个元素:
索引(Index) 属性(Attribute) 值(Values)
0 tm_year(年) 比如2011
1 tm_mon(月) 1 - 12
2 tm_mday(日) 1 - 31
3 tm_hour(时) 0 - 23
4 tm_min(分) 0 - 59
5 tm_sec(秒) 0 - 61
6 tm_wday(weekday) 0 - 6(0表示周日)
7 tm_yday(一年中的第几天) 1 - 366
8 tm_isdst(是否是夏令时) 默认为-1
接着介绍time模块中常用的几个函数:
1)time.localtime([secs]):将一个时间戳转换为当前时区的struct_time。secs参数未提供,则以当前时间为准。
>>> time.localtime()
time.struct_time(tm_year=2011, tm_mon=5, tm_mday=5, tm_hour=14, tm_min=14, tm_sec=50, tm_wday=3, tm_yday=125, tm_isdst=0)
>>> time.localtime(1304575584.1361799)
time.struct_time(tm_year=2011, tm_mon=5, tm_mday=5, tm_hour=14, tm_min=6, tm_sec=24, tm_wday=3, tm_yday=125, tm_isdst=0)
2)time.gmtime([secs]):和localtime()方法类似,gmtime()方法是将一个时间戳转换为UTC时区(0时区)的struct_time。
>>>time.gmtime()
time.struct_time(tm_year=2011, tm_mon=5, tm_mday=5, tm_hour=6, tm_min=19, tm_sec=48, tm_wday=3, tm_yday=125, tm_isdst=0)
注意:这里的tm_wday=3表示的是周几,但是要在这个返回值的基础上往后推一天,即表示的是周四,而不是周三。
3)time.time():返回当前时间的时间戳。
>>> time.time()
1304575584.1361799
4)time.mktime(t):将一个struct_time转化为时间戳。
>>> time.mktime(time.localtime())
1304576839.0
5)time.sleep(secs):线程推迟指定的时间运行。单位为秒。
6)time.clock():这个需要注意,在不同的系统上含义不同。在UNIX系统上,它返回的是“进程时间”,它是用秒表示的浮点数(时间戳)。而在WINDOWS中,第一次调用,返回的是进程运行的实际时间。而第二次之后的调用是自第一次调用以后到现在的运行时间。(实际上是以WIN32上QueryPerformanceCounter()为基础,它比毫秒表示更为精确)
1. import time
2. if __name__ == '__main__':
3. time.sleep(1)
4. print "clock1:%s" % time.clock()
5. time.sleep(1)
6. print "clock2:%s" % time.clock()
7. time.sleep(1)
8. print "clock3:%s" % time.clock()
clock1:3.35238137808e-006 运行结果:
clock2:1.00004944763
clock3:2.00012040636
其中第一个clock()输出的是程序运行时间
第二、三个clock()输出的都是与第一个clock的时间间隔
7)time.asctime([t]):把一个表示时间的元组或者struct_time表示为这种形式:'Sun Jun 20 23:21:05 1993'。如果没有参数,将会将time.localtime()作为参数传入。
>>> time.asctime()
'Thu May 5 14:55:43 2011'
8)time.ctime([secs]):把一个时间戳(按秒计算的浮点数)转化为time.asctime()的形式。如果参数未给或者为None的时候,将会默认time.time()为参数。它的作用相当于time.asctime(time.localtime(secs))。
>>> time.ctime()
'Thu May 5 14:58:09 2011'
>>> time.ctime(time.time())
'Thu May 5 14:58:39 2011'
>>> time.ctime(1304579615)
'Thu May 5 15:13:35 2011'
9)time.strftime(format[, t]):把一个代表时间的元组或者struct_time(如由time.localtime()和time.gmtime()返回)转化为格式化的时间字符串。如果t未指定,将传入time.localtime()。如果元组中任何一个元素越界,ValueError的错误将会被抛出。
格式 含义 备注
%a 本地(locale)简化星期名称
%A 本地完整星期名称
%b 本地简化月份名称
%B 本地完整月份名称
%c 本地相应的日期和时间表示
%d 一个月中的第几天(01 - 31)
%H 一天中的第几个小时(24小时制,00 - 23)
%I 第几个小时(12小时制,01 - 12)
%j 一年中的第几天(001 - 366)
%m 月份(01 - 12)
%M 分钟数(00 - 59)
%p 本地am或者pm的相应符 一
%S 秒(01 - 61) 二
%U 一年中的星期数。(00 - 53星期天是一个星期的开始。)第一个星期天之前的所有天数都放在第0周。 三
%w 一个星期中的第几天(0 - 6,0是星期天) 三
%W 和%U基本相同,不同的是%W以星期一为一个星期的开始。
%x 本地相应日期
%X 本地相应时间
%y 去掉世纪的年份(00 - 99)
%Y 完整的年份
%Z 时区的名字(如果不存在为空字符)
%% ‘%’字符
备注:
1. “%p”只有与“%I”配合使用才有效果。
2. 文档中强调确实是0 - 61,而不是59,闰年秒占两秒(汗一个)。
3. 当使用strptime()函数时,只有当在这年中的周数和天数被确定的时候%U和%W才会被计算。
举个例子:
>>> time.strftime("%Y-%m-%d %X", time.localtime())
'2011-05-05 16:37:06'
10)time.strptime(string[, format]):把一个格式化时间字符串转化为struct_time。实际上它和strftime()是逆操作。
>>> time.strptime('2011-05-05 16:37:06', '%Y-%m-%d %X')
time.struct_time(tm_year=2011, tm_mon=5, tm_mday=5, tm_hour=16, tm_min=37, tm_sec=6, tm_wday=3, tm_yday=125, tm_isdst=-1)
在这个函数中,format默认为:"%a %b %d %H:%M:%S %Y"。
最后,我们来对time模块进行一个总结。根据之前描述,在Python中共有三种表达方式:1)timestamp 2)tuple或者struct_time 3)格式化字符串。
它们之间的转化如图所示: