- 类和实例
- 访问限制
- 继承和多态以及多重继承
- 获取对象信息
- 实例属性和类属性
- 模块和包
类:用来描述具有相同属性和方法的对象的集合。定义了该集合中每个对象所共有的属性和方法,对象是类的实例
对象:通过类定义的数据结构的实例,对象包括两个数据成员(类变量和实例变量)和方法
类变量:类变量在整个实例化的过程中是公用的。定义在类中且在函数体之外。类变量通常不作为实例变量使用
实例变量:定义在方法中的变量,只作用于当前实例的类。
class Foo:
# 这里的变量name就是类变量,定义在类中且在函数体之外
name = 'xiao'
def bar(self):
print('Bar')
# self作为指代,指代了自己所在的class
def hello(self, name):
print('you are %s' %self.name)
print('i am %s' %name)
print('\n')
obj1 = Foo()
obj2 = Foo()
obj1.hello('August')
obj2.hello('july')
you are xiao
i am August
you are xiao
i am july
self:就是个指代,指代自己所在的class。
self就是一个代词,可以使用其他的代词替代,但是这个代词必须是这个类的所有子方法的第一个参数。
关于这变量,那变量,下面板块会好好分析。
构造函数 __init__(self)
构造函数是一种特殊的方法,主要用它来创建对象的时候初始化对象。模型创建初期就完成一些动作-----为对象中的成员变量赋初始值。
class Province(object):
# 构造函数
def __init__(self, name, captial, leader):
self.Name = name
self.Captial = captial
self.Leader = leader
hebei = Province('河北', '石家庄', 'XXX')
shanddong = Province('山东', '济南', '肖震')
what is self?
你瞅瞅上面的__init__函数,里面是不是有4个参数,但是你创建类的对象的时候是不是只传了3?self咋不传呢?
其实啊,self已经传了,Python帮你传的,self传的就是对象hebei
self其实就是指代,指代这个类所创建的对象!!!
所以说,这里的hebei就是__init__中的self,反之也成立。
析构函数 __del__(self)
对象创建了,你得销毁掉吧!
这里所说的销毁并不是指自己销毁内存,销毁内存是Python解释器干的事,具体见我的其他博客。
析构函数是这样的,解释器不是有销毁动作嘛,如果你想让解释器销毁的时候干点什么,就写到析构函数里面。
class Foo:
def __init__(self):
pass
def __del__(self):
print('Python解释器要销毁我(这里的我是指对象)了,我要做最后的挣扎!!!')
# 解释器通知一声(就是执行析构函数),然后就真的把对象销毁了。
类和对象
访问限制
1. 静态字段:也就是上面所说的类变量:属于类
2. 动态字段:也就是上面所说的实例变量:属于对象
Note:
别乱!属于类的变量就用 类名. 调用
属于对象的变量就用 对象. 调用
class Province(object):
# 静态字段,也就是类变量
memo = '中国的23个省之一'
def __init__(self, name, captial, leader):
# 动态字段
self.name = name
self.captial = captial
self.leader = leader
shandong = Province('山东', '济南', 'yyy')
print shandong.captial # captial属于对象,就用 对象. 调用
print Province.memo # memo属于类,就用类名. 调用
其实,对象也能调用静态字段,也就是说shandong.memo也可以,但是避免这样使用,别乱!
3. 动态方法:属于对象,类里面定义的方法,是供给对象使用的
思考一下,类能访问动态方法???
哈哈哈,NO WAY,假如用类名访问了动态方法,方法的返回是谁,是山东,是河北?self指代的是谁都不知道,Name也不知道
class Province(object):
# 静态字段
memo = '中国的23个省之一'
def __init__(self, name, captial, leader):
# 动态字段
self.Name = name
self.Captial = captial
self.Leader = leader
# 动态方法,类不能访问-----需要实例化
def sport_meet(self):
print self.Name + '正在开运动会'
hebei = Province('河北', '石家庄', 'XXX')
shandong = Province('山东', '济南', '肖震')
shandong.sport_meet() # >>> 山东正在开运动会
4. 静态方法:属于类
将一个方法变成静态方法的步骤是:
- 在动态方法上面加上装饰器@staticmethod
- 去掉self,因为self指代的是对象,类访问不了self(对象)的东西。
class Province(object):
# 静态字段
memo = '中国的23个省之一'
def __init__(self, name, captial, leader):
# 动态字段
self.Name = name
self.Captial = captial
self.Leader = leader
# 动态方法
def sport_meet(self):
print self.Name + '正在开运动会'
# 静态方法
1. 加上装饰器
@staticmethod
def anti_corruption(): 2. 去掉了self,self代表对象,类访问不了对象的东西
print '每个省都要带头反腐'
hebei = Province('河北', '石家庄', 'XXX')
shandong = Province('山东', '济南', '肖震') 这俩都是对象,只能访问动态方法!
Province.anti_corruption() >>> 每个省都要带头反腐 这里用的是类.访问的
5. @property 方法的访问形式 变成 字段的访问形式
在绑定属性的时候,我们如果直接将属性暴露出去,虽然写起来很简单,但是没有办法检验参数,导致了对象可以任意修改属性的值,如:
s = Student()
s.score = 9999
这一定不行的啦,我们可以通过一个set_score()方法来设置成绩(还记得get set方法吗?),主要进行范围限制!
然后再通过get_score(),这样对象就能获得属性,又不至于随便修改属性了。(使用get、set方法来访问属性,是不是有点麻烦)
class Student(object):
# 通过get方法获取属性
def get_score(self):
return self._score
# 通过set方法设置属性
def set_score(self, value):
if not isinstance(value, int):
aise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
你想随便搞事情,那是不可能的啦~
>>> s = Student()
>>> s.set_score(60) # 正常设置 ok!
>>> s.get_score() # 获得属性 ok!
60
>>> s.set_score(9999) # 乱搞!
Traceback (most recent call last):
...
你是否感觉到 这 有点 麻烦 呢?
有没有既能检查参数,又可以用类似属性这样简单的方式来访问变量呢
别忘了!!!你上面的那两个都是方法啊,你的目的是访问属性啊----我们找的类似访问属性一样的方式
福利来了----Python内置@property装饰器就负责把一个方法 变成 属性 调用的!
class Student(object):
@property
def score(self):
# 这里其实就是get方法的功能
return self._score
@score.setter
def score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer')
if value < 0 or value > 100:
raise ValueError('score must be 0~100')
self._score = value
@perproty 将一个getter方法变成属性只需要加上@perproty
本身,@perproty又创建了另外一个装饰器@score.setter,负责把一个setter方法变成属性 赋值
这样,我们就有了一个可以控制的属性控件了!
>>> s = Student()
>>> s.score = 60 # 实际转化为s.set_score(60)
>>> s.score # 实际转化为s.get_score()
60
>>> s.score = 9999
Traceback (most recent call last):
...
ValueError: score must between 0 ~ 100!
是不是只需要调用score这个属性就好了,改也是一样,这显得多方便!
@perproty 我们在对实例属性进行操作的时候,就知道该属性很有可能不是直接暴露的。而是通过getter和setter方法实现的。
同样,我们还可以定义一个只读属性,也就是不加setter方法。
class Student(object):
@property
def birth(self):
return self._birth
@birth.setter
def birth(self, value):
self._birth = value
@property
def age(self):
return 2015 - self._birth
上面的birth是可读写属性,而age就是一个只读属性,因为age可以根据birth和当前时间计算出来。
@property广泛应用在类的定义中,可以让调用者写出简短的代码-----少了get和set方法
同时保证对参数进行必要的检查[email protected],这样,程序运行时就减少了出错的可能性
小结:
类里面三种结构:
字段(静态,动态字段),方法(静态,动态方法),特性(@property)
静态字段的作用:
# 以下显示静态字段的作用
class MsSqlHelper:
def add(self,sql):
pass
def delete(self,sql):
pass
def update(self,sql):
pass
def select(self,sql):
pass
下面针对每一个业务方,需要创建n多个对象,在内存中开辟n多个空间
ms = MsSqlHelper()
ms.update(sql)
下面静态字段发挥作用了
class MsSqlHelper:
@staticmethod
def add(sql): # 注意,不需要self了
pass
@staticmethod
def delete(sql):
pass
@staticmethod
def update(sql):
pass
@staticmethod
def select(sql):
pass
下面我们要使用相关的方法,就可以根据每一个业务就可以直接使用类.去调用方法,就不用创建那么多对象
来一个吊的问题:
python中类的静态方法的作用:通过不实例化类就可以调用类中的方法
问题来了:!!!
我们不实例化类就直接调用类中的方法 和 我直接调用模块.函数名 有什么区别呢?
在内存里是没有区别的!
在类中直接使用@staticmethod字段使得一个方法变成静态方法 在逻辑上是属于这个类的
但是其他的跟外面都是一样的,也就是说,类的静态方法和外面的方法是一样的,只是给了这个方法一个从属关系,它是属于这个类的
鸡肋?
官方解释来了
高手在设计语言的时候,不会做无用功,或者是很少做无用功
1 为什么模块有了这个方法之后 又要设计出来静态的这个方法,他们的价值是一样的啊?
python在最初设计的时候,是模块化编程的思想,其实并不支持面向对象
只要我定义好模块,我想用哪一种方法,在我使用的时候调用这个模块就行了
所以说python最初是没有静态这个概念的
2 静态这个概念是怎么产生的呢?
我在进行面向对象编程的时候,面向对象编程是从java中提出的
在用java的时候你会发现,在用面向对象的时候必须要new出来东西,也就是要把对象构造出来,才能用里面的方法,但是一构造,就会在内存的堆里面开辟空间,内存里面有堆有栈什么的,堆里面就会有一块区域专门用来装这些东西,如果没有静态方法,100个对象在要用数据库的时候,我们就要构造100个方法,这是在面向对象编程中没法避免的问题,所以java设计出来叫做静态的东西,静态的东西在内存中只保存一份,当我们在调用静态方法的时候,就只会在那个专门的区域中找,不会给它单独开辟一块区域,所以,静态是专门应对面向对象编程产生的东西
3 python为什么有了模块化编程之后又有了这个静态呢?
是因为python想支持面向对象编程,于是乎python又把面向对象的所有的东西拿过来又做了一次
具体你选择用什么东西,这要看你的个人选择,为什么这个问题会产生?
因为这是一个历史遗留问题,这是两种编程思想的碰撞。。。
4. 模块化编程和面向对象编程两种思想的区别?
面向对象是灵活性的考虑,能够避免重复的代码, 多态是面向对象存在并且比模块化编程的最大优势所在
因为类这个东西嘛,和模块形式上差不多的,在编程的时候,你很难在开始的时候就知道要写什么什么类,都是在编程的过程中,你觉得这几个方法应该放到一个类中,才会想着把他们变成一个类
python的模块式编程是非常强大的,也可以实现多态,java是强制性语言,在定义的时候你必须告诉我类型是什么
反射 + 模块化编程 == 面向对象编程 ?
但是用java的时候,就要选面向对象编程
面向对象更多考虑到可扩展性,在做一件事之前,就要考虑好整体的框架
面向函数式编程更像是一个莽夫,走一步写一步,高手来说,可能写的时候整体框架就有了,但是新手还是面向对象吧!
公有私有
私有字段就是__变量名(两个下划线) 可以让你看,但是你不能改,毕竟python的安全机制要差一点
class Province(object):
# 静态字段
memo = '中国的23个省之一'
def __init__(self, name, captial, leader, flag):
# 动态字段
self.name = name
self.captial = captial
self.leader = leader
# 私有字段
self.__Thailand = flag
# 动态字段
def show(self):
print(self.__Thailand)
def sport_meet(self):
print(self.name + '正在开运动会')
# 私有方法
def __xiao(self):
print('I am xiaozhen!')
def zhen(self):
self.__xiao()
# 静态字段
@staticmethod
def anti_corruption():
print('每个省都要带头反腐!')
- 直接用对象去访问私有字段是访问不到的,但是类通过自己的动态方法访问私有字段就可以访问得到
- 对象不能直接访问类的私有方法,通过类自己内部的方法可以访问私有方法
japan = Province('日本', '东京', '小泽', True)
print japan.__Thailand 报错 直接用对象去访问__.Thailand(私有字段)访问不到 直接不行
japan.show() True 但是通过类自己的动态方法去访问私有字段就可以访问得到 间接行
japan.__xiao() 报错 对象不能直接访问类的私有方法 直接不行
japan.zhen() I am xiaozhen 通过类自己内部的方法可以访问私有方法 间接行
上面是在变量或者方法前面加上双下划线,还有一种方法就是:
外部通过property来访问类中的私有字段!
class Province(object):
# 静态字段
memo = '中国的23个省之一'
def __init__(self, name, captial, leader, flag):
# 动态字段
self.Name = name
self.Captial = captial
self.Leader = leader
# 私有字段
self.__Thailand = flag
# 动态方法
def show(self):
print self.__Thailand
# 动态方法
def sport_meet(self):
print self.Name + '正在开运动会'
# 私有方法
def __xiao(self):
print 'I am xiaozhen'
def zhen(self):
self.__xiao()
# 静态方法
@staticmethod
def anti_corruption():
print '每个省都要带头反腐'
@property 这里像不像前面写的get方法,这里的私有字段就是只读了
def Thailand(self):
return self.__Thailand
---------------------------------------------------------------
japan = Province('日本', '东京', '小泽', True)
print japan.Thailand # >>> True
不过,如果想要修改私有字段咋办? 推荐下面的方法,其实也就是前面讲过的,property实现方法的访问形式变成字段的访问形式,这里不就是利用了类自己的动态方法来访问类的私有字段或者私有方法,然后利用类自己的动态方法来更改类的私有字段或者私有方法。
如下:
class Province(object): # 要先继承Object类,才能实现下面的可写@Thailand.setter
# 静态字段
memo = '中国的23个省之一'
def __init__(self, name, captial, leader, flag):
# 动态字段
self.Name = name
self.Captial = captial
self.Leader = leader
# 私有字段
self.__Thailand = flag
# 动态方法
def show(self):
print self.__Thailand
# 动态方法
def sport_meet(self):
print self.Name + '正在开运动会'
# 私有方法
def __xiao(self):
print 'I am xiaozhen'
def zhen(self):
self.__xiao()
# 静态方法
@staticmethod
def anti_corruption():
print '每个省都要带头反腐'
@property # 这里是可读 加上了装饰器@property,注意与前面加staticmethod的区别,一个是动态方法,一个是静态方法
def Thailand(self):
return self.__Thailand
@Thailand.setter # 这里是可改 注意写法:@Thailand.setter 删了这一段就是可读的
def Thailand(self, value):
self.__Thailand = value
---------------------------------------------------------------------------
japan = Province('日本', '东京', '小泽', True)
# property将方法的访问形式变成了属性的访问形式,可以在setter方法中增加判断或者说访问限制
print japan.Thailand
japan.Thailand = False
print japan.Thailand
>>>输出 True False
不知你是否注意,上面定义class Province(object): 是不是对了一个object,这是新式类的写法。
先继承object类,才能实现下面的可写@Thailand.setter
也就是说,继承了object类,写的话得用@函数名.setter
__call__:对象()直接执行
__call__就是一个函数,就是调用方式不一样而已,自己想什么时候用就什么时候用,对象加上()就会执行__call__方法,就像
import time
class Foo:
def __init__(self):
pass
def __del__(self):
print 'i am xigou function'
def go(self):
print 'let us go'
def __call__(self):
print 'CALL'
f1 = Foo()
f1.go() 对象.方法名调用方法
time.sleep(5) 程序在这里睡5s,下面还有对象的调用,所以就不能执行析构函数,析构函数一定是最后执行的,
f1() ****对象+括号就会执行__call__方法*****
输出如下:
let us go
# 睡了5s
CALL
i am xigou function