类方法中的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
类的魔法方法:
__del__ 析构方法,对象被销毁时自动执行
__call__ 对象() 类()() 自动执行
__int__ int(对象)
__str__ str()
__dict__ 讲对象中封装的所有内容通过字典的形式返回
__getitem__ 切片(slice类型)或者索引
__setitem__
__delitem__
如果类中有 __iter__ 方法,对象=》可迭代对象
对象.__iter__() 的返回值: 迭代器
for 循环,迭代器,next
for 循环,可迭代对象,对象.__iter__(),迭代器,next
1、执行li对象的类F类中的 __iter__方法,并获取其返回值
2、循环上一步中返回的对象
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__':, '__module__': '__main__', '__doc__': None, '__init__': 10 # print Foo.__dict__ 11 # {'__module__': '__main__', 'father': 'daa', '__doc__': None, '__init__':, 'father': 'daa', '__weakref__': } } 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 "", line 1, in 4 AssertionError 5 >>> 6 >>> assert [], 'no' 7 Traceback (most recent call last): 8 File " ", line 1, in 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