Python

看下面一个简单类:

>>> class MyClass(object):
... """
... this is a class with a doc string
... """
... pass
...
>>> print MyClass.__doc__ this is a class with a doc string

实例化一个类和函数调用的语法是一样的:

>>> myClass = MyClass()

类属性是类的所有对象所共享的属性,它与C++中的static属性类似:

>>> class MyClass(object):
... """
... this is a class with a doc string
... """
... str = 'this is a class attribute'
...
>>> print MyClass.str
this is a class attribute
>>> a,b = MyClass(), MyClass()
>>> id(a.str)
25889584
>>> id(b.str)
25889584

实例属性是每个对象独有的属性,每个对象的实例属性的值都可能不同:

>>> class MyClass(object):
... ClassData = 'This is a Class Attribute'
...
>>> obj1, obj2 = MyClass(), MyClass()
>>> obj1.NewData, obj2.NewData = 'New Data of obj1', 'New Data of obj2'
>>> id(obj1.NewData)
29413928
>>> id(obj2.NewData)
29413968
>>>

Python中,对象的属性是可以动态增加的。

类的所有对象,都可以读取类属性;

但类属性不能通过对象修改,在修改时,Python会自动为对象创建一个实例属性,并屏蔽掉类属性。

>>> obj1.ClassData = 'Change obj1\'s ClassDate'
>>> print obj1.ClassData
Change obj1's ClassDate
>>> print MyClass.ClassData
This is a Class Attribute
>>> print obj2.ClassData
This is a Class Attribute
>>> del obj1.ClassData
>>> print obj1.ClassData
This is a Class Attribute

类方法是通过类名就可以直接调用的方法,与C++中的static方法类型,函数的第一个参数为类本身,约定俗成将参数命名为cls:

>>> class ClassWithClassMethod(object):
... @classmethod
... def classFunc(cls):
... print 'This is a class method:',id(ClassWithClassMethod),id(cls)
...
>>> ClassWithClassMethod.classFunc()
This is a class method: 29525656 29525656

实例方法是必须通过对象调用的方法,方法的第一个参数是对象本身,约定俗成将参数命名为self:

>>> ClassWithObjMethod.objFunc()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound method objFunc() must be called with ClassWithObjMethod instance as first argument (got nothing instead)
>>>
>>> obj = ClassWithObjMethod()
>>> obj.objFunc()
This is a obj method: 29392080
>>> id(obj)
29392080
>>>

Python中,也可以对构造了析构的行为进行定义:

__init__会在对象构造时调用,通常会在这里进行为对象的属性赋值等初始化动作。在__init__中,必须显示的调用父类的__init__方法。

super(type, obj)返回父对象,这行代码也可以用object.__init__(self)替代。

__del__是在对象被Python垃圾回收时调用,因为垃圾回收是由Python控制,所以通常不会重写__del__方法。

>>> class CtorAndDest(object):
... def __init__(self,val):
... super(CtorAndDest, self).__init__()
... self.data = val
... print 'construct an object'
... def __del__(self):
... print 'destroy an object'
...
>>> obj = CtorAndDest(100)
construct an object
>>> obj.data
100
>>> del obj
destroy an object

封装、继承、多态是面向对象的三个基本要素,通过继承可以让我们在子类中重用父类的属性、方法。

Python支持多继承,多个父类间以逗号分隔。如果子类不重写__init__方法,在构造时会自动调用父类的__init__。

>>> class ParentClass(object):
... def __init__(self):
... self.data = 100
... print 'ParentClass constructor'
... def fonc(self):
... print 'Parent function'
...
>>> class AnotherParentClass(object):
... def func(self):
... print 'another parent function'
...
>>> class ChildClass(ParentClass, AnotherParentClass):
... pass
...
>>>
>>>
>>> obj = ChildClass()
ParentClass constructor
>>> obj.fonc()
Parent function
>>> obj.func()
another parent function
>>> obj.data
100

类或对象中的数据,通常需要有不同的作用域。面向对象开发时不建议由客户直接访问对象的数据,而是由对象提供的方法进行访问,以便对象数据在修改时不影响客户代码。

Python对没有像提供C++一样的public/protected/private关键字,不过可以通过下划线的使用达到一定的可见性控制。

不以下划线开关的普通属性,相当于C++中的public,所有对象都可以访问。双下划线__开头的属性,代表是私有属性,无法被其它对象访问。

>>> class VisibleClass(object):
... def __init__(self):
... super(VisibleClass, self).__init__()
... self.publicData = 'This is public data'
... self.__privateData = 'This is private data'
...
>>> class SubClass(VisibleClass):
... def func(self):
... print self.publicData,self.__privateData
...
>>> vobj = VisibleClass()
>>> vobj.publicData
'This is public data'
>>> vobj.__privateData
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'VisibleClass' object has no attribute '__privateData'
>>>
>>> obj = SubClass()
>>> obj.func()
This is public data
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in func
AttributeError: 'SubClass' object has no attribute '_SubClass__privateData'
>>>

所谓多态,可以简单理解为子类使用与父类相同的接口,但提供不同的功能。通过在子类中重写父类中定义的方法,可以实现多态。

>>> class SortClass(object):
... def sort(self,lst):
... pass
...
>>> class SwapSortClass(SortClass):
... def sort(self,lst):
... print 'This is Swap sort'
...
>>> class QuickSortClass(SortClass):
... def sort(self,lst):
... print 'This is quick sort'
...
>>> def sort(lst, algo = SwapSortClass()):
... return algo.sort(lst)
...
>>> sort([1,3,2])
This is Swap sort
>>> sort([1,3,2], QuickSortClass())
This is quick sort
>>>

在上例中,由SortClass定义sort接口,子类中重写对应的方法提供不同的排序算法。在sort函数中,可以直接通过指定不同的参数使用不同的算法,而不需要修改sort函数的实现,代码可扩展性更强。

因为Python是弱类型的语言,所以上例中Sort类并不是必须的,实际不需要通过子类重写,只要传入的对象提供了相同的接口就可以达到相同的目的。

内置函数dir()可以查看对象/模块的属性列表,对象的__dict__则显示对象的所有属性及属性的值(等价于内置函数vars):

通过__dict__的例子可以看到,对象的所有属性及值是以dict的形式保存在对象的__dict__属性中的,而不是像C++一样,对象的所有属性是在内存中连续分布的。带来的好处是可以为对象动态的增加和删除属性,并可以通过名字方便的访问这些属性;坏处是会占用更大的内存,不过可以通过__slots__使对象属性固定下来,并减小内存占用。

>>> obj = DictClass()
>>> import sys
>>> sys.getsizeof(obj)
32
>>> obj.a = 1
>>> sys.getsizeof(obj)
32
>>> obj.__dict__['b'] = 2
>>> obj.a
1
>>> obj.b
2
>>>

注意:不要像例子中一样通过__dict__访问对象的属性!

>>> class SlotsClass(object):
... __slots__ = ()
...
>>> import sys
>>> sys.getsizeof(SlotsClass())

getattr可以获取一个对象的某个属性的值,如果属性不存在,可以返回一个给定的默认值;

setattr用来设置对象属性的值,属性不存在时会为对象增加属性;

delattr用来删除对象的属性。

hasattr用来判断对象是否存在某个属性。

这四个方法事实上都是通过操作对象的__dict__来进行的。

Isinstance方法可以用来确定一个对象是不是一个类或它的子类的实例:

还可以使用type(obj) is Type进行判断,此方法对于obj是Type的子类的实例的情况将返回False。

Issubclass用来判断一个类是否是另一个类的子类,包括直接子类或间接子类。

>>> isinstance(0,int)
True
>>> isinstance(True,bool)
True
>>> bool.__bases__
(<type 'int'>,)
>>> obj = QuickSortClass()
>>> isinstance(obj,QuickSortClass)
True
>>> isinstance(obj,SortClass)
True
>>> type(obj) is QuickSortClass
True
>>> type(obj) is SortClass
False
>>>
>>> issubclass(bool,int)
True
>>> issubclass(type,object)
True
>>> issubclass(str,object)
True
>>> issubclass(SwapSortClass,SortClass)
True
>>> SwapSortClass.__bases__
(<class '__main__.SortClass'>,)
>>>

Python为对象提供了一系统的方法重载,以改变对象在执行某此操作时的行为。下面提供了一个简单的示例,展示了如何使对象支持+, +=, <, if判断等操作。

可以在《Python核心编程》等资料中找到Python支持的特殊方法的全集。

数据描述符:(类似于C#中的属性)

重写了__get__和__set__方法的对象被称为数据描述符。数据描述符可以用于对象属性访问的封装和控制,如下例:

>>> class DataDescripterA(object):
... def __init__(self):
... self.data = None
... def __get__(self,attr,type=None):
... return 'returned by __get__:%s'%self.data
... def __set__(self,attr,val):
... if isinstance(val,str):
... self.data = val
... else:
... assert False,'Must set to string'
...
>>> class Sample(object);
File "<stdin>", line 1
class Sample(object);
^
SyntaxError: invalid syntax
>>> class Sample(object):
... desc = DataDescripterA()
...
>>> obj = Sample()
>>> obj.desc = 10
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 10, in __set__
AssertionError: Must set to string
>>>
>>>
>>> obj.desc = 'a string'
>>> obj.desc
'returned by __get__:a string'
>>>

元类:后续单独开辟一篇来理解。

Python基础(9) - 类的更多相关文章

  1. python基础——枚举类

    python基础——枚举类 当我们需要定义常量时,一个办法是用大写变量通过整数来定义,例如月份: JAN = 1 FEB = 2 MAR = 3 ... NOV = 11 DEC = 12 好处是简单 ...

  2. python基础——定制类

    python基础——定制类 看到类似__slots__这种形如__xxx__的变量或者函数名就要注意,这些在Python中是有特殊用途的. __slots__我们已经知道怎么用了,__len__()方 ...

  3. Python基础-类的探讨(class)

    Python基础-类的探讨(class) 我们下面的探讨基于Python3,我实际测试使用的是Python3.2,Python3与Python2在类函数的类型上做了改变 1,类定义语法  Python ...

  4. 二十六. Python基础(26)--类的内置特殊属性和方法

    二十六. Python基础(26)--类的内置特殊属性和方法 ● 知识框架 ● 类的内置方法/魔法方法案例1: 单例设计模式 # 类的魔法方法 # 案例1: 单例设计模式 class Teacher: ...

  5. python基础(26):类的成员(字段、方法、属性)

    1. 字段 字段:包括普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同. 普通字段属于对象 静态字段属于类 字段的定义和使用: class Province: # ...

  6. Python基础(十一) 类继承

    类继承: 继承的想法在于,充份利用已有类的功能,在其基础上来扩展来定义新的类. Parent Class(父类) 与 Child Class(子类): 被继承的类称为父类,继承的类称为子类,一个父类, ...

  7. python基础编程——类和实例

    在了解类和实例之前,需要先了解什么是面向对象,什么又是面向过程.面向过程是以过程为中心实现一步步操作(相互调用,类似流水线思想):面向对象是以事物为中心,某个事物可以拥有自己的多个行为,而另一个事物也 ...

  8. python基础----元类metaclass

    1 引子 class Foo: pass f1=Foo() #f1是通过Foo类实例化的对象 python中一切皆是对象,类本身也是一个对象,当使用关键字class的时候,python解释器在加载cl ...

  9. python基础===新式类与经典类

    首先: Python 2.x中默认都是经典类,只有显式继承了object才是新式类 Python 3.x中默认都是新式类,不必显式的继承object 这两种类的区别: 新式类重定义的方法更多,当然这不 ...

随机推荐

  1. php二维数组去除重复值

    <?php //二维数组 $test["aa"] = array("id"=>"17","name"=> ...

  2. Java算法 -- 顺序表

    顺序表结构定义:就是按照顺序存储方式存储的线性表 1.定义一个顺序表的基本数据: static final int MAXLEN = 100; Class Student{ private Strin ...

  3. pycharm注册

    1.官方下载专业版,并安装 http://www.jetbrains.com/pycharm/download/#section=windows 2.下载crack激活包 http://idea.la ...

  4. django admin后台的简单使用

    创建自己的model.py文件 from django.db import models from django.contrib.auth.models import ( BaseUserManage ...

  5. 关键字的使用 pass break continue

    # ### 关键字的使用 # (1)pass 过 作用 作站位用的 if 5==5: pass i = 0 while i <5: pass #约定俗成,在循环里面什么也不行的情况下,给友好提示 ...

  6. ajax 提交 json格式数据到后台

    例子:$.ajax({ type: 'POST', url: "/ROOT/modify.do", contentType: "application/json" ...

  7. 洛谷P3643 [APIO2016]划艇(组合数学)

    题面 传送门 题解 首先区间个数很少,我们考虑把所有区间离散化(这里要把所有的右端点变为\(B_i+1\)代表的开区间) 设\(f_{i,j}\)表示考虑到第\(i\)个学校且第\(i\)个学校必选, ...

  8. python difflib详解

    difflib -帮助进行差异化比较 这个模块提供的类和方法用来进行差异化比较,它能够生成文本或者html格式的差异化比较结果,如果需要比较目录的不同,可以使用filecmp模块. class dif ...

  9. 方法引用(Method reference)和invokedynamic指令详细分析

    方法引用(Method reference)和invokedynamic指令详细分析 invokedynamic是jvm指令集里面最复杂的一条.本文将详细分析invokedynamic指令是如何实现方 ...

  10. javascript 判断对象的内置类型

    判断某个对象值属于哪种内置类型,最靠谱的做法就是通过Object.prototype.toString方法.在toString方法被调用时,会执行下面的操作步骤:1. 获取this对象的[[Class ...