Python基础(9) - 类
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) - 类的更多相关文章
- python基础——枚举类
python基础——枚举类 当我们需要定义常量时,一个办法是用大写变量通过整数来定义,例如月份: JAN = 1 FEB = 2 MAR = 3 ... NOV = 11 DEC = 12 好处是简单 ...
- python基础——定制类
python基础——定制类 看到类似__slots__这种形如__xxx__的变量或者函数名就要注意,这些在Python中是有特殊用途的. __slots__我们已经知道怎么用了,__len__()方 ...
- Python基础-类的探讨(class)
Python基础-类的探讨(class) 我们下面的探讨基于Python3,我实际测试使用的是Python3.2,Python3与Python2在类函数的类型上做了改变 1,类定义语法 Python ...
- 二十六. Python基础(26)--类的内置特殊属性和方法
二十六. Python基础(26)--类的内置特殊属性和方法 ● 知识框架 ● 类的内置方法/魔法方法案例1: 单例设计模式 # 类的魔法方法 # 案例1: 单例设计模式 class Teacher: ...
- python基础(26):类的成员(字段、方法、属性)
1. 字段 字段:包括普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同. 普通字段属于对象 静态字段属于类 字段的定义和使用: class Province: # ...
- Python基础(十一) 类继承
类继承: 继承的想法在于,充份利用已有类的功能,在其基础上来扩展来定义新的类. Parent Class(父类) 与 Child Class(子类): 被继承的类称为父类,继承的类称为子类,一个父类, ...
- python基础编程——类和实例
在了解类和实例之前,需要先了解什么是面向对象,什么又是面向过程.面向过程是以过程为中心实现一步步操作(相互调用,类似流水线思想):面向对象是以事物为中心,某个事物可以拥有自己的多个行为,而另一个事物也 ...
- python基础----元类metaclass
1 引子 class Foo: pass f1=Foo() #f1是通过Foo类实例化的对象 python中一切皆是对象,类本身也是一个对象,当使用关键字class的时候,python解释器在加载cl ...
- python基础===新式类与经典类
首先: Python 2.x中默认都是经典类,只有显式继承了object才是新式类 Python 3.x中默认都是新式类,不必显式的继承object 这两种类的区别: 新式类重定义的方法更多,当然这不 ...
随机推荐
- .net 程序集的加载与反射
一. 程序集的加载: 在CLR内部使用System.Reflection.Assembly类的静态LoadFrom方法尝试加载程序集. LoadFrom方法在内部调用Assembly的Load方法,将 ...
- ASP.NET MVC 如何使用自定义过滤器(筛选器)
继承*****Attribute(筛选器三种具体类)-->重写方法-->标记在控制器 或者 方法上面 或者 在FilterConfig中Add [类名(类属性 = 值)]还有[AllowA ...
- ZKEACMS 的两种发布方式
前言 如果你还不知道ZKEACMS,不妨先了解一下. ASP.NET MVC 开源建站系统 ZKEACMS 推荐,从此网站“拼”起来 官方地址:http://www.zkea.net/zkeacms ...
- Web Server 在IIS上部署ASP.NET Core项目
在IIS上部署ASP.NET Core项目 一.配置应用程序池为无托管: 二.安装ASPNETCoreModule:(核心) 下载地址:https://go.microsoft.com/fwlink/ ...
- [Perl]通过GD模块获取字符/汉字的点阵
原来Perl获取汉字的点阵如此简单 示例脚本应保存为utf8格式 Code: [全选] [展开/收缩] [Download] (Untitled.pl) use GD; use utf8; my $g ...
- php 多维数据根据某个或多个字段排序
实现多维数组的指定多个字段排序 上面的实例讲解了如何实现多维数组指定一个字段排序,但如果要实现指定多个字段来对数组进行排序该如何思考? 多个字段是几个?2个,3个或更多,所以这个不确定的因素需要排除. ...
- jQuery滚动到特定位置时出现
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- ACM-ICPC 2018北京网络赛-A题 Saving Tang Monk II-优先队列
做法:优先队列模板题,按步数从小到大为优先级,PASS掉曾经以相同氧气瓶走过的地方就好了 题目1 : Saving Tang Monk II 时间限制:1000ms 单点时限:1000ms 内存限制: ...
- easyui里面的加载tree的两种方式
第一种: 使用EasyUI中Tree 符合EasyUI中Tree的Json格式,我们先看一下,格式是如何的 [{ "id":1, "text":"My ...
- Unity---解决重新调整游戏分辨率后,再运行游戏还是和之前分辨率一样的问题
经历 上次在Unity做了个小游戏,发布的时候忘了取消默认全屏了. 于是在Unity重新发布了一下,可是出来后分辨率还是默认全屏. 当时百思不得其解 原因 主要是因为当用Unity发布一个新游戏的时候 ...