二十一、 Python 面向对象基础(二) -- 类成员、修饰符、特殊成员
一、类成员
类成员可以分为3类:字段,方法和属性。
字段:静态字段、普通字段
方法:静态方法、普通方法、类方法
属性:普通属性
通过类访问:静态字段、 静态方法、类方法、
通过对象访问:普通字段,类普通方法、类特性
所有的成员中:只有普通字段内容保存在对象中。即:根据此类创建了多少对象,在内存中就有多少普通字段。
其他的成员则保存在类中。即:无论对象多少,在内存中仅创建一份。
二、字段
字段包括:普通字段和静态字段。他们在定义和使用中有区别。本质区别为在内存中保存的位置不同。
- 普通字段属于对象
- 静态字段属于类
静态字段,将每个对象重复的东西放到类中。
访问规则:谁的成员谁访问。对象的成员用对象访问。类的成员用类访问,除了类中的方法。
1 class Province: 2 3 #静态字段 4 country = '中国' 5 6 def __init__(self,name): 7 8 #普通字段 9 self.name = name 10 11 #直接访问普通字段 12 obj = Province('河北') 13 print(obj.name) 14 15 #直接访问静态字段 16 print(Province.country) 17 18 #也可以通过对象访问静态字段,但是不推荐 19 print(obj.country)

从上图可以看出
- 静态字段内存中只保存一份
- 普通字段在每个对象都保存一份
三、方法
方法包括:普通方法、静态方法和类方法。 3种方法 都内存中都归属于类。 区别在于调用方式不同。
普通方法:由对象调用,至少一个self参数;执行普通参数的时候,自动调用该方法的对象,赋值给self
静态方法:由类调用,无默认参数。
类方法:由类调用;至少一个cls参数。在执行的时候,自动调用该类赋值个给cls
静态方法:仅仅属于该类,类似函数工具库的作用。可以直接使用,不需要类的实例调用
类方法:将类作为参数传递,主要用来获取和类相关的一些数值
1 class Foo: 2 3 def __init__(self,name): 4 self.name = name 5 6 def ord_func(self): 7 8 """ 9 定义普通方法,至少一个self参数 10 :return: 11 """ 12 #print self.name 13 14 print('普通方法') 15 16 @classmethod 17 18 def class_fun(cls): 19 """ 20 定义类方法,至少有一个cls 参数 21 :return: 22 """ 23 print('类方法') 24 print(dir(cls)) 25 26 @staticmethod 27 def static_func(): 28 """静态方法,无默认参数""" 29 print('静态方法') 30 31 32 #调用普通方法 33 f = Foo('yy') 34 f.ord_func() 35 36 #调用类方法 37 Foo.class_fun() 38 39 #调用静态方法 40 Foo.static_func() 41 42 43 C:\Python35\python.exe D:/python/day8/pr.py 44 普通方法 45 类方法 46 ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'class_fun', 'ord_func', 'static_func'] 47 静态方法

相同点:对于所有方法而言,均属于类中。所以在内存中也只保存一份。
不同点:方法调用者不同。调用方法时传递的参数不同
四、属性
Python中的属性就是普通方法的变种。
- 属性的基本使用
- 属性的两种定义方式
1:属性的基本使用
1 class Foo: 2 3 def __init__(self,name): 4 self.name = name 5 6 def ord_func(self): 7 8 """ 9 定义普通方法,至少一个self参数 10 :return: 11 """ 12 #print self.name 13 14 print('普通方法') 15 16 @property 17 def start(self): 18 temp = '%s '%self.name 19 print(temp) 20 21 22 #调用普通方法 23 f = Foo('yy') 24 25 #直接使用特性名称访问 26 f.start
属性的定义和使用的注意点:
定义时,在普通方法的基础上添加 @property 装饰器
定义时,仅仅有self一个参数
调用方法的时候,无需()
属性存在的意义: 访问属性时可以制造出和访问字段相同的假象。
2、属性的定义
(此部分,需要参考老师博客http://www.cnblogs.com/wupeiqi/p/4766801.html)
装饰器:在方法上应用property装饰器
1 @property 2 def start(self): 3 temp = '%s '%self.name 4 print(temp)
静态字段:定义只为property对象的静态字段
1 BAR = property(get_bar)
五、成员修饰符
类的所有成员,对于访问分2种:
- 公有成员 任何地方都可以访问
- 私有成员 只有在类的内部才能访问
1:私有成员和公有成员定义不同
私有成员命名时:前2个字符是下划线(特殊成员除外:__init__, __call__, __dict__等)
2: 私有成员和公有成员的访问限制不同
静态字段
- 公有静态字段 :类可以访问;类内部可以访问;派生类可以访问
- 私有静态字段 :仅内部可以访问
普通字段
- 公有普通字段: 对象可以访问;类内部可以访问;派生类可以访问
- 私有普通字段:仅类内部可以访问
- 如果要强制访问私有字段,可以使用【对象.__类名称__私有字段】 访问
-
1 class Foo: 2 3 def __init__(self): 4 self.name = '公有字段' 5 self.__foo = '私有字段' 6 7 def Foo_f1(self): 8 print(self.__foo) 9 10 class B(Foo): 11 def F1(self): 12 print(self.name) 13 #派生类调用父类私有字段报错 14 #print(self.__foo) 15 16 #强制访问 17 print(self._Foo__foo) 18 19 obj1 = Foo() 20 obj2 = B() 21 #对象调用普通公有字段 22 print(obj1.name) 23 print(obj2.name) 24 #对象调用普通私有字段报错 25 # print(obj1.__foo) 26 # print(obj2.__foo) 27 28 #类内部可以调用私有字段 29 obj1.Foo_f1() 30 obj2.Foo_f1() 31 obj2.F1() 32 33 34 #强制访问 35 obj1._Foo__foo
静态字段
- 普通静态字段
- 私有静态字段
- 如果要强制访问私有字段,可以使用【对象.__类名称__私有字段】 访问
1 class Foo: 2 age = '公有静态' 3 __sex = '私有静态' 4 def __init__(self): 5 self.name = '公有字段' 6 self.__foo = '私有字段' 7 8 def Foo_f1(self): 9 print(Foo.age) 10 print(Foo.__sex) 11 12 class B(Foo): 13 def F1(self): 14 print(self.name) 15 #派生类调用父类私有字段报错 16 # print(self.__foo) 17 18 #强制访问 19 print(self._Foo__foo) 20 21 #强制访问 22 print(self._Foo__sex) 23 24 25 26 obj1 = Foo() 27 obj2 = B() 28 29 #公有静态类可以访问 30 print(Foo.age) 31 32 #私有静态,类直接访问报错 33 # print(Foo.__sex) 34 35 #公有静态类内部可以访问 36 #私有静态类内可以直接访问 37 obj1.Foo_f1() 38 39 #公有静态派生类可以访问 40 print(obj2.name) 41 42 #私有静态派生类访问直接报错 43 # print(obj2.__sex) 44 45 46 obj2.F1()
方法
普通方法
- 普通公有方法: 在对象、类内部、派生类访问
- 普通私有访问:仅仅在内内部访问
- 如果要强制访问私有字段,可以使用【对象.__类名称__私有字段】 访问
1 class Foo: 2 3 def __init__(self): 4 self.name = '公有字段' 5 self.__foo = '私有字段' 6 7 def Foo_f1(self): 8 print('普通公有方法') 9 10 def __Foo_f2(self): 11 print('普通私有方法') 12 13 14 def Foo_f3(self): 15 self.__Foo_f2() 16 17 @staticmethod 18 def static_method(): 19 print('静态方法') 20 21 22 23 24 25 class B(Foo): 26 def F1(self): 27 self.Foo_f1() 28 29 #强制调用普通私有 30 self._Foo__Foo_f2() 31 32 33 obj1 = Foo() 34 obj2 = B() 35 36 #对象调用普通访问 37 obj1.Foo_f1() 38 39 #对象调用普通私有报错 40 # obj1.__Foo_f2() 41 42 #类内部调用普通私有方法 43 obj1.Foo_f3() 44 45 obj2.F1()
静态方法
- 静态公有方法: 在对象、类内部、派生类访问
- 静态私有访问:仅仅在内内部访问
- 如果要强制访问私有字段,可以使用【对象.__类名称__私有字段】 访问
1 class Foo: 2 3 def __init__(self): 4 self.name = '公有字段' 5 self.__foo = '私有字段' 6 7 @staticmethod 8 def Foo_f1(): 9 print('静态公有方法') 10 11 @staticmethod 12 def __Foo_f2(): 13 print('静态私有方法') 14 15 16 def Foo_f3(self): 17 self.__Foo_f2() 18 19 20 class B(Foo): 21 def F1(self): 22 self.Foo_f1() 23 24 #强制调用普通私有 25 self._Foo__Foo_f2() 26 27 28 obj1 = Foo() 29 obj2 = B() 30 # 类中直接调用静态公有方法 31 Foo.Foo_f1() 32 33 # 类内部调用静态私有方法访问 34 obj1.Foo_f3() 35 36 #派生类调用静态公有,强制调用静态私有 37 obj2.F1()
在属性上,与字段和方法类似。
六、类的特殊成员
类中有字段、字段、属性三大类成员
如果成员前有两个下环线,表示该成员是私有成员,私有成员只能用于类内部调用。
但是也存在一些特殊含义的成员
1:__doc__
输出类的描述信息
1 class Foo(): 2 """ 查看类的doc """ 3 4 def func(self): 5 pass 6 7 8 obj1 = Foo() 9 print(Foo.__doc__) 10 print(obj1.__doc__)
2:__module__ 和 __class__
__module__当前操作的对象在哪个模块
__class__ 当前操作的对象是什么类
class Foo(): """ 查看类的doc """ def func(self): pass obj1 = Foo() print(Foo.__module__) print(obj1.__module__) print(Foo.__class__) print(obj1.__class__) C:\Python35\python.exe D:/python/day8/pr.py __main__ __main__ <class 'type'> <class '__main__.Foo'>
3、__init__
构造方法,通过类创建对象的时候,自动触发执行
1 class Foo(): 2 """ 查看类的doc """ 3 4 def func(self): 5 pass 6 def __init__(self): 7 print('我是构造函数') 8 9 obj1 = Foo() #自动触发__init__
4、__del___
解析防范,在对象被释放的时候,自动触发
此方法不需要定义。python在进行垃圾回收的时候自动触发执行
5、__call__
对象后面加(),触发执行
- 构造方法的执行是有创建对象触发的。即: 对象= 类名()
- 对于__call__的方法的执行是有对象后加()触发执行,即对象() 或者类()
1 class Foo(): 2 def func(self): 3 pass 4 def __init__(self): 5 print('我是构造函数') 6 7 def __call__(self): 8 print('我是call函数') 9 10 obj1 = Foo() #自动触发__init__ 11 12 # 对象后加()触发执行__call__ 13 obj1() 14 15 #类后加()触发执行__call__ 16 Foo()() 17 18 C:\Python35\python.exe D:/python/day8/pr.py 19 我是构造函数 20 我是call函数 21 我是构造函数 22 我是call函数
6、__dict__
显示对象或者类中所有成员
普通字段属于对象,静态字段和方法属于类。
1 class Foo(): 2 name = 'Foo' 3 4 def __init__(self,age): 5 self.age = age 6 7 obj1 = Foo(18) 8 9 #获取类所有的成员 :静态成员和方法 10 print(Foo.__dict__) 11 12 #{'__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__init__': <function Foo.__init__ at 0x009D4F60>, '__dict__': <attribute '__dict__' of 'Foo' objects>, 'name': 'Foo', '__module__': '__main__', '__doc__': None} 13 14 #获取对象的成员 15 print(obj1.__dict__) 16 #{'age': 18}
7、__str__
打印对象,默认返回对象的地址
如果类中定义了__str__, 在打印对象的时候, 返回该方法返回值
1 class Foo(): 2 name = 'Foo' 3 4 def __init__(self,age): 5 self.age = age 6 7 def __str__(self): 8 return '我是一个字符串' 9 10 obj1 = Foo(18) 11 print(obj1) 12 # 未定义__str__ <__main__.Foo object at 0x005995D0> 13 14 #添加 __str__ 后返回 我是一个字符串
8、 __gettiem__ __setitem__ __delitem__
用于索引上进行操作,如字段。以上分别为获取、设置、删除数据
1 class Foo: 2 3 def __init__(self,name): 4 self.name = name 5 6 def __getitem__(self,item): 7 print(item) 8 9 def __setitem__(self,item,value): 10 print(item,value) 11 12 def __delitem__(self,key): 13 print(key) 14 15 obj1 = Foo('kk') 16 17 #对象后【】 调用 __getitem__ 18 result = obj1['k1'] 19 20 #自动执行__setitem__ 21 obj1['k2'] = 123 22 23 #自动执行__delitem__ 24 del obj1['k2']
9、__getslice__ __setslice__ __delslice__
上面3个方法用于切片操作(python2.7)
在3.5中,3个功能被 __getitem__ __setitem__ __delitem__ 替换
1 class Foo: 2 3 def __init__(self,name): 4 self.name = name 5 6 def __getitem__(self,item): 7 print(type(item),item, '__getitem__') 8 9 def __setitem__(self,item,value): 10 print(item,value,'__setitem__') 11 12 def __delitem__(self,key): 13 print(key,'__delitem__') 14 15 obj1 = Foo('kk') 16 17 #调用 __getitem__ <class 'slice'> slice(1, 3, None) __getitem__ 18 result = obj1[1:3] 19 20 #自动执行__setitem__ 21 obj1[1,2] = [11,22] 22 23 #自动执行__delitem__ 24 del obj1[1,2] 25 26 27 C:\Python35\python.exe D:/python/day8/pr.py 28 <class 'slice'> slice(1, 3, None) __getitem__ 29 (1, 2) [11, 22] __setitem__ 30 (1, 2) __delitem__
10、__iter__
用于迭代器,列表、字段、元组都可以进行迭代,是因为内部定义了__inter__
如果for对象,直接执行 对象内部的__iter__
有2中方式: 在__iter__应用yield
在__iter__iter 返回迭代器
1 class Foo(object): 2 3 def __init__(self,sq): 4 self.sq = sq 5 6 #第一种方式 7 def __iter__(self): 8 yield 1 9 yield 2 10 yield 3 11 12 #第二种方式 13 def __iter__(self): 14 return iter(self.sq) 15 16 obj1 = Foo([11,22,33,44]) 17 18 for i in obj1: 19 print(i)
11: __new__ 和 __metaclass__
__new__ 创建类实例
__metaclass__ 指定类由哪个类创建
类本身也是对象。类是type 类的实例
1 #普通方式 2 class Foo(object): 3 4 def func1(self): 5 print('Foo') 6 7 8 obj1 = Foo() 9 obj1.func1() 10 11 #特殊方式,type创建 12 def func(self): 13 print('bar') 14 15 Bar = type('Bar',(object,),{'func':func}) 16 17 #type 第一个参数,类名称 18 #type 第二个参数,当前类的基类 19 #type 第三个参数,类的成员 20 21 obj2 = Bar() 22 obj2.func()

浙公网安备 33010602011771号