zoukankan      html  css  js  c++  java
  • Python学习笔记

    写在前面

    每种语言都有各自的特性,适用的场景也有差别,比如C/C++常用于高性能环境中,而Java常用于网络应用程序,Python给人的感觉有点想Shell等脚本语言,能快速开发出程序,关键是在Windows、Linux、Mac上基本上都是有安装Python的。

    这篇是学习笔记,主要用来记录在用Python编程时需要注意的地方。下面来看一些非常常用的操作:

    isinstance:判断obj是否为对应类型的实例

    type:获取obj的类型

    dir:获取所有的属性和方法

    callable:对象是否可以执行

    基础

    字符串编码问题

    在python 2.x中使用的str实际是字节码,是Unicode经过编码后的字节组成的序列,简单的验证方法是通过print len('我')输出3(utf-8编码中汉字有三个字节)得到验证,str和Unicode都是basestring的子类,而Unicode才是真正意义上的字符串,即printf len(u'我')的结果为1。

    另外在有中文的python源文件上有加注释来说明编码:# coding: UTF-8

    在python中打开文件读取到的内容实际上是str,而不是unicode(这样实现更合理),如果要当做字符串处理的话要自己encode。

    数据集合

    提供了list(可变有序列表)、tuple(不可变的列表)、dict(字典)、set(集合)等能快速使用的数据结构,在根据下标访问时传入负数不会报错,比如list[-1]在实际上得到的是最后一个元素。在初始化时集合中的数据可以是任意的,不需要一致:

    s = ['python', 'java', ['asp', 'php'], 'scheme']

    在python中有很多截取、生成列表的例子,这也算是一个比java、c灵活快捷的地方:

    [x * x for x in range(1, 11)]                  # 从1到10的平方的数组
    [x * x for x in range(1, 11) if x % 2 == 0]    # 可以增加条件
    [m + n for m in 'ABC' for n in 'XYZ']          # 甚至嵌套循环
    
    list[0:3]    # 取list前3个元素
    list[:3]     # 同上,第一个是0则可以省略不写
    list[-3:]    # 取list后3个元素
    list[::3]    # 每3个取一个
    list[:]      # 复制一个list
    

    这样生成的数据是占用内存的,有时候这样的代价太大,这便有了generator,它只保存了逻辑,不存储数据。generator的初始化方法只是简单的将上面的中括号变成括号即可:

    g = (x * x for x in range(10))

    而在访问generator是使用g.next()来完成,当然也可以使用for...in...的方式。

    函数和逻辑控制

    在python中比较蛋疼的是通过缩进来控制逻辑控制语句、函数的范围,写不好就错了,比如if语句你要写成:

    if a > 0 :
        print 1
        print 2 # 如果这一行没有缩进的话a < 2也能输出来了

    和c的函数指针有点类似的是python中的函数也可以传递,比如在用sorted对列表实现倒序排序时将比较函数当做参数传进去:

    def cmp(x, y) : 
        return y - x;
    sorted([1, 2, 3, 4], cmp);

    同样的方法也可以作为返回值。lambda函数使得这种用法更爽(虽然python对lambda的支持有限,只有在简单情况下此案呢过使用),上面三行有一行就可以搞定了:

    sorted([1, 2, 3], lambda x,y:y-x);

    调用函数的地方传递参数并不一定要跟函数声明时的顺序保持一致,只要你讲清楚具体是哪个传给哪个就可以了,举个例子,申明一个函数为func(a, b),在调用是可以是:

    func(b=1,a=2) 等价于 func(2, 1)

    在很多的python代码中会看到func(*args, **kwargs)类型的参数,那么可以猜到第一个为正常方式传入的,第二种为key-value方式传入的。在参数比较多的函数调用时比较麻烦,因为大部分参数在大部分场景下是相同的,在Java/C中的方法是重新声明一个函数,而在python中进一步简化(需要functools模块):

    int2 = functools.partial(int, base=2)

    另外Spring中的AOP很好用吧?这里也有了类似的写法:

    def log(func):
        def wrapper(*args, **kw):
            print 'call %s():' % func.__name__
            return func(*args, **kw)
        return wrapper
    
    @log
    def now():
        print '2013-12-25'
    

    模块

    把所有的代码写在一个文件里面很不显示,python通过模块的方式来组织,声明的方法如下:

    mycompany(一个模块就是一个目录

    __init__.py让解释器将该目录当成模块

    xxx.py(模块中的内容

    用import引入之后就可以使用xxx功能了。

    面向对象编程

    在申明类型时跟函数一样,需要用缩进来标记出来属于该类的代码的范围,最简单的例子:

    class Student :
    	def __init__(self, name, score): # 构造函数
    		self.name = name
    		self.score = score
    

    在使用时s = Student()即可得到一个实例,python中的继承与Java/C++稍有不同:class Student(Person) 。类是属性和方法的封装体,自然并不是所有的属性都能被访问,在python中比较“牛逼”的地方是用两个下划线来将属性保护起来:

    s.__name

    访问的时候会出错~ 使用时可以“随意”地给类型、实例添加属性和方法,给obj添加属性很简单:s.age=18,给class添加方法之后,所有的实例中都可以访问了:

    Student.set_score = MethodType(set_score, None, Student)

    很多时候我们并不希望大家随意地添加属性,那么可以通过__slots__ = ('name', 'age')来进行限制,需要注意的是该方法对子类并不起作用。用函数的方式设置和读取看起来比较麻烦,在python又做了一次改进,通过注解将对属性的访问映射到函数上:

    class Student(object):
        @property
        def score(self):
            return self._score
        @score.setter
        def score(self, value):
    	self._score = value
    

    从次可以用s.score=2来调用score(self,value)方法,这个想法很不错,但是貌似这样写完会把代码搞乱掉的,让调用者看得云里雾里。为了将输出更优化在Java中建议重写toString方法,同样目的,在python中建议重写__str____repr__方法,另外可以做出一些额外的定制:

    __getattr__:从obj中获取不到属性时,会尝试调用该方法,如果不重写的话会直接抛出AttributeError

    __call__:使obj可以像函数一样执行

    __getitem__:用来支持obj[0]这种下标的方式获取数据

    __iter__:用来支持for .... in这种循环遍历

    后面两种有点像C++里面的运算符重载,感觉应用的场景很少。在Java中可以使用cglib等产生新的类型,Python中的type()也提供了类似的功能:

    type('Hello', (object,), dict(hello=fn))

    其中,第一个参数是class的名称,第二个参数是父类的集合,第三个参数是将方法名称(hello)和函数(fn)绑定。另外一种创建类型的方法是metaclass,来看一个例子,看不懂就算了:

    # metaclass是创建类,所以必须从`type`类型派生:
    class ListMetaclass(type):
        def __new__(cls, name, bases, attrs):
            attrs['add'] = lambda self, value: self.append(value)
            return type.__new__(cls, name, bases, attrs)
    
    class MyList(list):
        __metaclass__ = ListMetaclass # 指示使用ListMetaclass来定制类
    

    在用到对象的地方一般都会涉及到序列化,python通过pickle.dumpspickle.loads来完成序列化和反序列化,还有问题是对象与JSON格式的字符串进行互相转换,可以使用json.dump来变成JSON,不过它并不认识你自己定义的类型,需要用指定一个函数来完成,简单做法如下:

    print(json.dumps(s, default=lambda obj: obj.__dict__))

    而在从JSON变成对象的时候需要指定object_hock方法用来根据dict生成对象:

    json.loads(json_str, object_hook=dict2student)

    进程、线程、协程

    创建进程与C一样:os.fork(),如果是父进程的话返回子进程ID,如果是子进程的话返回0。另外还可以通过multiprocessing模块创建进程:

    Process(target=run_proc, args=('test',))

    如果要创建大量子进程可以用Pool的方式批量创建:

    p = Pool()
    for i in range(5):
            p.apply_async(long_time_task, args=(i,))

    进程间的通信可以通过QueuePipes来做。Python进程的一个牛逼之处是可以使用managers模块方便地做分布式进程。

    Python中的线程是真正的Posix Thread,但不幸的是解释器执行代码时有一个GIL锁,任意Python线程执行前必须获取GIL锁,导致的结果就是多线程不能有效地利用多核优势,不管怎么样看下线程的用法:

    t = threading.Thread(target=run_thread, args=(5,))  # 创建线程
    t.start()  # 开始执行
    lock = threading.Lock()  # 创建锁
    lock.acquire()  # 获取锁
    // todo
    lock.release()  # 释放锁

    Java中的ThreadLocal很好用吧,Python也有(感觉都是抄来抄去),用法基本上一样:

    local_school = threading.local()  # 创建ThreadLocal变量
    local_school.student = 123  # 绑定属性

    其他的基础方面的还有网络编程,但是这部分和Java/C太像了,这里就不写了。

    数学计算

    毫无疑问在搞机器学习计算的最好工具是Matlab,但是作为一个程序员比较排斥这种东西,更愿意自己写代码来做,但是不用现成的模块的话代码量巨大,所以这里介绍几种常用的Python中数值计算的工具。

    NumPy

    该模块可以搞定大部分的矩阵中的运算,在官网中的文档看起来要比大部分的翻译轻松很多,它所支持的功能可以在这里查看,如果访问不了可以试试这个

    SciPy

    用来支持最优化、线性代数、积分、插值等,和NumPy的有一定的重复,在这里可以用具体用法,如果访问不了可以试试这个

    SymPy

    纯python实现的符号运算器,感觉很强大,但是我实际上还没用到,因为都是自己在推公式,感兴趣可以在官网了解。

    matplotlib

    一个画图工具,为什么需要画图?你运算的结果或者模型在你脑子里面是清楚的,但是你要跟人家展示啊,官网学习中。

    实战

  • 相关阅读:
    开源项目
    [Accessibility] Missing contentDescription attribute on image [可取行]失踪contentDescription属性图像
    Android 布局 中实现适应屏幕大小及组件滚动
    EF 错误记录
    EasyUI 加载时需要显示和隐藏 panel(面板)内容破版问题
    IE 报表缩放后页面破版
    VS 2017 引入nuget 问题
    SSRS 报表显示页面 asp net session丢失或者找不到 asp net session has expired or could not be found()
    log4net 配置
    网站
  • 原文地址:https://www.cnblogs.com/antispam/p/4018452.html
Copyright © 2011-2022 走看看