【python】面向对象编程
No1:
类和实例
__init__方法的第一个参数永远是self
,表示创建的实例本身;init相当于构造函数
No2:
数据封装
No3:
如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__
,在Python中,实例的变量名如果以__
开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问
在Python中,变量名类似__xxx__
的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以,不能用__name__
、__score__
这样的变量名。
Python解释器对外把__name
变量改成了_(类名)_name
,所以,仍然可以通过_(类名)__name
来访问__name
变量;但是不同版本的Python解释器可能会把__name
改成不同的变量名。
No4:
不知道为什么拿不出值
No5:
继承
No6:
多态
No7:
No8:
判断对象类型
能用type()
判断的基本类型也可以用isinstance()
判断:
No9:
如果要获得一个对象的所有属性和方法,可以使用dir()
函数
No10:
动态给class加上功能
No11:
__slots__限制class实例能添加的属性
No12:
@property是为了s.getScore变为简单实用s.score
上面的birth
是可读写属性,而age
就是一个只读属性
No13:
多继承
No14:
定制类__str__
直接显示变量调用的不是__str__()
,而是__repr__()
No15:
用__iter__实用斐波那契
No16:
没有找到类的属性之外,可以使用__getattr__
No17:
__call__实例调用方法
No18:
枚举
@unique
装饰器可以帮助我们检查保证没有重复值。
No19:
type()
函数既可以返回一个对象的类型,又可以创建出新的类型
No20:
metaclass:先定义metaclass,就可以创建类,最后创建实例。
__new__()
方法接收到的参数依次是:
-
当前准备创建的类的对象;
-
类的名字;
-
类继承的父类集合;
-
类的方法集合。
No21:
简单的ORM框架
class Field(object): def __init__(self, name, column_type): self.name = name self.column_type = column_type def __str__(self): return '<%s:%s>' % (self.__class__.__name__, self.name)
class StringField(Field): def __init__(self, name): super(StringField, self).__init__(name, 'varchar(100)') class IntegerField(Field): def __init__(self, name): super(IntegerField, self).__init__(name, 'bigint')
class ModelMetaclass(type): def __new__(cls, name, bases, attrs): if name=='Model': return type.__new__(cls, name, bases, attrs) print('Found model: %s' % name) mappings = dict() for k, v in attrs.items(): if isinstance(v, Field): print('Found mapping: %s ==> %s' % (k, v)) mappings[k] = v for k in mappings.keys(): attrs.pop(k) attrs['__mappings__'] = mappings # 保存属性和列的映射关系 attrs['__table__'] = name # 假设表名和类名一致 return type.__new__(cls, name, bases, attrs)
class Model(dict, metaclass=ModelMetaclass): def __init__(self, **kw): super(Model, self).__init__(**kw) def __getattr__(self, key): try: return self[key] except KeyError: raise AttributeError(r"'Model' object has no attribute '%s'" % key) def __setattr__(self, key, value): self[key] = value def save(self): fields = [] params = [] args = [] for k, v in self.__mappings__.items(): fields.append(v.name) params.append('?') args.append(getattr(self, k, None)) sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(params)) print('SQL: %s' % sql) print('ARGS: %s' % str(args))
class User(Model): # 定义类的属性到列的映射: id = IntegerField('id') name = StringField('username') email = StringField('email') password = StringField('password') # 创建一个实例: u = User(id=12345, name='Michael', email='test@orm.org', password='my-pwd') # 保存到数据库: u.save()
输出如下
Found model: User Found mapping: email ==> <StringField:email> Found mapping: password ==> <StringField:password> Found mapping: id ==> <IntegerField:uid> Found mapping: name ==> <StringField:username> SQL: insert into User (password,email,username,id) values (?,?,?,?) ARGS: ['my-pwd', 'test@orm.org', 'Michael', 12345]
在ModelMetaclass
中,一共做了几件事情:
-
排除掉对
Model
类的修改; -
在当前类(比如
User
)中查找定义的类的所有属性,如果找到一个Field属性,就把它保存到一个__mappings__
的dict中,同时从类属性中删除该Field属性,否则,容易造成运行时错误(实例的属性会遮盖类的同名属性); -
把表名保存到
__table__
中,这里简化为表名默认为类名。
No22:
抓异常
使用try...except
捕获错误还有一个巨大的好处,就是可以跨越多层调用,比如函数main()
调用foo()
,foo()
调用bar()
,结果bar()
出错了,这时,只要main()
捕获到了,就可以处
也就是说,不需要在每个可能出错的地方去捕获错误,只要在合适的层次去捕获错误就可以了。这样一来,就大大减少了写try...except...finally
的麻烦
python的错误日志是从上往下看
No23:
抛异常用raise相当于java的thorws
No24:
import logging logging.basicConfig(level=logging.INFO)
logging
的好处,它允许你指定记录信息的级别,有debug
,info
,warning
,error
等几个级别
No25:
调试:l-查看代码,n-单步执行,p-查看变量的值
#err.py import pdb s='0' n=int(s) pdb.set_trace() print(10/n)
No26:
比较好的Python IDE有:
Visual Studio Code:https://code.visualstudio.com/,需要安装Python插件。
PyCharm:http://www.jetbrains.com/pycharm/
No27:
单元测试
mydict.py
class Dict(dict): def __init__(self,**kw): super().__init__(**kw) def __getattr__(self,key): try: return self[key] except KeyError: raise AttributeError(r"'Dict' object has no attribute '%s'" % key) def __setattr__(self,key,value): self[key]=value
mydict_test.py
import unittest from mydict import Dict class TestDict(unittest.TestCase): def test_init(self): d = Dict(a=1,b='test') self.assertEqual(d.a,1) self.assertEqual(d.b,'test') self.assertTrue(isinstance(d,dict)) def test_key(self): d = Dict() d['key']='value' self.assertEqual(d.key,'value') def test_attr(self): d = Dict() d.key = 'value' self.assertTrue('key' in d) self.assertEqual(d['key'],'value') def test_keyerror(self): d = Dict() with self.assertRaises(KeyError): value = d['empty'] def test_attrerror(self): d = Dict() with self.assertRaises(AttributeError): value = d.empty def setUp(self): print('setUp...') def tearDown(self): print('tearDown...')
运行结果
No28:
文档测试
class Dict(dict): ''' Simple dict but also support access as x.y style. >>> d1 = Dict() >>> d1['x'] = 100 >>> d1.x 100 >>> d1.y = 200 >>> d1['y'] 200 >>> d2 = Dict(a=1, b=2, c='3') >>> d2.c '3' >>> d2['empty'] Traceback (most recent call last): ... KeyError: 'empty' >>> d2.empty Traceback (most recent call last): ... AttributeError: 'Dict' object has no attribute 'empty' ''' def __init__(self, **kw): super(Dict, self).__init__(**kw) def __getattr__(self, key): try: return self[key] except KeyError: raise AttributeError(r"'Dict' object has no attribute '%s'" % key) def __setattr__(self, key, value): self[key] = value if __name__=='__main__': import doctest doctest.testmod()
当模块正常导入时,doctest不会被执行。只有在命令行直接运行时,才执行doctest。所以,不必担心doctest会在非测试环境下执行
No29:
读文件
f = open('/Users/michael/test.txt', 'r') f.read() f.close() with open('/path/to/file', 'r') as f: print(f.read())
非UTF-8编码的文本文件
f = open('/Users/michael/gbk.txt', 'r', encoding='gbk') f.read() f = open('/Users/michael/gbk.txt', 'r', encoding='gbk', errors='ignore')
写文件
f = open('/Users/michael/test.txt', 'w') f.write('Hello, world!') f.close() with open('/Users/michael/test.txt', 'w') as f: f.write('Hello, world!')
No30:
StringIO读写
>>> from io import StringIO >>> f = StringIO() >>> f.write('hello') 5 >>> f.write(' ') 1 >>> f.write('world!') 6 >>> print(f.getvalue()) hello world! >>> from io import StringIO >>> f = StringIO('Hello!\nHi!\nGoodbye!') >>> while True: ... s = f.readline() ... if s == '': ... break ... print(s.strip()) ... Hello! Hi! Goodbye!
BytesIO读写
>>> from io import BytesIO >>> f = BytesIO() >>> f.write('中文'.encode('utf-8')) 6 >>> print(f.getvalue()) b'\xe4\xb8\xad\xe6\x96\x87' >>> from io import BytesIO >>> f = BytesIO(b'\xe4\xb8\xad\xe6\x96\x87') >>> f.read() b'\xe4\xb8\xad\xe6\x96\x87'
No31:
操作文件
# 查看当前目录的绝对路径: >>> os.path.abspath('.') '/Users/michael' # 在某个目录下创建一个新目录,首先把新目录的完整路径表示出来: >>> os.path.join('/Users/michael', 'testdir') '/Users/michael/testdir' # 然后创建一个目录: >>> os.mkdir('/Users/michael/testdir') # 删掉一个目录: >>> os.rmdir('/Users/michael/testdir')
拆分路径
>>> os.path.split('/Users/michael/testdir/file.txt') ('/Users/michael/testdir', 'file.txt')
扩展名
>>> os.path.splitext('/path/to/file.txt') ('/path/to/file', '.txt')
# 对文件重命名: >>> os.rename('test.txt', 'test.py') # 删掉文件: >>> os.remove('test.py')
No32:
要列出所有的.py
文件
>>> [x for x in os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1]=='.py'] ['apis.py', 'config.py', 'models.py', 'pymonitor.py', 'test_db.py', 'urls.py', 'wsgiapp.py']
No33:
序列化
No34:
JSON和python对比
No35:
类转为json
json转为类