Posted by:
努力记

努力记,通过记录,计划,让自己的努力可以触碰彩虹!

11,477

Python面向对象

  • 2015-01-24
  • 暂无评论
Python类中定义的方法通常有三种:实例方法,类方法以及静态方法。
这三者之间的区别是
实例方法一般都以self作为第一个参数,必须和具体的对象实例进行绑定才能访问
类方法以cls作为第一个参数,cls表示类本身,定义时使用@classmethod
静态方法不需要默认的任何参数,跟一般的普通函数类似.定义的时候使用@staticmethod
实例方法很容易理解,但类方法和静态方法在不同的语言中实现是不同的
Python的静态方法和Java的是一致的:如果父类中定义有静态方法a(),在子类中没有覆盖该方法的话,Sub.a()仍然指的是父类的a()方法
类方法是另类的静态方法继承:如果a()是类方法的情况下,Sub.a()指向的是子类。
最终的区别就是类成员变量的作用域不同
直接定义在类体中的变量叫类变量,而在类的方法中定义的变量叫实例变量。
PHP在5.3中对于面向对象添加static关键词:
  • self::访问的的变量就是通过静态方法访问
  • static::访问的变量就是通过类方法访问
封装和访问控制
Python的访问控制相对简单,没有public,private,protected等属性
python认为用户在访问对象的属性的时候是明确自己在做什么的,因此认为私有数据不是必须的,但是如果你必须实现数据隐藏,也是可以的,具体方法就是在变量名前加双下划线。
    如:__privatedata=0,定义私有方法则是在方法名称前加上__下划线。但即使对于隐藏的数据,也是有一定的方法可以访问的。方法就是__className__attrName。
构造函数
Python的构造函数有两种,__init__和__new__
__init__的调用不会返回任何值,在继承关系中,为了保证父类实例正确的初始化,最好显示的调用父类的__init__方法。
与__init__不同,__new__实际是个类方法,以cls作为第一个参数。
#如果类中同时定义了__init__和__new__方法,则在创建对象的时候会优先使用__new__
class A(object):
    def __init__(self):
        print("in init")
    def __new__(self):
        print("in new")
A() #in new

#如果__new__需要返回对象,则会默认调用__init__方法。
class A(object):
    def __new__(cls):
        Object = super(A,cls).__new__(cls)
        print "in New"
        return Object
    def __init__(self):
        print "in init"
 
class B(A):
    def __init__(self):
        print "in B's init"
B()#in New in B's init


析构函数
Python的析构函数:__del__
由于具有垃圾回收机制,通常不需要用户显示的去调用析构函数,即使调用,实例也不会立即释放,而是到该实例对象所有的引用都被清除掉后才会执行。
专有属性
__class__ 当前实例所属类
__dict__ 类属性
__doc__ 用于描述该类的作用
__module__ 类所属的模块,在启动脚本中的类为__main__和脚本中判断__name__一致
运算符重载
__add__(self, object) 加运算 object + object
__sub__(self, object) 减法运算 object - object
__mul__(self, object)  乘运算 object * object
__cmp__(self, object) 比较运算,第2参数为比较对象,返回:0:等于 1:大于 -1:小于
__gt__(self, object) 判断是否大于other对象
__lt__(self, object) 判断是否小于other对象
__ge__(self, object) 判断是否大于或者等于other对象
__le__(self, object) 判断是否小于或者等于other对象
__eq__(self, object)  判断是否等于other对象
__or__(self, object) object | object
__radd__(self, object)Right-side +   +object ,如果前一个对象没有重载__add__则查询后一个对象的__radd__
__iadd__(self, object) +=    object+=object
__iter__(self, index) 迭代  for in
专有方法
__str__ print语句输出内建数据类型,如果没设置则调用__repr__
__repr__(self) 打印、转换,repr(obj),该函数返回对象字符串表达式
__hash__(self) hash(object)
__setitem__(self, name, value) 按照索引赋值 ,object[xxx] =
__getitem__(self, name) 按照索引获取值 ,object[xxx]
__delitem__(self, name) 按照索引删除值,del object[xxx]
__len__(self) 获得长度 ,len(object)
__call__(self, function) 函数调用
__getattr__(self, name) 获取属性的值 ,object.xxx
__setattr__(self, name, value) 设置属性的值 ,object.xxx =
__delattr__(self, name) 删除name属性 ,del object.xxx
__getattribute__(self, name) 对于新式类调用该方法获取属性值
__mro__(cls) 返回新式类的内置mro算法后的tuple
__sizeof__(self) 返回类暂用的内存大小
继承
Python同时支持单继承与多继承,继承的基本语法为class新类名(父类1,父类2,..)
当只有一个父类时为单继承,当存在多个父类时为多继承。
子类会继承父类的所有的属性和方法,子类也可以覆盖父类同名的变量和方法。
在传统类中,如果子类和父类中同名的方法或者属性,在查找的时候基本遵循自左到右,深度优先的原则。
在引入新型类后,使用C3的MRO算法:可以简单的理解为:深度优先,从左到右遍历基类,先遍历高level的,再遍历低level的,如果任何类在搜索中是重复的,只有最后一个出现的位置被保留,其余会从MROlist中删除。也就是说类的共同的祖先只有在其所有的子类都已经被check之后才会check。
构造函数:
  •   如果子类没有定义自己的构造函数,父类的构造函数会被默认调用,但是此时如果要实例化子类的对象,则只能传入父类的构造函数对应的参数,否则会出错
  •   如果子类定义了自己的构造函数,而没有显示调用父类的构造函数,则父类的属性不会被初始化
  •   如果子类定义了自己的构造函数,显示调用父类,子类和父类的属性都会被初始化
  •   super(object, self).__init__(self)
    构造函数的使用原理也可以扩展到其他重载方法上
自省与反射
Python提供一些接口来实现该功能:
dir([object]):查看对象的属性和函数列表。如果对象是个模块,则返回模块的所有属性,如果object是一个类对象,返回类和其父类的所有属性。
    不带参数时,显示调用者的局部变量,作用在模块上时候,显示模块的__dict__内容,显示在类上,显示类和基类的__dict__内容
issubclass(sub,sup):判断一个类是另一个类的子类或子孙类
isinstance(obj1,obj2):在判定一个对象是否是另一个给定类的实例
callable():是一个布尔函数,确定一个对象是否可以通过函数操作符(())来调用。如果函数可 调用便返回True,否则便是False.
inspect模块提供了一系列自省函数,它可以获取模块,类,方法,函数,traceback,帧对象,代码对象的信息。常用的方法getmembers,ismodule,getcallargs,isclass等
新型类:访问控制
新型类是在Python2.2中引入的,其在语法和行为上基本和经典类兼容,主要差别在于所有的新式类必须继承至少一个父类,Object是所有类之母,如果类没有继承任何其他父类,则object将作为默认的父类,新型类还支持从内置类型如list,dict, file等创建子类。
新型类的实例在具有传统类实例的特性,但在__init__的基础上加入的新的构造函数__new__,同时支持静态方法@staticmethod和类方法@classmethod
Property:提供灵活的机制来读取、编写或计算私有字段的值。可以像使用公共数据成员一样使用属性,但实际上它们是称作“访问器”的特殊方法。这使得可以轻松访问数据,此外还有助于提高方法的安全性和灵活性。
property(fget=None,fset=None, fdel=None,doc=None)
__slots__:在Python中可以用__dict__属性来跟踪所有实例属性,而事实上__dict__会占用大量的内存,从Python2.2开始可以用类变量__slots__代替__dict__.,它是一个由具有合法标识的实例属性构成的集合。在定义了__slots__属性的类中不会在存在__dict__,因此可以节约内存,同时它能防止动态增加实例属性,从某种程度上讲更为安全。
描述符
元类:访问控制
对于万物皆是对象的Python,对于定义类的一段代码其本身也是对象,那么这个类对象的类型就是元类,它用来描述类的类。
__metaclass__:在元类用于创建类的时候,解释器先查找__metaclass__属性,该属性的值便是类的元类,如果没有找到该属性的定义,则会查找其父类的__metaclass__.如果仍然没有找到,对于新型类则会以type(object)作为其元类,如果当前模块有全局变量名为metaclass,则将其值作为其元类,而对于传统的类,其元类类型为types.ClassType.
在元类中也可以定义类方法,一般叫做元方法,元方法和普通的类方法在使用上存在一定的区别,元方法能够被元类或者元类对象(类)直接调用,但不能被类的实例调用,而类方法可以被类或者类的实例直接调用。
在继承关系中,元类和普通的超类存在一定的区别,元类属性的可用性是不会传递的,也就是说,元类的属性是对它的实例是可用的,但是对它的实例的实例是不可用的。
在元类的多继承中,通常会产生冲突,比如A,B都是带有元类的类,C多继承于A和B时会产生冲突
包/模块
Python中很重要的一个概念package|module,可以将代码进行很好的组织复用,避免命名冲突
__name__:当前module的名称,但当当前脚本为执行入口时,该值为__main__
每个python脚本文件即为一个module,脚本中的全局变量即为该module的attr
package由module组成,在module的目录中有__init__.py,则该目录即为package,该文件可以理解为package的构造文件,会在导入该package的时候执行
该文件必须存在,否则就只当成普通目录
__all__:列出该package提供的module列表,方便执行import package.*进行全部导入
module的查找顺序:
    1.在当前目录中查找module.py
   2.若没找到,在环境变量中查找,就像在PATH中查找一样
   3.若无PYTHONPATH变量,那么在安装目录中查找,在unix中是.:/usr/local/lib/python 其实python是在sys.path中的所有目录中查找module的,可以查看sys.path
命名空间
命名空间(name space)是从名称(name)到对象(object)的映射(map)。当一个name映射到一个object上时,这个name和这个object就绑定(bind)了。
Python中一切都是对象(object),包括function,module,class,package本身。这些对象都在内存中真正的存在,就像活在世上的每一个人。
用name给每个object起名。每个名字只对应一个对象,一个对象可以由多个名字。但是name不是object本身。
Python中有很多name space,常用的有:build—in name space(内建命名空间)global name space(全局命名空间),local name space(局部命名空间)。在不同的name space中的name是没有关系的。
每个object都有自己的name space,可以通过object.name的方式访问object的name space中的name,每个object的name都是独立。即使在别的name space中有与之相同的name,它们也是没有任何关联的。
每一个object,都有自己的name space,name space都是动态创建的,每一个name space的生存时间也不一样。
LGB的规则用scope的概念来解释就是:在任何代码执行的时候,都至少有三个scope
  •   一个是local namespace 组成的scope
  •   一个是当前module的global namespace 组成的scope
  •   还有build-in namespace 组成的scope
  •   从内到外一次查找一个unqualified name。L-local G-global B-buildin
with as
with所求值的对象必须有2个方法,__enter__  __exit__
提供block的操作,__enter__在block前执行,__exit__在block后执行
其中__enter__方法能有返回值,提供给as,用于block内部访问
当block内部有异常时,__exit__也依旧会被执行


back up ↑

无觅相关文章插件,快速提升流量