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

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

    实战

  • 相关阅读:
    CSS调整DIV最小高度问题
    Ubuntu不再支持从Windows安装
    在控制面板里面找不到“添加或删除程序”
    根据IP定位用户所在城市信息
    jQuery 文档操作 remove() 方法
    基于jQuery+JSON的省市联动效果
    移动端网页实现拨打电话功能的几种方法
    NetBeans 时事通讯(刊号 # 36 Nov 26, 2008)
    有关3S产业前景的一些思考
    NetBeans IDE 6.5 for JavaFX Now Available!
  • 原文地址:https://www.cnblogs.com/antispam/p/4018452.html
Copyright © 2011-2022 走看看