首页 > 代码库 > 面向对象(二)

面向对象(二)

类的成员

类的成员可以分为三大类:字段、方法和属性

技术分享

一、字段

字段包括普通字段和静态字段,他们在定义和使用中有所区别,最本质的区别是内存中保存的位置不同。

  • 普通字段属于对象,在内存中为每个对象保存一份
  • 静态字段属于类,在内存中只保存一份

一般情况下,自己访问自己字段,普通字段只能使用对象访问,静态字段使用类访问(最好不要用对象访问静态字段),静态字段在代码加载时创建。

技术分享
 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

相同点:对于所有的方法而言,均属于类(非对象)中,所以,在内存中也只保存一份。

不同点:方法调用者不同、调用方法时自动传入的参数不同。

三、属性

属性定义有两种方式

  1. 装饰器 在方法上应用装饰器
    技术分享View Code
  2. 静态字段 在类中定义为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
    View Code

类成员修饰符

对于每一个类的成员而言都有两种形式:

  • 公有成员,在任何地方都能访问
  • 私有成员,只有在类的内部才能方法
技术分享
 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()  # 错误
View Code

类的特殊成员

上面介绍了Python的类成员以及成员修饰符,从而了解到类中有字段、方法和属性三大类成员,并且成员名前如果有两个下划线,则表示该成员是私有成员,私有成员只能由类内部调用。无论人或事物往往都有不按套路出牌的情况,Python的类成员也是如此,存在着一些具有特殊含义的成员,详情如下:

1. __doc__

  表示类的描述信息

技术分享
1 class Foo:
2     """ 描述类信息 """
3 
4     def func(self):
5         pass
6 
7 print Foo.__doc__
View Code

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
lib/a.py
技术分享
1 from lib.aa import C
2 
3 obj = C()
4 print obj.__module__  # 输出 lib.aa,即:输出模块
5 print obj.__class__      # 输出 lib.aa.C,即:输出类
index.py

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
View Code

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__)
View Code

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)
View Code

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]
View Code

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)
View Code

10. __add__, __del__

在类中定义__add__, __del__时,执行两个对象相加,执行__add__,两个对象相减,执行__del__

技术分享
1 def __add__(self, lover):
2     xxx
View Code

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)
View Code

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
View Code

 

面向对象(二)