首页 > 代码库 > 面向对象(二)
面向对象(二)
类的成员
类的成员可以分为三大类:字段、方法和属性
一、字段
字段包括普通字段和静态字段,他们在定义和使用中有所区别,最本质的区别是内存中保存的位置不同。
- 普通字段属于对象,在内存中为每个对象保存一份
- 静态字段属于类,在内存中只保存一份
一般情况下,自己访问自己字段,普通字段只能使用对象访问,静态字段使用类访问(最好不要用对象访问静态字段),静态字段在代码加载时创建。
1 #!/usr/bin/env python
2 # coding=utf-8
3 class Province(object):
4 # 静态字段,保存在类中
5 country = ‘中国‘
6 def __init__(self, province):
7 # 普通字段,保存在对象中
8 self.name = ‘province‘
9 def show(self):
10 print(self.name)
11 test = Province(‘henan‘)
12 print(Province.country)
13 print(test.country)
14 print(test.show())
应用场景: 通过类创建对象时,如果每个对象都具有相同的字段,那么就使用静态字段
二、方法
方法包括:普通方法、静态方法和类方法,三种方法在内存中都归属于类,区别在于调用方式不同。
- 普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self;
- 类方法:由类调用; 至少一个cls参数;执行类方法时,自动将调用该方法的类复制给cls;
- 静态方法:由类调用;无默认参数;
1 class Province(object):
2 country = ‘中国‘
3 def __init__(self, province):
4 self.name = ‘province‘
5 # 普通方法,由对象去调用执行(方法属于类)
6 def show(self):
7 return self.name
8
9 # 静态方法,由类调用执行,对象是封装数据的,用不到对象封装数据,使用静态方法
10 # 可以有参数,可以没有
11 @staticmethod
12 def f1():
13 return ‘....‘
14 # 类方法
15 # 必须有一个参数cls, cls是类名 加()创建对象
16 @classmethod
17 def f2(cls):
18 print(cls.country)
19 print(cls)
20 test = Province(‘henan‘)
21 print(Province.country)
22 print(test.country)
23 print(test.show())
24 print(Province.f1())
25 Province.f2()
相同点:对于所有的方法而言,均属于类(非对象)中,所以,在内存中也只保存一份。
不同点:方法调用者不同、调用方法时自动传入的参数不同。
三、属性
属性定义有两种方式
- 装饰器 在方法上应用装饰器
View Code - 静态字段 在类中定义为property对象的静态字段
1 #!/usr/bin/env python 2 # coding=utf-8 3 class Pager: 4 def __init__ (self, all_count): 5 self.all_count = all_count 6 def f1(self): 7 return 123 8 def f2(self, value): 9 pass 10 def f3(self): 11 pass 12 foo = property(fget=f1, fset=f2, fdel=f3) 13 p = Pager(101) 14 ret = p.foo # 执行fget 15 print(ret) 16 p.foo = ‘hexm‘ # 执行fset 17 del p.foo # 执行fdel
类成员修饰符
对于每一个类的成员而言都有两种形式:
- 公有成员,在任何地方都能访问
- 私有成员,只有在类的内部才能方法
1 class Foo(object): 2 __cc = ‘123‘ # 公有静态字段 3 4 def __init__(self, name): 5 # 私有的,只能在类内部访问 6 self.__name = name # 私有字段 7 8 def f1(self): 9 print(self.__name) 10 11 def f2(self): 12 print(Foo.__cc) 13 14 obj = Foo(‘hexm‘) 15 obj.f1() 16 # print(obj.__name) # 错误 17 print(obj._Foo__name) # 最好不要用这种方式访问私有字段 18 19 obj.f2() 20 print(Foo.f1__cc) 21 22 # 继承Foo也不能访问私有的 23 class Bar(Foo): 24 def f2(self): 25 print(self.__name) 26 27 obj = Bar(‘hexm‘) 28 obj.f1() 29 obj.f2() # 错误
类的特殊成员
上面介绍了Python的类成员以及成员修饰符,从而了解到类中有字段、方法和属性三大类成员,并且成员名前如果有两个下划线,则表示该成员是私有成员,私有成员只能由类内部调用。无论人或事物往往都有不按套路出牌的情况,Python的类成员也是如此,存在着一些具有特殊含义的成员,详情如下:
1. __doc__
表示类的描述信息
1 class Foo: 2 """ 描述类信息 """ 3 4 def func(self): 5 pass 6 7 print Foo.__doc__
2. __module__ 和 __class__
__module__ 表示当前操作的对象在那个模块
__class__ 表示当前操作的对象的类是什么
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 class C(object): 5 6 def __init__(self): 7 self.name = ‘hexm‘
1 from lib.aa import C 2 3 obj = C() 4 print obj.__module__ # 输出 lib.aa,即:输出模块 5 print obj.__class__ # 输出 lib.aa.C,即:输出类
3. __init__
构造方法,通过类创建对象时,自动触发执行。
4. __del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
5.__call__
对象后面加括号,触发执行
1 class Foo(object): 2 def __init__(self): 3 # 构造方法,创建对象自动执行 4 print(‘init‘) 5 def __del__(self): 6 # 析构方法 7 pass 8 def __call__(self): 9 print(‘call‘) 10 p = Foo() 11 ret = p.__class__ 12 print(ret) 13 p() # 对象后面加括号,执行__call__方法 14 Foo()() # 先执行构造方法再执行call
6.__dict__
类或对象里面所有成员
1 class Foo: 2 def __init__(self, name, age): 3 self.name = name 4 self.age = age 5 def __call__(self): 6 return 123 7 test1 = Foo(‘hexm‘, 18) 8 test2 = Foo(‘zhuxj‘, 17) 9 # 对象里面封装的字段 10 ret = test1.__dict__ 11 print(ret) 12 # 类里面所有成员 13 print(Foo.__dict__)
7.__str__
在类中定义了__str__方法,在打印对象时,默认输出该方法的返回值
1 #!/usr/bin/env python 2 # coding=utf-8 3 class Foo: 4 def __init__(self, name, age): 5 self.name = name 6 self.age = age 7 def __str__(self): 8 # print 对象时,自动执行该方法 9 return ‘%s---%s‘ % (self.name, self.age) 10 test1 = Foo(‘hexm‘, 18) 11 test2 = Foo(‘zhuxj‘, 17) 12 print(test1) 13 print(test2) 14 ret1 = str(test1) 15 ret2 = str(test2) 16 print(ret1) 17 print(ret2)
8.__getitem__、__setitem__、__delitem__
用于索引操作,如字典。以上分别表示获取、设置、删除数据
1 #!/usr/bin/env python 2 # coding=utf-8 3 class Foo: 4 def __init__(self, name, age): 5 self.name = name 6 self.age = age 7 def __str__(self): 8 # print 对象时,自动执行该方法 9 return ‘%s---%s‘ % (self.name, self.age) 10 def __getitem__(self, item): 11 if type(item) == slice: 12 print(item.start) 13 print(item.stop) 14 print(item.step) 15 elif type(item) == str: 16 print(item) 17 def __setitem__(self, key, value): 18 # print(type(key), type(value)) 19 if type(key) == slice: 20 print(key,value) 21 def __delitem__(self, key): 22 print(type(key)) 23 test1 = Foo(‘hexm‘, 18) 24 test1[‘sb‘] # 执行__getitem__ 字符串类型 25 test1[1:3:1] # 执行__getitem__ slice类型 26 test1[‘k1‘] = ‘hexm‘ # 执行 __setitem__ 27 test1[1:4] = [1, 2, 3, 4] 28 del test1[‘k1‘] # 执行 __delitem__ 29 del test1[1:4]
9.__iter__
用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了__iter__
1 #!/usr/bin/env python 2 # coding=utf-8 3 class Foo: 4 def __iter__(self): 5 return iter([1, 2, 3, 4]) 6 test = Foo() 7 # 把对象放到for循环中,会自动执行__iter__方法, 返回的值得可迭代对象 8 for item in test: 9 print(item)
10. __add__, __del__
在类中定义__add__, __del__时,执行两个对象相加,执行__add__,两个对象相减,执行__del__
1 def __add__(self, lover): 2 xxx
11. issbuclass, isinstance
1 #!/usr/bin/env python 2 # coding=utf-8 3 class Foo: 4 def __iter__(self): 5 return iter([1, 2, 3, 4]) 6 7 class Fo(Foo): 8 pass 9 test = Foo() 10 # 对象是否属于某个类 11 ret = isinstance(test, Foo) 12 print(ret) 13 ret = isinstance(test, Fo) 14 print(ret) 15 # 一个类是否是另一个类的子类 16 ret = issubclass(Fo, Foo) 17 print(ret)
12.__enter__
当python使用with-as语法,就会调用__enter__函数,然后把函数的return值传给as后指定的变量。然后执行with-as下的语句,无论出现了什么异常,都会在离开时执行__exit__。
为了让一个对象兼容with语句,需要实现__enter__()和__exit__()方法。
1 from socket import socket, AF_INET, SOCK_STREAM 2 class LazyConnection: 3 def __init__(self, address, family=AF_INET, type=SOCK_STREAM): 4 self.address = address 5 self.family = family 6 self.type = type 7 self.connections = [] 8 def __enter__(self): 9 sock = socket(self.family, self.type) 10 sock.connect(self.address) 11 self.connections.append(sock) 12 return sock 13 def __exit__(self, exc_ty, exc_val, tb): 14 self.connections.pop().close() 15 # Example use 16 from functools import partial 17 conn = LazyConnection((‘www.python.org‘, 80)) 18 with conn as s1: 19 pass 20 with conn as s2: 21 pass 22 # s1 and s2 are independent sockets
面向对象(二)