Python 原创基础教程
第四章 类与对象
4.1 类简述
- 类是一个“模版”,可以包含变量和函数(即类是属性和方法的集合)
- 对象是类创建的实例,通过实例可以调用变量和函数
- 类中普通函数的必须有第一个参数,来代表该类调用函数的具体对象(一般取名为self)
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class A: x = 'x' def __init__(self): self.y = 'y' def f1(self): print("aaa") def f2(self,name): print('my name is %s'%name) obj1 = A() obj1.f1()
|
4.2 类成员
类的结构图,其中变量也称属性,函数也称方法
1 2 3 4 5 6 7 8 9 10
| graph LR A(类成员)-->B(变量) A-->C(函数) A-->D(方法属性) B-->普通变量 B-->静态变量 C-->普通函数 C-->类函数 C-->静态函数
|
4.3 变量(属性)
类中的变量也叫属性,亦可叫字段,是类这种数据结构中保存多样数据的方式
- 普通字段属于对象(每个对象都存一份)
- 静态字段属于类(就类存有一份)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class Province: country = '中国' def __init__(self,name): self.name=name
obj = Province('河北省') 访问普通字段 print obj.name
访问静态字段 Province.country
|
4.4 函数(方法)
函数在类中也叫方法。通过方法,让类这种数据结构具有“运动”的特征,即类不仅可以保存数据,以可以操作处理数据,其中操作处理数据就是通过类方法实现。
- 普通方法:对象调用,至少一个self参数,执行方法自动调用具体对象给该方法
- 类方法:由类调用,至少一个cls参数,执行时自动调用cls给该方法
- 静态方法:由类调用,无默认参数
三种方法都存于类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| class Foo: def __init__(self,name): self.name = name def ord_func(self): print(普通方法) @classemethod def class_func(cls): print(类方法) @staticmethod def static_func(): print(静态方法)
f = Foo() f.ord_func()
Foo.class_func()
Foo.static_func()
|
4.4.1 函数属性化
通过装饰器,函数可以像属性一样调用
- 用@property装饰器定义
- 仅有一个self参数
- 调用时无需括号
经典类(python2中常用)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| ################ 定义 ############### class Foo: def func(self): pass # 定义属性 @property def prop(self): print('abc') ################ 调用 ############### foo_obj = Foo() foo_obj.func() foo_obj.prop #调用属性
|
新式类
由于新式类中具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| # ############### 定义 ############### class Goods(object): @property def price(self): print '@property' @price.setter def price(self, value): print '@price.setter' @price.deleter def price(self): print '@price.deleter' # ############### 调用 ############### obj = Goods() obj.price # 自动执行 @property 修饰的 price 方法,并获取方法的返回值 obj.price = 123 # 自动执行 @price.setter 修饰的 price 方法,并将 123 赋值给方法的参数 del obj.price # 自动执行 @price.deleter 修饰的 price 方法
|
以下是property的构造方法(静态变量的方式)中有个四个参数
- 第一个参数是方法名,调用 对象.属性 时自动触发执行方法
- 第二个参数是方法名,调用 对象.属性 = XXX 时自动触发执行方法
- 第三个参数是方法名,调用 del 对象.属性 时自动触发执行方法
- 第四个参数是字符串,调用 对象.属性.doc ,此参数是该属性的描述信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Foo: def get_bar(self): return 'wupeiqi' def set_bar(self, value): return return 'set value' + value def del_bar(self): return 'wupeiqi' BAR = property(get_bar, set_bar, del_bar, 'description...') obj = Foo() obj.BAR obj.BAR = "alex" del Foo.BAR obj.BAE.__doc__
|
4.5 类变量(属性)扩展
- 静态变量(保存在类中):在任何对方都能访问
- 私有静态变量(变量前加__):只有在类的内部能访问
- 普通变量(在函数里的变量):对象可以访问、类内部可以访问、派生类中可以访问
- 普通私有变量(变量前加__):仅类内部能访问
- 静态变量:类可以访问、类内部可以访问、派生类中可以访问
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class C: name = "全局变量" def func(self): print C.name class D(C): def show(self): print C.name C.name obj = C() obj.func() obj_son = D() obj_son.show()
|
2.私有静态变量:仅类内部可以访问
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class C: __name = "私有静态变量" def func(self): print C.__name class D(C): def show(self): print C.__name C.__name obj = C() obj.func() obj_son = D() obj_son.show()
|
3.普通变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class C: def __init__(self): self.foo = "普通变量" def func(self): print self.foo class D(C): def show(self): print self.foo # 派生类中访问 obj = C() obj.foo obj.func() obj_son = D(); obj_son.show()
|
4.私有字段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class C: def __init__(self): self.__foo = "私有字段" def func(self): print self.foo class D(C): def show(self): print self.foo # 派生类中访问 obj = C() obj.__foo obj.func() obj_son = D(); obj_son.show()
|
如果想要强制访问私有字段,可以通过 【对象._类名__私有字段明 】访问(如:obj._C__foo),不建议强制访问私有成员。
4.6 类的特殊成员
类的特殊成员包括特殊变量和特殊方法,其是系统定义的,不需要用户定义,一般具有普通变量和方法所不具有的特殊功能
1.__ doc__:表示类的描述
1 2 3 4 5 6 7 8
| class Foo: """ 描述类信息,这是用于看片的神奇 """ def func(self): pass print(Foo.__doc__)
|
2.__ module__:表示当前操作对象在哪个模块
模块:组织函数和类的单位(类似java的一类一文件,有时不同模块可能有同名函数),例如Django
1
| print(obj.__module__) #输出对象所在模块
|
3.__ class__:表示当前操作对象的是什么
类
1
| print(obj.__class__) #输出对象所在类
|
4.__ init(self,..)__:
构造方法、类创建对象时自动执行
5.__ del(self,..)__:
析构方法、当对象在内存释放时、自动触发执行。
此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
6.__ call(self,..)__:
除析构方法外,执行对象的另一种特殊方法,对象加括号执行
1 2 3 4 5 6 7 8 9 10 11
| class Foo: def __init__(self): pass def __call__(self, *args, **kwargs): print '__call__' obj = Foo() # 执行 __init__ obj() # 执行 __call__
|
7.__ dict__:
显示类(静态变量、方法)和对象(普通字段)的所以成员
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| 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__ # 输出:{'country': 'China', '__module__': '__main__', 'func': , '__init__': , '__doc__': None} obj1 = Province('HeBei',10000) print obj1.__dict__ # 获取 对象obj1 的成员 # 输出:{'count': 10000, 'name': 'HeBei'} obj2 = Province('HeNan', 3888) print obj2.__dict__ # 获取 对象obj1 的成员 # 输出:{'count': 3888, 'name': 'HeNan'}
|
- __ str__:如果一个类中定义了__str__方法,那么在打印(print)对象时,默认输出该方法的返回值。
9.__ getitem__、__ setitem__、__ delitem__
用于对象的索引操作,如字典。以上分别表示获取、设置、删除数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #!/usr/bin/env python # -*- coding:utf-8 -*- class Foo(object): def __getitem__(self, key): print '__getitem__',key def __setitem__(self, key, value): print '__setitem__',key,value def __delitem__(self, key): print '__delitem__',key obj = Foo() result = obj['k1'] # 自动触发执行 __getitem__ obj['k2'] = 'wupeiqi' # 自动触发执行 __setitem__ del obj['k1'] # 自动触发执行 __delitem__
|
10.getslice__、__setslice__、__delslice
用于对象的分片操作(如列表)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Foo(object): def __getslice__(self, i, j): print '__getslice__',i,j def __setslice__(self, i, j, sequence): print '__setslice__',i,j def __delslice__(self, i, j): print '__delslice__',i,j obj = Foo() obj[-1:1] obj[0:1] = [11,22,33,44] del obj[0:2]
|
11.__ iter__:迭代器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
|
class Foo(object): pass obj = Foo() for i in obj: print i
class Foo(object): def __iter__(self): pass obj = Foo() for i in obj: print i
class Foo(object): 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
|
迭代的变种
1 2 3 4 5 6 7 8 9 10 11
| obj = iter([11,22,33,44]) for i in obj: print i
############################ obj = iter([11,22,33,44]) while True: val = obj.next() print val
|
4.7 旧式类和新式类
从Python2.2开始,Python 引入了 new style class(新式类)
- 新式类类似Java,有一个根类object,所有类都继承自根类object
- 新式类跟经典类的差别主要是以下几点:
a.新式类对象可以直接通过__class__属性获取自身类型:type
b.继承搜索的顺序发生了改变,经典类多继承属性搜索顺序: 先深入继承树左侧,再返回,开始找右侧;新式类多继承属性搜索顺序: 先水平搜索,然后再向上移动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| class A(object): """ 新式类 作为所有类的基类 """ def foo(self): print "class A" class A1(): """ 经典类 作为所有类的基类 """ def foo(self): print "class A1" class C(A): pass class C1(A1): pass class D(A): def foo(self): print "class D" class D1(A1): def foo(self): print "class D1" class E(C, D): pass class E1(C1, D1): pass e = E() e.foo() e1 = E1() e1.foo()
|
c.新式类增加了__slots__内置属性,可以把实例属性的种类锁定到__slots__规定的范围之中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| #比如只允许对A实例添加name和age属性 # -*- coding:utf-8 -*- class A(object): __slots__ = ('name', 'age') class A1(): __slots__ = ('name', 'age') a1 = A1() a = A() a1.name1 = "a1" a.name1 = "a"
#A是新式类添加了__slots__ 属性,所以只允许添加 name age
#A1经典类__slots__ 属性没用
|
d.新式类增加了__getattribute__方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class A(object): def __getattribute__(self, *args, **kwargs): print "A.__getattribute__" class A1(): def __getattribute__(self, *args, **kwargs): print "A1.__getattribute__" a1 = A1() a = A() a.test print "=========" a1.test
#A是新式类,每次通过实例访问属性,都会经过__getattribute__函数,
#A1不会调用__getattribute__所以出错了
|
4.8 类的实例化
类的实例化主要通过__init__()函数和__call__()函数实现,其中__init__()较为常用,call()函数是一种让类像函数一样使用的特殊方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class MyType(type): def __init__(self, what, bases=None, dict=None): super(MyType, self).__init__(what, bases, dict) def __call__(self, *args, **kwargs): obj = self.__new__(self, *args, **kwargs) self.__init__(obj) class Foo(object): __metaclass__ = MyType def __init__(self, name): self.name = name def __new__(cls, *args, **kwargs): return object.__new__(cls, *args, **kwargs) # 第一阶段:解释器从上到下执行代码创建Foo类 # 第二阶段:通过Foo类创建obj对象 obj = Foo()
|
继承自object的新式类才有__new__
__new__方法接受的参数虽然也是和__init__一样,但__init__是在类实例创建之后调用,而 __new__方法正是创建这个类实例的方法。
依照Python官方文档的说法,__new__方法主要是当你继承一些不可变的class时(比如int, str, tuple), 提供给你一个自定义这些类的实例化过程的途径。还有就是实现自定义的metaclass。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| # 创建一个类,继承int,并返回绝对值 class PositiveInteger(int): def __init__(self, value): super(PositiveInteger, self).__init__(self, abs(value)) i = PositiveInteger(-3) print i #结果还是-3
class PositiveInteger(int): def __new__(cls, value): return super(PositiveInteger, cls).__new__(cls, abs(value)) i = PositiveInteger(-3) print i #结果是 3
|
因为类的每一次实例化都是通过__new__实现的,通过重载类来实现单例
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Singleton(object): def __new__(cls): # 关键在于这,每一次实例化的时候,我们都只会返回这同一个instance对象 if not hasattr(cls, 'instance'): cls.instance = super(Singleton, cls).__new__(cls) return cls.instance obj1 = Singleton() obj2 = Singleton() obj1.attr1 = 'value1' print obj1.attr1, obj2.attr1 print obj1 is obj2
|