面向对象、异常处理、反射、单例模式

类方法中的self:

  代指调用该方法的对象,可以借此传入各种属性在各方法中使用。

 1 class Foo:
 2     def __init__(self, name):
 3         self.name = name
 4 
 5     def foo(self):
 6         print(self, self.name, self.age)
 7 
 8 f = Foo('yangxl')
 9 f.age = 28
10 f.foo()

面向对象三大特性之一,封装:

  把变量放到对象中,使用的时候直接从对象中取。

 1 class Bar:
 2     def foo(self, arg):
 3         print(self, self.name, self.age, self.gender, arg)
 4 
 5 z = Bar()
 6 z.name = 'yangxl'  # 封装
 7 z.age = 28
 8 z.gender = 'male'
 9 z.foo(666)
10 
11 z1 = Bar()
12 z1.name = 'eric'
13 z1.age = 73
14 z1.gender = 'female'
15 z1.foo(666)

构造函数:

  __init__,把属性封装到函数中。

 1 class Bar:
 2     def __init__(self, name, age, gender):
 3         self.name = name
 4         self.age = age
 5         self.gender = gender
 6 
 7     def foo(self, arg):
 8         print(self, self.name, self.age, self.gender, arg)
 9 
10 z = Bar('yangxl', 28, 'male')
11 z.foo(666)

三大特征之二,继承:

  需要注意的一个问题,子类对象调用父类中的方法,父类方法中的self是指子类对象还是父类对象?子类对象

 1 class F:
 2     def f1(self):
 3         print(self, 'F.f1')
 4 
 5 class S(F):
 6     def s1(self):
 7         print(self, 'S.s1')
 8 
 9 obj = S()
10 obj.s1()  # s1中的self是形参,此时代指 obj
11 obj.f1()  # f1中的self仍是obj, self用于指调用方法的调用者
12 # <__main__.S object at 0x0000020AF533BAC8> S.s1
13 # <__main__.S object at 0x0000020AF533BAC8> F.f1

  多继承:

    1. 左侧父类优先

    2. 采用一条路走到黑的策略。

    

 1 class F0:
 2     def a(self):
 3         print('F0.a')
 4 
 5 class F1(F0):
 6     def a1(self):
 7         print('F1.a')
 8 
 9 class F2:
10     def a1(self):
11         print('F2.a')
12 
13 class S(F1, F2):
14     pass
15 
16 obj = S()
17 obj.a()  # F0.a  采用一条路走到黑的策略

  父类有交叉:

    3. 先找各条支线,最后找交叉。

    

 1 class Base:
 2     def a(self):
 3         print('Base.a')
 4 
 5 class F0(Base):
 6     def a1(self):
 7         print('F0.a')
 8 
 9 class F1(F0):
10     def a1(self):
11         print('F1.a')
12 
13 class F2(Base):
14     def a1(self):
15         print('F2.a')
16 
17 class S(F1, F2):
18     pass
19 
20 obj = S()
21 obj.a()  # Base.a

  小练习:

  多继承,

 1 class Foo1:
 2     print('foo1')
 3 
 4 class Foo2:
 5     print('foo2')
 6 
 7 class Foo3(Foo1, Foo2):
 8     print('foo3')
 9 
10 f = Foo3()
11 # foo1
12 # foo2
13 # foo3
 1 class RequestHandler:
 2     def serve_forever(self):
 3         # self,是obj
 4         print('RequestHandler.serve_forever')
 5         self.process_request()  # 这里执行的是Minx中的process_request方法,只要时刻注意self是谁就不容易出错。
 6 
 7     def process_request(self):
 8         print('RequestHandler.process_request')
 9 
10 class Minx:
11     def process_request(self):
12         print('minx.process_request')
13 
14 class Son(Minx, RequestHandler):
15     pass
16 
17 obj = Son()
18 obj.serve_forever()
19 # RequestHandler.serve_forever
20 # minx.process_request

三大特性之三,多态:

  函数只接受指定类及其子类的对象作为参数。python原生多态。

 1 class Foo:
 2     pass
 3 
 4 class Son(Foo):
 5     pass
 6 
 7 def func(Foo arg):  # 只接受Foo类及其子类的对象作为参数
 8     print(arg)
 9 
10 obj = Son()
11 func(obj)

类的成员:

  字段:

    普通字段:创建对象时定义

    静态字段:创建类时定义;

         应用场景是当多个对象的某属性相同时如果创建普通字段会在每个对象上保存一份数据,占用不必要的内存空间,如果创建为静态字段可以只保存一份,而且容易修改。

 1 class Province:
 2     # 静态字段,属于类
 3     country = '中国'
 4 
 5     def __init__(self, name):
 6         # 普通字段,属于对象
 7         self.name = name
 8 
 9 henan = Province('河南')
10 hebei = Province('河北')

  方法:

    普通方法:

    静态方法:@staticmethod,不必再传self;可以让类直接调用方法,不必再创建对象作为中介。

    类方法:@classmethod;与静态方法没有多大区别。

 1 class Foo:
 2     def __init__(self):
 3         self.name = 'a'
 4 
 5     def bar(self):
 6         # self是对象
 7         print('bar')
 8 
 9     @staticmethod
10     def sta():
11         print('123')
12 
13     @staticmethod
14     def stat(a1, a2):
15         print(a1, a2)
16 
17     @classmethod
18     def classmd(cls):
19         # cls 是类名
20         print(cls)
21 
22 Foo.sta()
23 Foo.stat(1, 2)
24 Foo.classmd()

  属性:@property

 1 class Foo:
 2     def __init__(self):
 3         self.name = 'a'
 4         # obj.name
 5 
 6     # 用于执行 obj.per
 7     @property
 8     def perr(self):
 9         return 123
10 
11     # obj.per = 123
12     @perr.setter
13     def perr(self, val):  # 函数名相同
14         print(val)
15 
16     @perr.deleter
17     def perr(self):
18         print(666)
19 
20 obj = Foo()
21 r = obj.perr
22 print(r)
23 
24 obj.perr = 123
25 
26 del obj.perr

    属性的另一种表示方法:

 1 class Foo:
 2     def f1(self):
 3         return 123
 4 
 5     def f2(self, v):
 6         print(v)
 7 
 8     def f3(self):
 9         print('del')
10 
11     per = property(fget=f1, fset=f2, fdel=f3, doc='adfasdfasdfasdf')
12 
13     # @property
14     # def per(self):
15     #     return 123
16 
17 obj = Foo()
18 ret = obj.per
19 print(ret)
20 
21 obj.per = 123456
22 
23 del obj.per

  第三种表示方法:

 1 class Func:
 2     def __init__(self):
 3         self.a = 1
 4         self.b = 2
 5 
 6     def is_npc():  # 不传入self
 7 
 8         def fget(self):
 9             return self.a
10 
11         def fset(self, value):
12             print('fset')
13             pass
14 
15         def fdel(self):
16             print('fdel')
17             pass
18         return locals()  # 返回定义的方法给property
19     is_npc = property(**is_npc())
20 
21 f = Func()
22 print(f.is_npc)
23 f.is_npc = 4
24 del f.is_npc

  示例:把UserM._attrs_class的键值对加到UserL上

 1     def foo(atr):
 2         doc = "The foo property."
 3         def fget(self):
 4             return getattr(self.user_m, atr)
 5         def fset(self, value):
 6             setattr(self.user_m, atr, value)
 7         # def fdel(self):
 8         #    del self.__dict__[atr]
 9         return {
10             'doc': doc,
11             'fget': fget,
12             'fset': fset,
13         #    'fdel': fdel,
14         }
15     # property_keys = UserM._attrs_class.keys()  # py2
16     property_keys = list(UserM._attrs_class.keys())  # py3
17     property_keys.extend([
18         'food_pool_max', 'metal_pool_max', 'energy_pool_max'
19     ])
20     special_property = ['uid', 'exp', 'action_point']
21     for atr in property_keys:
22         if atr in special_property:
23             continue
24         locals()[atr] = property(**foo(atr))
25     del atr  # 删除最后一次循环的值

成员修饰符:

  共有成员:

  私有成员:__字段名 (双下划线);无法在外部直接访问,只能间接访问;即使子类对象也不行。

    私有普通字段,

 1 class Foo:
 2     def __init__(self, name, age):
 3         self.name = name
 4         # self.age = age
 5         self.__age = age  # 私有,外部无法直接访问
 6 
 7     def show(self):
 8         return self.__age
 9 
10 obj = Foo('yangxl', 19)
11 print(obj.name)
12 # print(obj.__age)
13 
14 ret = obj.show()
15 print(ret)

    私有静态字段,

 1 class Foo:
 2     __v = '123'
 3 
 4     def __init__(self):
 5         pass
 6 
 7     def show(self):
 8         return Foo.__v
 9 
10     @staticmethod
11     def stat():
12         return Foo.__v
13 
14 # print(Foo.__v)  # No
15 
16 ret = Foo().show()
17 # print(ret)
18 
19 ret = Foo.stat()
20 print(ret)
21 
22 print(Foo.stat())

    私有方法,

 1 class Foo:
 2     def __f1(self):
 3         return 123
 4 
 5     def f2(self):
 6         r = self.__f1()
 7         return r
 8 
 9 obj = Foo()
10 ret = obj.f2()
11 print(ret)

    当然,属性也可以这么搞。

 1 class F:
 2     def __init__(self):
 3         self.ge = 123
 4         self.__gene = 123
 5 
 6     def show(self):
 7         print(self.__gene)
 8 
 9 class S(F):
10     def __init__(self, name):
11         self.name = name
12         self.__age = 18
13         super(S, self).__init__()
14 
15     # def show(self):
16     #     print(self.name)
17     #     print(self.__age)
18     #     print(self.ge)
19     #     # print(self.__gene)  # 不能访问父类中的私有成员
20 
21 s = S('yangxl')
22 s.show()  # 可以通过调用父类中的共有方法,来访问父类中的私有成员。

类属性修改值:

 1 class Foo:
 2     f1 = 1
 3     def __init__(self, a):
 4         self.a = a
 5 
 6 
 7 foo1 = Foo(1)
 8 print(foo1)
 9 print(foo1.f1)  # 1
10 
11 foo1.f1 = 11
12 print(foo1.f1)  # 11
13 
14 foo2 = Foo(2)
15 print(foo2)
16 print(foo2.f1)  # 1, 并不会变成11

类的魔法方法:

__init__  类()自动执行
__del__  析构方法,对象被销毁时自动执行
__call__  对象()  类()() 自动执行
__int__   int(对象)
__str__     str()
__add__
__dict__      讲对象中封装的所有内容通过字典的形式返回
__getitem__   切片(slice类型)或者索引
__setitem__
__delitem__
__iter__
    如果类中有 __iter__ 方法,对象=》可迭代对象
    对象.__iter__() 的返回值: 迭代器
    for 循环,迭代器,next
    for 循环,可迭代对象,对象.__iter__(),迭代器,next
    1、执行li对象的类F类中的 __iter__方法,并获取其返回值
    2、循环上一步中返回的对象
 
  __init__,__call__,
 1 class Foo:
 2     def __init__(self):
 3         print('init')
 4 
 5     def __call__(self, *args, **kwargs):
 6         print('call')
 7 
 8 obj = Foo()
 9 obj()
10 # Foo()()

  __str__,__int__,

1 s = "123"  # 相当于s = str('123'),内部调用了__str__()
2 
3 i = int(s)  # 内部调用了__int__()
4 print(i, type(i))

  注意,__dict__后没有括号,不包括父类

 1 class Foo:
 2     father = 'daa'
 3     def __init__(self, name, age):
 4         self.name = name
 5         self.__age = age
 6 
 7 
 8 # print(Foo.__dict__)  # py2和py3有稍许不同;不包括父类属性
 9 # {'__dict__': <attribute '__dict__' of 'Foo' objects>, '__module__': '__main__', '__doc__': None, '__init__': <function Foo.__init__ at 0x7f7e6d446840>, 'father': 'daa', '__weakref__': <attribute '__weakref__' of 'Foo' objects>}
10 # print Foo.__dict__
11 # {'__module__': '__main__', 'father': 'daa', '__doc__': None, '__init__': <function __init__ at 0x7f1961f53668>}
12 
13 
14 
15 foo = Foo('yangxl', 26)
16 # print(foo.__dict__)
17 print foo.__dict__
18 # {'name': 'yangxl', '_Foo__age': 26}  # 也会显示私有成员,但不包含类属性

  __getitem__,__setitem__,__delitem__,还可做切片操作,

 1 class Foo:
 2     def __init__(self, name,age):
 3         self.name = name
 4         self.age = age
 5 
 6     def __getitem__(self, item):
 7         return item+10
 8 
 9     def __setitem__(self, key, value):
10         print(key, value)
11 
12     def __delitem__(self, key):
13         print(key)
14 
15 li = Foo('alex', 18)
16 r = li[8]  # 自动执行li对象的类中的 __getitem__方法,8当作参数传递给item
17 print(r)
18 
19 li[100] = "asdf"
20 
21 del li[999]
22 ######################
23 class Foo:
24     def __init__(self, name, age):
25         self.name = name
26         self.age = age
27 
28     def __getitem__(self, item):
29         # 如果item是基本类型:int,str,索引获取
30         # slice对象的话,切片
31         if type(item) == int:
32             print('调用这希望内部做切片处理')
33         else:
34             print(item.start)
35             print(item.stop)
36             print(item.step)
37             print('调用这希望内部做索引处理')
38 
39     def __setitem__(self, key, value):
40         print(key, value)
41 
42     def __delitem__(self, key):
43         print(key)
44 
45 li = Foo('alex', 18)
46 li[123]
47 li[1:4:2]
48 
49 li[1:3] = [11, 22]
50 
51 del li[1:3]

  __iter__,

1 li = [11, 22, 33, 44]
2 li = list([11, 22, 33, 44])
3 for item in li:
4     print(item)

metaclass:

  python中一切皆对象,类也是对象,是type的对象。

  下面创建一个元类模拟foo对象创建的真实过程,

 1 class MyType(type):
 2     def __init__(self, *args, **kwargs):
 3         # self=Foo
 4         print(123)
 5         pass
 6 
 7     def __call__(self, *args, **kwargs):
 8         # self=Foo
 9         r = self.__new__(*args, **kwargs)
10      self.__init__(r)
11 
12 class Foo(object,metaclass=MyType):
13     def __init__(self):
14         pass
15 
16     def __new__(cls, *args, **kwargs):
17         return '对象'
18 
19     def func(self):
20         print('hello wupeiqi')
21 
22 obj = Foo()

  执行过程如下:

    

异常处理:

  except与else执行其一。

 1 try:
 2     li = [11, 22]
 3     li[1]
 4     int('w3r')
 5 except IndexError as e:
 6     print('IndexError', e)
 7 except ValueError as e:
 8     print('ValueError', e)
 9 except Exception as e:
10     print('Exception', e)
11 else:
12     ret = 1
13     print('elese')
14 finally:
15     print('....')

  主动抛出异常,raise:

    注意,raise抛出的异常还是需要except来处理。

1 try:
2     # int('asdf')
3     # 主动出发异常
4     raise Exception('不过了...')
5 except Exception as e:
6     print(e)
7 
8 # 不过了...

  自定制异常:

 1 class MyError(Exception):
 2     def __init__(self, msg):
 3         self.message = msg
 4 
 5     def __str__(self):
 6         return self.message
 7 
 8 try:
 9     raise MyError('我错了...')
10 except MyError as e:
11     print(e)  # e对象的__str__()方法,获取返回

  断言,assert:

    用于强制用户服从,不服从就报错,可捕获(try),一般不捕获。

1 print(23)
2 assert 1 == 2  # AssertionError
3 print(456)  # assert报错后,下面不执行

    断言比逻辑运算符的优先级低,

1 assert loop is None or isinstance(loop, AbstractEventLoop)  # _UnixSelectorEventLoop和AbstractEventLoop隔着好几代呢

    断言添加解释性信息,

1 >>> assert []
2 Traceback (most recent call last):
3   File "<stdin>", line 1, in <module>
4 AssertionError
5 >>> 
6 >>> assert [], 'no'
7 Traceback (most recent call last):
8   File "<stdin>", line 1, in <module>
9 AssertionError: no

反射:

  通过字符串的形式操作对象成员,对象可以是模块,成员可以是一个对象可调用的非私有属性、方法等。

  getattr,hasattr,setattr,delattr,

 1 class Foo:
 2     def __init__(self, name,age):
 3         self.name = name
 4         self.age = age
 5 
 6     def show(self):
 7         return  "%s-%s " %(self.name,self.age)
 8 
 9 obj = Foo('yangxl', 18)
10 ret = getattr(obj, 'name')
11 print(ret)
12 
13 print(hasattr(obj, 'name'))
14 
15 setattr(obj, 'k1', 'v1')
16 print(obj.k1)
17 
18 func = getattr(obj, 'show')
19 r = func()
20 print(r)

  反射在模块调用中的应用,

# s2.py

NAME = 'dandan'

def func():
    return 'func'

class Foo:
    def __init__(self):
        self.name = 123
########################

# s1.py

import s2

r1 = getattr(s2, 'NAME')
print(r1)

r2 = getattr(s2, 'func')
result = r2()
print(result)

cls = getattr(s2, 'Foo')
print(cls)

isinstance:

1 assert isinstance(delegate, httputil.HTTPServerConnectionDelegate)  # httputil.HTTPServerConnectionDelegate为httpserver.HTTPServer的三个父类之一

与type(None)联用,

1 _TO_UNICODE_TYPES = (str, type(None))
2 isinstance(value, _TO_UNICODE_TYPES)

issubclass:

1 issubclass(cls, UIModule)  # cls 继承UIModule

type创建类

1 def func(self, a):
2     return a
3 
4 Foo = type('Fo', (object,), {'f1': func})
5 f = Foo()
6 print(Foo.__name__)  # 'Fo'
7 print(f.f1(345))

单例模式:

 1 class Foo:
 2     __v = None
 3 
 4     @classmethod
 5     def get_instance(cls):
 6         if cls.__v:
 7             return cls.__v
 8         else:
 9             cls.__v = Foo()
10             return cls.__v
11 
12 # 不要在使用 类()
13 obj1 = Foo.get_instance()
14 print(obj1)
15 obj2 = Foo.get_instance()
16 print(obj2)
17 obj3 = Foo.get_instance()
18 print(obj3)

  应用场景:

    只创建一个实例,节省空间。

    数据库连接池

      原理:在系统初始化的时候,将数据库连接作为对象存储在内存中,当用户需要访问数据库时,并非建立一个新的连接,而是从连接池中取出一个已建立的空闲连接对象。使用完毕后,用户也并非将连接关闭,而是将连接放回连接池中,以供下一个请求访问使用。

# tornado中的IOloop
class IOLoop():
    @staticmethod
    def instance():
        if not hasattr(IOLoop, "_instance"):
            with IOLoop._instance_lock:
	        if not hasattr(IOLoop, "_instance"):
		    IOLoop._instance = IOLoop()
        return IOLoop._instance

参考:http://www.cnblogs.com/wupeiqi/p/4766801.html

原文地址:https://www.cnblogs.com/yangxiaoling/p/6843096.html