内容目录:
- 面向对象三大特性之多态性
- 面向对象中的成员:字段、方法、属性
- 类的成员修饰符
- 类的特殊成员
- 特殊成员方法
- 面向对象其他
- 异常处理
- 设计模式之单例模式
面向对象的多态性
多态性:即指多种形态多种类型
比如在函数中可以定义def func(arg),arg可以为为整型,可以为字符串可以为字典可以为列表等等多种类型,这就是面向对象的多态性。
#python中
def func(arg):
print(arg)
func(1)
func('jabe')
func([11,22,33]) #python 中参数可以为整型,字符串,列表等即为面向对象的多态 # c#/java中
def func1(int arg): #c#/java 中定义参数时需要指定该参数类型
print(arg)
func1(123)
func1('123') #报错 class A:
pass
class B(A):
pass
class C(A):
pass
def func(A arg): #arg的参数必须是A类型或者A类的子类
pass
面向对象的成员
- 字段:包括静态字段和普通字段
- 方法:包括静态方法和普通方法
- 属性:静态属性
一、字段
字段分为静态字段和普通字段,主要区别在于两者在内存中存在位置不同,静态字段存在类中,类创建完静态字段就已经生成,而普通字段存在于对象中,只有进行实例化之后才能生成普通的字段存入内存中,创建类时候普通字段是不占用内存的。
class Province:
#静态字段
country = '中国' def __init__(self,name):
#普通字段
self.name = name #普通字段直接访问方式,通过对象来访问普通字段
obj = Province('河北省')
print(obj.name)
#静态字段访问方式,直接通过类调用方式访问
print(Province.country)
ps:静态字段一般用类访问,对象方式也可以访问但是不推荐用对象方式访问。
静态字段在内存中只保存一份数据,普通字段在每个对象中都要保存一份;通过类创建对象时,如果每个对象都具有相同的字段那么就使用静态字段
二、方法
方法分为普通方法、静态方法和类方法,所有的方法均属于类,在内存中也是只保存一份,区别在于调用方式不同,各种方式调用传入的参数不同。
普通方法:至少有一个self,由对象调用执行;
静态方法:由类调用执行,可以添加任意参数;
类方法:至少一个cls参数,由类调用执行;
class Province:
country = '中国' #静态字段
def __init__(self,name):
self.name = name #普通字段
print(self.name)
#普通方法
def show(self,name):
#print(self.name)
print(123) #静态方法
@staticmethod
def f1(arg1,arg2):
print(arg1,arg2)
#类方法
@classmethod
def f2(cls):
print(cls) Province.f1(111,222) #静态方法调用
Province.f2() #类方法调用 返回当前的类名 <class '__main__.Province'>
obj = Province('河北')
obj.show('河北') #普通方法调用
三、属性
属性即为特殊的普通方法,方法和字段结合体,方法的定义方式,字段的调用方式。
定义方式:
1 在普通方法的基础上添加 @property 装饰器;
2 属性仅有一个self参数
3 调用时无需括号,方法:obj.func() 属性:obj.func
基本使用
class Pager:
def __init__(self,all_count):
self.all_count = all_count #属性的定义
@property
def all_pager(self):
a1,a2 = divmod(self.all_count,10)
if a2 == 0:
return a1
else:
return a1+1
#属性的设置
@all_pager.setter
def all_pager(self,value):
print(value) #属性的删除
@all_pager.deleter
def all_pager(self):
print('del all_pager') p = Pager(101)
# p.all_count #字段
# ret = p.all_pager #属性的调用,比一般的方法调用少了括号
# print(ret)
p.all_pager = 11 #属性的setter,可以直接赋值方式,调用@all_pager.setter方法
del p.all_pager #属性的删除 调用@all_pager.deleter 方法
属性的另一种定义方式
class Pager:
def __init__(self,all_count):
self.all_count = all_count def f1(self):
return 123
def f2(self,value):
pass
def f3(self):
pass
foo = property(fget=f1,fset=f2,fdel=f3) #直接将f1,f2,f3代入到属性指定关键字中 p = Pager(101)
resault = p.foo #自动调用fget的方法
print(resault) p.foo = 'jabe' #fset f2的方法 del p.foo #自动调用fdel的方法
类的成员修饰符
类的成员我们可以从上面知道包括字段、方法和属性,对于每一个类的成员来说都有两种形式:
公有成员:在任何地方都能访问,即类的内部和外部都能访问;
私有成员:只能在类的内部访问;
公有成员和私有成员主要区别在于私有成员命名时前面两个字符是下划线(特殊成员例外__init__,__doc__,__dict__,__call__等)
私有字段成都使用
class Foo:
__cc = '123' #私有静态字段定义 def __init__(self,name):
self.__name = name #私有普通字段定义
def f1(self):
print(self.__name) #私有字段内部调用 def f3(self):
print(Foo.__cc) #私有静态字段内部调用 class Bar(Foo):
def f2(self):
print(self.__name) # obj = Foo('jabe')
# obj.f1()
# obj.f2() #继承方式不能访问私有字段 #print(Foo.__cc) #私有静态字段直接在类外不能调用
obj = Foo('jabe')
obj.f3()
私有方法使用
class Foo: def __init__(self,name):
self.name = name
def __f1(self): #私有 普通方法
print(self.name) def f3(self):
self.__f1() #私有普通方法调用
self.__f4('jabe') #私有静态方法调用 @staticmethod
def __f4(arg1): #私有静态方法
print(arg1) obj = Foo('jabe') obj.f3() #外部调用私有方法方式
类的特殊成员方法
在python中包含一些特殊的成员,也是以双下划线开头,同时以双下划线结尾的方法或者字段
__doc__:显示程序中的注释信息
class A:
'''
__dic__ 是注释
'''
pass obj = A()
print(obj.__doc__) #输出 __dic__ 是注释
__del__:析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
class Foo: def __del__(self):
pass
__init__:构造方法通过类创建对象时,自动触发执行。
class Foo:
#构造方法
def __init__(self,name,age):
self.name = name
self.age = age
__call__:对象后面加()执行__call__方法
class Foo:
def __call__(self):
print('call fangfa') obj = Foo()
obj() #obj() #直接对象+()调用call方法
__dict__:类或对象中的所有成员
class Province: country = 'China' def __init__(self, name, count):
self.name = name
self.count = count def func(self, *args, **kwargs):
print ('func') # 获取类的成员,即:静态字段、方法、
print(Province.__dict__)
# 输出:{'__doc__': None, '__weakref__': <attribute '__weakref__' of 'Province' objects>,
# 'func': <function Province.func at 0x00000013984416A8>, '__dict__':
# <attribute '__dict__' of 'Province' objects>, 'country':
# 'China', '__init__': <function Province.__init__ at 0x0000001398441620>,
# '__module__': '__main__'}
obj1 = Province('HeBei',10000)
print(obj1.__dict__)
# 获取 对象obj1 的成员
# 输出:{'count': 10000, 'name': 'HeBei'} obj2 = Province('HeNan', 3888)
print(obj2.__dict__)
# 获取 对象obj2 的成员
# 输出:{'count': 3888, 'name': 'HeNan'}
__str__:如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。
class Foo: def __str__(self):
return 'jabe' obj = Foo()
print(obj)
# 输出:jabe
__getitem__、__setitem__、__delitem__:用于索引操作,例如字典。三个方法分别表示获取设置删除数据
class Foo:
def __getitem__(self, item):
print(item,type(item))
print(item.start)
print(item.stop)
print(item.step)
return 123
def __setitem__(self, key, value):
print(type(key),type(value))
print('setitem')
def __delitem__(self, key):
print(type(key))
print('del item') obj = Foo('jabe',23)
# print(obj['ad']) #对象+[] 调用__getitem__方法
# obj['k1'] = 'v1' #执行字典赋值操作时调用__setitem__方法
# del obj['k1'] #执行del调用__delitem__方法 obj[1:4:2] #slice(1, 4, None) <class 'slice'>
obj[1:4] = [11,22,33,44] #<class 'slice'> <class 'list'> setitem
del obj[1:4] #<class 'slice'> del item
__iter__:用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了 __iter__
#首先实例化一个对象,不能被循环报错如下
class Foo(object):
pass obj = Foo() for i in obj:
print(1) # 报错:TypeError: 'Foo' object is not iterable #定义了iter方法,但是返回值必须为可迭代的类型
def __iter__(self):
pass obj = Foo() for i in obj:
print(i) # 报错:TypeError: iter() returned non-iterator of type 'NoneType' #执行如下操作能正常执行
def __init__(self, sq):
self.sq = sq def __iter__(self):
return iter(self.sq) obj = Foo([11,22,33,44]) for i in obj:
print(i)
以上步骤可以看出,for循环迭代的其实是 iter([11,22,33,44]) ,所以执行流程可以变更为:
obj = iter([11,22,33,44]) for i in obj:
print(i)
for循环语法内部执行过程
obj = iter([11,22,33,44]) while True:
val = obj.next()
print val
面向对象其他
isinstance(obj,类)
判断对象是否是类的对象
class Foo(object):
pass obj = Foo() print(isinstance(obj, Foo))
issubclass(sub,super)
判断sub是否是super的子类
class Foo(object):
pass obj = Foo() class B(Foo):
pass print(issubclass(B, Foo))
有序字典
class Mydict(dict):
def __init__(self):
self.li = []
super(Mydict,self).__init__()
def __setitem__(self, key, value):
self.li.append(key)
super(Mydict,self).__setitem__(key,value) #主动执行父类的__setitem__方法 def __str__(self):
temp_list = []
for key in self.li:
value = self.get(key)
temp_list.append("%s:%s"%(key,value,))
temp_str = "{" + ",".join(temp_list) +"}"
return temp_str obj = Mydict()
obj['k1'] = 123
obj['k2'] = 456
print(obj)
ps:默认执行类内的函数会寻找自己内部的f1函数,不会执行父类的方法,如果要执行父类的方法需要使用super方法
异常处理
异常结构
try:
pass #抓取异常的代码段
except ValueError as ex: #按顺序逐一抓取匹配ValueError
print(ex)
except Exception as ex: #如果ValueError没有抓取到,进行下次匹配Exception
print(ex)
else:
pass #都没有抓取到异常执行else下代码段
finally:
pass #无论是否异常,最终都执行该代码段
简单应用例子
while True:
num1 = input('num1:')
num2 = input('num2:')
try:
num1 = int(num1)
num2 = int(num2)
resault = num1 + num2
except Exception as ex:
print(ex) #错误输出字符串
异常种类
常用异常
AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x
IOError 输入/输出异常;基本上是无法打开文件
ImportError 无法引入模块或包;基本上是路径问题或名称错误
IndentationError 语法错误(的子类) ;代码没有正确对齐
IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
KeyError 试图访问字典里不存在的键
KeyboardInterrupt Ctrl+C被按下
NameError 使用一个还未被赋予对象的变量
SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了)
TypeError 传入对象类型与要求的不符合
UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,
导致你以为正在访问它
ValueError 传入一个调用者不期望的值,即使值的类型是正确的
其他异常
ArithmeticError
AssertionError
AttributeError
BaseException
BufferError
BytesWarning
DeprecationWarning
EnvironmentError
EOFError
Exception
FloatingPointError
FutureWarning
GeneratorExit
ImportError
ImportWarning
IndentationError
IndexError
IOError
KeyboardInterrupt
KeyError
LookupError
MemoryError
NameError
NotImplementedError
OSError
OverflowError
PendingDeprecationWarning
ReferenceError
RuntimeError
RuntimeWarning
StandardError
StopIteration
SyntaxError
SyntaxWarning
SystemError
SystemExit
TabError
TypeError
UnboundLocalError
UnicodeDecodeError
UnicodeEncodeError
UnicodeError
UnicodeTranslateError
UnicodeWarning
UserWarning
ValueError
Warning
ZeroDivisionError
IndexError
dic = ["k1", 'jabe']
try:
dic[10]
except IndexError as e:
print(e)
KeyError
dic = {'k1':'v1'}
try:
dic['k20']
except KeyError, e:
print e
ValueError
s1 = 'hello'
try:
int(s1)
except ValueError, e:
print e
在python中存在一个万能异常,当列举的异常都未匹配时可以用这个万能异常匹配即Exception
s1 = 'hello'
try:
int(s1)
except Exception,e:
print e
接下来你可能要问了,既然有这个万能异常,其他异常是不是就可以忽略了!
答:当然不是,对于特殊处理或提醒的异常需要先定义,最后定义Exception来确保程序正常运行。
s1 = 'hello'
try:
int(s1)
except KeyError,e:
print '键错误'
except IndexError,e:
print '索引错误'
except Exception, e:
print '错误'
主动触发异常(raise)
try:
raise Exception('错误了。。。')
except Exception,e:
print e
自定义异常
class WupeiqiException(Exception): def __init__(self, msg):
self.message = msg def __str__(self):
return self.message try:
raise WupeiqiException('我的异常')
except WupeiqiException,e:
print e
断言
# assert 条件 assert 1 == 1 assert 1 == 2
设计模式之单例模式
在实际应用中或许会有这样的情况,调用很多功能一样的对象,每创建一个对象则占用一个内存,这样大量请求时候可能会占满内存
单例模式用来保证内存中仅存在一个实例
通过面向对象的特性,构造出单例模式:
# ########### 单例类定义 ###########
class Foo(object): __instance = None @staticmethod
def singleton():
if Foo.__instance:
return Foo.__instance
else:
Foo.__instance = Foo()
return Foo.__instance # ########### 获取实例 ###########
obj = Foo.singleton()
对于Python单例模式,创建对象时不能再直接使用:obj = Foo(),而应该调用特殊的方法:obj = Foo.singleton() 。
应用
class Foo:
instance = None def __init__(self,name):
self.name = name @classmethod
def get_instance(cls):
#cls类名
if cls.instance: #判断类中是否存在实例,存在的话直接返回
return cls.instance
else:
obj = cls('jabe') #不存在则进行初始化
cls.instance = obj obj1 = Foo.get_instance()
print(obj1)
obj2 = Foo.get_instance()
print(obj2)