zoukankan      html  css  js  c++  java
  • python基础学习笔记

    Python中,数值类型(intfloat)、字符串str、元组tuple都是不可变类型。

    而列表list、字典dict、集合set是可变类型。

    1.关于''' '''(一对三引号)
    主要有两种作用 1.对代码得注释 2.在print(''' ''' )按原样输出
    2.关于转义字符
    回车,将当前位置移动到本行开头
    换行,将当前位置移动到下一行开头

    >>> print('ab\rcd')
    ab
    cd
    >>> print('ab
    cd')
    ab cd
    >>> print('ab
    cd')
    ab
    cd
    >>> print(r'ab
    cd')
    ab
    cd

    3.变量命名规则
    字母、数字和下划线,不能以数字开头
    4.常用数据类型
    最常用的数据类型有三种——字符串(str)、整数(int)和浮点数(float)、
    print(0.55+0.3)      0.8500000000000001
    Python计算浮点数时,会先把0.55和0.3转化成二进制数
    5.数据拼接
    数据拼接的方法简单,利用数据拼接符号【+】,将需要拼接的变量连在一起就行了
    hero = '亚瑟'
    enemy = '敌方'
    action = '团灭'
    gain = '获得'
    achieve = 'ACE称号'
    print(hero+action+enemy+gain+achieve)
    print()函数也可以接受多个字符串,用逗号“,”隔开,就可以连成一串输出:
    >>> print('The quick brown fox', 'jumps over', 'the lazy dog')
    The quick brown fox jumps over the lazy dog

    6.type()函数
    为什么不同类型的数据不能拼接在一起呢?一句话:圈子不同不相融。
    负责转换数据类型的函数一共有3种:str()、 int()和float()。
    整数转换字符串类型的方法是不是很方便?还有一种转换成字符串的方法,那就是借用引号的帮助,
    只有符合整数规范的字符串类数据,才能被int()强制转换。
    虽然浮点形式的字符串,不能使用int()函数。但浮点数是可以被int()函数强制转换的。
    7.float()函数
    首先float()函数的使用,也是将需要转换的数据放在括号里,像这样:float(数据)。
    其次,float()函数也可以将整数和字符串转换为浮点类型。同时,如果括号里面数据是字符串类型,这个数据一定得是数字形式。

    用英文输入法打:后按回车,开发工具(IDE)会自动实现下一行代码,向右缩进的功能。

    else想正确执行,一定要有一个和他平级的前提,这个前提可以是if判断,也可以是其他命令,比如循环命令。

    多向判断:if…elif…else…

    8.input()函数
    input('请铲屎官输入宠物的名字:')
    对于input()函数来说,不管我们输入的回答是什么,
    不管你输入的是整数1234,还是字符串我爱摩卡,input()函数的输入值(搜集到的回答),
    永远会被强制性地转换为字符串类型。(Python3固定规则)
    9.CPython用>>>作为提示符,而IPython用In [序号]:作为提示符。

    方法是在.py文件的第一行加上一个特殊的注释:
    #!/usr/bin/env python3
    print('hello, world')
    然后,通过命令给hello.py以执行权限:
    $ chmod a+x hello.py
    就可以直接运行hello.py了
    10.如果字符串里面有很多字符都需要转义,就需要加很多,
    为了简化,Python还允许用r' '表示' '内部的字符串默认不转义
    >>> print(r'\ \')
    \ \

    对于单个字符的编码,
    Python提供了ord()函数获取字符的整数表示,chr()函数把编码转换为对应的字符:

    encode()编码
    decode()解码
    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-

    11.关于格式化输出

    >>> 'Hello, %s' % 'world'
    'Hello, world'
    >>> 'Hi, %s, you have $%d.' % ('Michael', 1000000)
    'Hi, Michael, you have $1000000.'
    %d整数
    %f浮点数
    %s字符串
    %x十六进制整数
    >>> '%2d-%02d' % (3, 1)
    ' 3-01'
    >>> '%.2f'% 3.1415926
    '3.14'

    如果你不太确定应该用什么,%s永远起作用,它会把任何数据类型转换为字符串:
    >>> 'Age: %s. Gender: %s' % (25, True)
    'Age: 25. Gender: True'
    有些时候,字符串里面的%是一个普通字符怎么办?这个时候就需要转义,用%%来表示一个%:
    >>> 'growth rate: %d %%' % 7
    'growth rate: 7 %'
    list
    12.Python内置的一种数据类型是列表:list。
    list是一种有序的集合,可以随时添加和删除其中的元素。
    列表 list[]
    元组tuple() t=(1,)
    这是因为input()返回的数据类型是str,str不能直接和整数比较,必须先把str转换成整数。
    Python提供了int()函数来完成这件事情:
    13.Python的循环有两种:
    一种是for...in循环,依次把list或tuple中的每个元素迭代出来,看例子:
    names = ['Michael', 'Bob', 'Tracy']
    for name in names:
      print(name)
    =================================================
    sum = 0
    for x in range(101):
      sum = sum + x
      print(sum)
    第二种循环是while循环,只要条件满足,就不断循环,条件不满足时退出循环。
    比如我们要计算100以内所有奇数之和,可以用while循环实现:
    sum = 0
    n = 99
    while n > 0:
      sum = sum + n
      n = n - 2
    print(sum)
    =================================================
    14.使用dict和set
    dict字典:使用键-值(key-value)存储,具有极快的查找速度。
    >>> d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}
    >>> d['Michael']
    95
    由于一个key只能对应一个value,所以,多次对一个key放入value,后面的值会把前面的值冲掉:
    >>> d['Jack'] = 90
    >>> d['Jack']
    90
    >>> d['Jack'] = 88
    >>> d['Jack']
    88
    要避免key不存在的错误,有两种办法,一是通过in判断key是否存在:
    >>> 'Thomas' in d
    False
    二是通过dict提供的get方法,如果key不存在,可以返回None,或者自己指定的value:
    >>> d.get('Thomas')
    >>> d.get('Thomas', -1)
    -1
    要删除一个key,用pop(key)方法,对应的value也会从dict中删除:
    >>> d.pop('Bob')
    75
    >>> d
    {'Michael': 95, 'Tracy': 85}
    请务必注意,dict内部存放的顺序和key放入的顺序是没有关系的。
    和list比较,dict有以下几个特点:
    1. 查找和插入的速度极快,不会随着key的增加而增加;
    2. 需要占用大量的内存,内存浪费多。
    而list相反:
    1. 查找和插入的时间随着元素的增加而增加;
    2. 占用空间小,浪费内存很少。
    所以,dict是用空间来换取时间的一种方法。
    dict可以用在需要高速查找的很多地方,在Python代码中几乎无处不在,
    正确使用dict非常重要,需要牢记的第一条就是dict的key必须是不可变对象。
    set
    set和dict类似,也是一组key的集合,但不存储value。
    由于key不能重复,所以,在set中,没有重复的key
    >>> s = set([1, 2, 3])
    >>> s
    {1, 2, 3}
    注意,传入的参数[1, 2, 3]是一个list,而显示的{1, 2, 3}只是告诉你这个set内部有1,2,3这3个元素,
    显示的顺序也不表示set是有序的。
    通过add(key)方法可以添加元素到set中,可以重复添加,但不会有效果:
    通过remove(key)方法可以删除元素:
    set可以看成数学意义上的无序和无重复元素的集合,因此,两个set可以做数学意义上的交集、并集等操作:
    上面我们讲了,str是不变对象,而list是可变对象。
    对于可变对象,比如list,对list进行操作,list内部的内容是会变化的,比如:
    >>> a = ['c', 'b', 'a']
    >>> a.sort()
    >>> a
    ['a', 'b', 'c']
    而对于不可变对象,比如str,对str进行操作呢:
    >>> a = 'abc'
    >>> a.replace('a', 'A')
    'Abc'
    >>> a
    'abc'
    15.定义函数
    在Python中,定义一个函数要使用def语句,依次写出函数名、括号、括号中的参数和冒号:,
    然后,在缩进块中编写函数体,函数的返回值用return语句返回。
    我们以自定义一个求绝对值的my_abs函数为例:
    def my_abs(x):
      if x >= 0:
        return x
      else:
        return -x
    已经把my_abs()的函数定义保存为abstest.py文件了,可以在该文件的当前目录下启动Python解释器
    用from abstest import my_abs来导入my_abs()函数,注意abstest是文件名(不含.py扩展名):
    16.空函数
    如果想定义一个什么事也不做的空函数,可以用pass语句:
    def nop():
      pass
    pass语句什么都不做,那有什么用?实际上pass可以用来作为占位符,
    比如现在还没想好怎么写函数的代码,就可以先放一个pass,让代码能运行起来。
    pass还可以用在其他语句里,比如:
    if age >= 18:
      pass
    缺少了pass,代码运行就会有语法错误。
    让我们修改一下my_abs的定义,对参数类型做检查,只允许整数和浮点数类型的参数。
    数据类型检查可以用内置函数isinstance()实现:
    def my_abs(x):
      if not isinstance(x, (int, float)):
        raise TypeError('bad operand type')
      if x >= 0:
        return x
      else:
        return -x
    函数执行完毕也没有return语句时,自动return None。
    函数可以同时返回多个值,但其实就是一个tuple。
    Python的函数定义非常简单,但灵活度却非常大。
    除了正常定义的必选参数外,还可以使用默认参数、可变参数和关键字参数,使得函数定义出来的接口,不但能处理复杂的参数,还可以简化调用者的代码。
    把power(x)修改为power(x, n),用来计算xn
    def power(x, n):
      s = 1
    while n > 0:
      n = n - 1
      s = s * x
      return s
    对于这个修改后的power(x, n)函数,可以计算任意n次方:
    17.默认参数
    新的power(x, n)函数定义没有问题,
    但是,旧的调用代码失败了,原因是我们增加了一个参数,导致旧的代码因为缺少一个参数而无法正常调用:
    Python的错误信息很明确:调用函数power()缺少了一个位置参数n。
    这个时候,默认参数就排上用场了。由于我们经常计算x2,所以,完全可以把第二个参数n的默认值设定为2:
    def power(x, n=2):
    这样,当我们调用power(5)时,相当于调用power(5, 2):
    >>> power(5)
    25
    >>> power(5, 2)
    25
    而对于n > 2的其他情况,就必须明确地传入n,比如power(5, 3)。
    从上面的例子可以看出,默认参数可以简化函数的调用。
    设置默认参数时,有几点要注意:
    一是必选参数在前,默认参数在后,否则Python的解释器会报错
    定义默认参数要牢记一点:默认参数必须指向不变对象!
    18.关键字参数
    可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。

    而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。请看示例:
    def person(name, age, **kw):
      print('name:', name, 'age:', age, 'other:', kw)
    函数person除了必选参数name和age外,还接受关键字参数kw。在调用该函数时,可以只传入必选参数:
    >>> person('Michael', 30)
    name: Michael age: 30 other: {}
    也可以传入任意个数的关键字参数:
    >>> person('Bob', 35, city='Beijing')
    name: Bob age: 35 other: {'city': 'Beijing'}
    >>> person('Adam', 45, gender='M', job='Engineer')
    name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}
    关键字参数有什么用?它可以扩展函数的功能。
    比如,在person函数里,我们保证能接收到name和age这两个参数,
    但是,如果调用者愿意提供更多的参数,我们也能收到。试想你正在做一个用户注册的功能,
    除了用户名和年龄是必填项外,其他都是可选项,利用关键字参数来定义这个函数就能满足注册的需求。
    和可变参数类似,也可以先组装出一个dict,然后,把该dict转换为关键字参数传进去:
    >>> extra = {'city': 'Beijing', 'job': 'Engineer'}
    >>> person('Jack', 24, city=extra['city'], job=extra['job'])
    name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}
    当然,上面复杂的调用可以用简化的写法:
    >>> extra = {'city': 'Beijing', 'job': 'Engineer'}
    >>> person('Jack', 24, **extra)
    name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}
    **extra表示把extra这个dict的所有key-value用关键字参数传入到函数的**kw参数,
    kw将获得一个dict,注意kw获得的dict是extra的一份拷贝,对kw的改动不会影响到函数外的extra。
    19.命名关键字参数
    对于关键字参数,函数的调用者可以传入任意不受限制的关键字参数。
    至于到底传入了哪些,就需要在函数内部通过kw检查。
    仍以person()函数为例,我们希望检查是否有city和job参数:
    def person(name, age, **kw):
      if 'city' in kw:
    # 有city参数
      pass
    if 'job' in kw:
    # 有job参数
      pass
    print('name:', name, 'age:', age, 'other:', kw)
    但是调用者仍可以传入不受限制的关键字参数:
    >>> person('Jack', 24, city='Beijing', addr='Chaoyang', zipcode=123456)
    如果要限制关键字参数的名字,就可以用命名关键字参数,
    例如,只接收city和job作为关键字参数。这种方式定义的函数如下:
    def person(name, age, *, city, job):
      print(name, age, city, job)
    和关键字参数**kw不同,命名关键字参数需要一个特殊分隔符*,*后面的参数被视为命名关键字参数。
    调用方式如下:
    >>> person('Jack', 24, city='Beijing', job='Engineer')
    Jack 24 Beijing Engineer
    命名关键字参数必须传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错:
    >>> person('Jack', 24, 'Beijing', 'Engineer')
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    TypeError: person() takes 2 positional arguments but 4 were given
    由于调用时缺少参数名city和job,
    Python解释器把这4个参数均视为位置参数,但person()函数仅接受2个位置参数。
    命名关键字参数可以有缺省值,从而简化调用:
    def person(name, age, *, city='Beijing', job):
      print(name, age, city, job)
    由于命名关键字参数city具有默认值,调用时,可不传入city参数:
    >>> person('Jack', 24, job='Engineer')
    Jack 24 Beijing Engineer
    使用命名关键字参数时,要特别注意,*不是参数,而是特殊分隔符。
    如果缺少*,Python解释器将无法识别位置参数和命名关键字参数:
    def person(name, age, city, job):
    # 缺少 *,city和job被视为位置参数
      pass
    *args是可变参数,args接收的是一个tuple;
    **kw是关键字参数,kw接收的是一个dict。
    在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
    20.切片
    取一个list或tuple的部分元素是非常常见的操作。比如,一个list如下:
    >>> L = ['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack']
    取前3个元素,应该怎么做?
    对应上面的问题,取前3个元素,用一行代码就可以完成切片:
    >>> L[0:3]
    ['Michael', 'Sarah', 'Tracy']
    如果第一个索引是0,还可以省略:
    >>> L[:3]
    tuple也是一种list,唯一区别是tuple不可变。因此,tuple也可以用切片操作,只是操作的结果仍是tuple:
    >>> (0, 1, 2, 3, 4, 5)[:3]
    (0, 1, 2)
    字符串'xxx'也可以看成是一种list,每个元素就是一个字符。因此,字符串也可以用切片操作,只是操作结果仍是字符串:
    >>> 'ABCDEFG'[:3]
    'ABC'
    >>> 'ABCDEFG'[::2]
    'ACEG'
    在很多编程语言中,针对字符串提供了很多各种截取函数(例如,substring),其实目的就是对字符串切片。
    Python没有针对字符串的截取函数,只需要切片一个操作就可以完成,非常简单。
    21.默认情况下,dict迭代的是key。

    如果要迭代value,可以用for value in d.values()
    如果要同时迭代key和value,可以用for k, v in d.items()
    >>> d = {'x': 'A', 'y': 'B', 'z': 'C' }
    >>> for k, v in d.items():
    ... print(k, '=', v)
    y = B
    x = A
    z = C
    那么,如何判断一个对象是可迭代对象呢?方法是通过collections模块的Iterable类型判断:
    >>> from collections import Iterable
    >>> isinstance('abc', Iterable) # str是否可迭代
    True
    >>> isinstance([1,2,3], Iterable) # list是否可迭代
    True
    >>> isinstance(123, Iterable) # 整数是否可迭代
    False
    最后一个小问题,如果要对list实现类似Java那样的下标循环怎么办?
    Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身:
    >>> for i, value in enumerate(['A', 'B', 'C']):
    ... print(i, value)
    0 A
    1 B
    2 C
    22.列表生成式
    >>> list(range(1, 11))
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    >>> [x * x for x in range(1, 11)]
    [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
    写列表生成式时,把要生成的元素x * x放到前面,后面跟for循环,就可以把list创建出来
    for循环后面还可以加上if判断,这样我们就可以筛选出仅偶数的平方:
    >>> [x * x for x in range(1, 11) if x % 2 == 0]
    [4, 16, 36, 64, 100]
    还可以使用两层循环,可以生成全排列:
    >>> [m + n for m in 'ABC' for n in 'XYZ']
    ['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']
    因此,列表生成式也可以使用两个变量来生成list:
    >>> d = {'x': 'A', 'y': 'B', 'z': 'C' }
    >>> [k + '=' + v for k, v in d.items()]
    ['y=B', 'x=A', 'z=C']
    最后把一个list中所有的字符串变成小写:
    >>> L = ['Hello', 'World', 'IBM', 'Apple']
    >>> [s.lower() for s in L]
    ['hello', 'world', 'ibm', 'apple']
    23.要创建一个generator,有很多种方法
    第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:
    >>> L = [x * x for x in range(10)]
    >>> L
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    >>> g = (x * x for x in range(10))
    >>> g
    <generator object <genexpr> at 0x1022ef630>
    创建L和g的区别仅在于最外层的[]和(),L是一个list,而g是一个generator。
    当然,上面这种不断调用next(g)实在是太变态了,正确的方法是使用for循环,因为generator也是可迭代对象:
    >>> g = (x * x for x in range(10))
    >>> for n in g:
    ... print(n)
    同样的,把函数改成generator后,
    我们基本上从来不会用next()来获取下一个返回值,而是直接使用for循环来迭代

    24.yield
    def odd():
      print('step 1')
      yield 1
      print('step 2')
      yield(3)
      print('step 3')
      yield(5)
    >>> for n in odd():
        print(n)
    step 1
    1
    step 2
    33
    step 3
    55
    我们已经知道,可以直接作用于for循环的数据类型有以下几种:
    一类是集合数据类型,如list、tuple、dict、set、str等;
    一类是generator,包括生成器和带yield的generator function。
    这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。
    可以使用isinstance()判断一个对象是否是Iterable对象:
    >>> from collections import Iterable
    >>> isinstance([], Iterable)
    True
    >>> isinstance({}, Iterable)
    True
    >>> isinstance('abc', Iterable)
    True
    >>> isinstance((x for x in range(10)), Iterable)
    True
    >>> isinstance(100, Iterable)
    False
    而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。
    可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
    可以使用isinstance()判断一个对象是否是Iterator对象:
    >>> from collections import Iterator
    >>> isinstance((x for x in range(10)), Iterator)
    True
    >>> isinstance([], Iterator)
    False
    >>> isinstance({}, Iterator)
    False
    >>> isinstance('abc', Iterator)
    False
    生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。
    把list、dict、str等Iterable变成Iterator可以使用iter()函数:

    25.要进行反向排序,不必改动key函数,可以传入第三个参数reverse=True:
    >>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
    ['Zoo', 'Credit', 'bob', 'about']
    由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数。
    >>> def now():
    ... print('2015-3-25')
    >>> f = now
    >>> f()
    2015-3-25
    函数对象有一个__name__属性,可以拿到函数的名字:
    >>> now.__name__
    'now'
    >>> f.__name__
    'now'
    现在,假设我们要增强now()函数的功能,比如,在函数调用前后自动打印日志,
    但又不希望修改now()函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。
    和静态语言不同,Python允许对实例变量绑定任何数据,也就是说,对于两个实例变量,虽然它们都是同一个类的不同实例,但拥有的变量名称都可能不同:
    >>> bart = Student('Bart Simpson', 59)
    >>> lisa = Student('Lisa Simpson', 87)
    >>> bart.age = 8
    >>> bart.age
    8
    >>> lisa.age
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    AttributeError: 'Student' object has no attribute 'age'
    如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,
    在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),
    只有内部可以访问,外部不能访问,所以,我们把Student类改一改:
    class Student(object):
      def __init__(self, name, score):
        self.__name = name
        self.__score = score
      def print_score(self):
        print('%s: %s' % (self.__name, self.__score))
    但是如果外部代码要获取name和score怎么办?可以给Student类增加get_name和get_score这样的方法:
    class Student(object):
    ...
      def get_name(self):
        return self.__name
      def get_score(self):
        return self.__score
    如果又要允许外部代码修改score怎么办?可以再给Student类增加set_score方法:
    class Student(object):
    ...
    def set_score(self, score):
    self.__score = score
    需要注意的是,在Python中,变量名类似__xxx__的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以,不能用__name__、__score__这样的变量名。
    有些时候,你会看到以一个下划线开头的实例变量名,比如_name,这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”。
    双下划线开头的实例变量是不是一定不能从外部访问呢?其实也不是。不能直接访问__name是因为Python解释器对外把__name变量改成了
    _Student__name,所以,仍然可以通过_Student__name来访问__name变量:
    >>> bart._Student__name
    'Bart Simpson'
    但是强烈建议你不要这么干,因为不同版本的Python解释器可能会把__name改成不同的变量名。
    总的来说就是,Python本身没有任何机制阻止你干坏事,一切全靠自觉。
    比如,我们已经编写了一个名为Animal的class,有一个run()方法可以直接打印:
    class Animal(object):
      def run(self):
        print('Animal is running...')
    当我们需要编写Dog和Cat类时,就可以直接从Animal类继承:
    class Dog(Animal):
      pass
    class Cat(Animal):
      pass
    要理解什么是多态,我们首先要对数据类型再作一点说明。当我们定义一个class的时候,我们实际上就定义了一种数据类型。我们定义的数据类型和Python自带的数据类型,比如str、list、dict没什么两样:
    a = list() # a是list类型
    b = Animal() # b是Animal类型
    c = Dog() # c是Dog类型
    判断一个变量是否是某个类型可以用isinstance()判断:
    >>> isinstance(a, list)
    True
    >>> isinstance(b, Animal)
    True
    >>> isinstance(c, Dog)
    True
    所以,在继承关系中,如果一个实例的数据类型是某个子类,那它的数据类型也可以被看做是父类。但是,反过来就不行:
    >>> b = Animal()
    >>> isinstance(b, Dog)
    False
    Dog可以看成Animal,但Animal不可以看成Dog。
    获取对象信息
    当我们拿到一个对象的引用时,如何知道这个对象是什么类型、有哪些方法呢?
    使用type()
    首先,我们来判断对象类型,使用type()函数:
    基本类型都可以用type()判断:
    >>> type(123)
    <class 'int'>
    >>> type('str')
    <class 'str'>
    >>> type(None)
    <type(None) 'NoneType'>
    如果一个变量指向函数或者类,也可以用type()判断:
    >>> type(abs)
    <class 'builtin_function_or_method'>
    >>> type(a)
    <class '__main__.Animal'>
    >>> isinstance([1, 2, 3], (list, tuple))
    True
    >>> isinstance((1, 2, 3), (list, tuple))
    True
    使用dir()
    如果要获得一个对象的所有属性和方法,可以使用dir()函数,它返回一个包含字符串的list,比如,获得一个str对象的所有属性和方法:
    >>> dir('ABC')
    ====================================================
    186/531
    >>> def set_age(self, age): # 定义一个函数作为实例方法
    ... self.age = age
    ...
    >>> from types import MethodType
    >>> s.set_age = MethodType(set_age, s) # 给实例绑定一个方法
    >>> s.set_age(25) # 调用实例方法
    >>> s.age # 测试结果
    25
    但是,给一个实例绑定的方法,对另一个实例是不起作用的:
    >>> s2 = Student() # 创建新的实例
    >>> s2.set_age(25) # 尝试调用方法
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    AttributeError: 'Student' object has no attribute 'set_age'
    为了给所有实例都绑定方法,可以给class绑定方法:
    >>> def set_score(self, score):
    ... self.score = score
    ...
    >>> Student.set_score = MethodType(set_score, Student)
    给class绑定方法后,所有实例均可调用:
    >>> s.set_score(100)
    >>> s.score
    100
    >>> s2.set_score(99)
    >>> s2.score
    99
    通常情况下,上面的set_score方法可以直接定义在class中,
    但动态绑定允许我们在程序运行的过程中动态给class加上功能,这在静态语言中很难实现。
    如果我们想要限制实例的属性怎么办?比如,只允许对Student实例添加name和age属性。
    为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性:
    class Student(object):
      __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
    然后,我们试试:
    >>> s = Student() # 创建新的实例
    >>> s.name = 'Michael' # 绑定属性'name'
    >>> s.age = 25 # 绑定属性'age'
    >>> s.score = 99 # 绑定属性'score'
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    AttributeError: 'Student' object has no attribute 'score'
    由于'score'没有被放到__slots__中,所以不能绑定score属性,试图绑定score将得到AttributeError的错误。
    使用__slots__要注意,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的:
    >>> class GraduateStudent(Student):
    ... pass
    ...
    >>> g = GraduateStudent()
    >>> g.score = 9999
    除非在子类中也定义__slots__,这样,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__。
    怎么才能打印得好看呢?只需要定义好__str__()方法,返回一个好看的字符串就可以了:
    >>> class Student(object):
    ... def __init__(self, name):
    ... self.name = name
    ... def __str__(self):
    ... return 'Student object (name: %s)' % self.name
    ...
    >>> print(Student('Michael'))
    Student object (name: Michael)
    高级语言通常都内置了一套try...except...finally...的错误处理机制,Python也不例外。
    try
    让我们用一个例子来看看try的机制:
    try:
      print('try...')
      r = 10 / 0
      print('result:', r)
    except ZeroDivisionError as e:
      print('except:', e)
    finally:
      print('finally...')
      print('END')
    当我们认为某些代码可能会出错时,就可以用try来运行这段代码,
    如果执行出错,则后续代码不会继续执行,而是直接跳转至错误处理代码,
    即except语句块,执行完except后,如果有finally语句块,则执行finally语句块,至此,执行完毕。
    所有的错误类型都继承自BaseException
    try:
      print('try...')
      r = 10 / 0
      print('result:', r)
    except BaseException as e:
      print('except:', e)
    finally:
      print('finally...')
      print('END')
    可以使用Python内置的logging模块可以非常容易地记录错误信息:
    except Exception as e:
      logging.exception(e)
    同样是出错,但程序打印完错误信息后会继续执行,并正常退出
    raise 抛出错误
    如果要比较爽地设置断点、单步执行,就需要一个支持调试功能的IDE。
    目前比较好的Python IDE有PyCharm:
    第一种是CPU等着,也就是程序暂停执行后续代码,等100M的数据在10秒后写入磁盘,再接着往下执行,这种模式称为同步IO;

    另一种方法是CPU不等待,只是告诉磁盘,“您老慢慢写,不着急,我接着干别的事去了”,
    于是,后续代码可以立刻接着执行,这种模式称为异步IO。
    26.读文件
    要以读文件的模式打开一个文件对象,使用Python内置的open()函数,传入文件名和标示符:
    >>> f = open('/Users/michael/test.txt', 'r')
    标示符'r'表示读,这样,我们就成功地打开了一个文件。
    248/531
    如果文件不存在,open()函数就会抛出一个IOError的错误,并且给出错误码和详细的信息告诉你文件不存在:
    >>> f=open('/Users/michael/notfound.txt', 'r')
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    FileNotFoundError: [Errno 2] No such file or directory: '/Users/michael/notfound.txt'
    如果文件打开成功,接下来,调用read()方法可以一次读取文件的全部内容,Python把内容读到内存,用一个str对象表示:
    >>> f.read()
    'Hello, world!'
    最后一步是调用close()方法关闭文件。文件使用完毕后必须关闭,因为文件对象会占用操作系统的资源,并且操作系统同一时间能打开的文件数量也是有限的:
    >>> f.close()
    Python引入了with语句来自动帮我们调用close()方法:
    with open('/path/to/file', 'r') as f:
    print(f.read())
    如果文件很小,read()一次性读取最方便;如果不能确定文件大小,反复调用read(size)比较保险;如果是配置文件,调用readlines()最方便:
    for line in f.readlines():
    print(line.strip()) # 把末尾的' '删掉
    要读取二进制文件,比如图片、视频等等,用'rb'模式打开文件即可:
    >>> f = open('/Users/michael/test.jpg', 'rb')
    >>> f.read()
    b'xffxd8xffxe1x00x18Exifx00x00...' # 十六进制表示的字节
    要读取非UTF-8编码的文本文件,需要给open()函数传入encoding参数,例如,读取GBK编码的文件:
    >>> f = open('/Users/michael/gbk.txt', 'r', encoding='gbk')
    >>> f.read()
    '测试'
    遇到有些编码不规范的文件,你可能会遇到UnicodeDecodeError,
    因为在文本文件中可能夹杂了一些非法编码的字符。
    遇到这种情况,open()函数还接收一个errors参数,表示如果遇到编码错误后如何处理。
    最简单的方式是直接忽略:
    >>> f = open('/Users/michael/gbk.txt', 'r', encoding='gbk', errors='ignore')
    写文件
    写文件和读文件是一样的,唯一区别是调用open()函数时,传入标识符'w'或者'wb'表示写文本文件或写二进制文件:
    >>> f = open('/Users/michael/test.txt', 'w')
    >>> f.write('Hello, world!')
    >>> f.close()
    251/531
    你可以反复调用write()来写入文件,但是务必要调用f.close()来关闭文件。
    当我们写文件时,操作系统往往不会立刻把数据写入磁盘,而是放到内存缓存起来,空闲的时候再慢慢写入。
    只有调用close()方法时,操作系统才保证把没有写入的数据全部写入磁盘。
    忘记调用close()的后果是数据可能只写了一部分到磁盘,剩下的丢失了。
    所以,还是用with语句来得保险:
    with open('/Users/michael/test.txt', 'w') as f:
    f.write('Hello, world!')
    要写入特定编码的文本文件,请给open()函数传入encoding参数,将字符串自动转换成指定编码。
    27.StringIO和BytesIO
    StringIO
    很多时候,数据读写不一定是文件,也可以在内存中读写。
    StringIO顾名思义就是在内存中读写str。
    要把str写入StringIO,我们需要先创建一个StringIO,然后,像文件一样写入即可:
    >>> from io import StringIO
    >>> f = StringIO()
    >>> f.write('hello')
    5
    >>> f.write(' ')
    1
    >>> f.write('world!')
    6
    >>> print(f.getvalue())
    hello world!
    getvalue()方法用于获得写入后的str。
    要读取StringIO,可以用一个str初始化StringIO,然后,像读文件一样读取:
    >>> from io import StringIO
    >>> f = StringIO('Hello! Hi! Goodbye!')
    >>> while True:
    ... s = f.readline()
    ... if s == '':
    ... break
    ... print(s.strip())
    ...
    Hello!
    Hi!
    Goodbye!
    BytesIO
    StringIO操作的只能是str,如果要操作二进制数据,就需要使用BytesIO。
    BytesIO实现了在内存中读写bytes,我们创建一个BytesIO,然后写入一些bytes:
    >>> from io import BytesIO
    >>> f = BytesIO()
    >>> f.write('中文'.encode('utf-8'))
    6
    >>> print(f.getvalue())
    b'xe4xb8xadxe6x96x87'
    请注意,写入的不是str,而是经过UTF-8编码的bytes。
    和StringIO类似,可以用一个bytes初始化BytesIO,然后,像读文件一样读取:
    >>> from io import StringIO
    >>> f = BytesIO(b'xe4xb8xadxe6x96x87')
    >>> f.read()
    b'xe4xb8xadxe6x96x87'
    小结
    StringIO和BytesIO是在内存中操作str和bytes的方法,使得和读写文件具有一致的接口。
    操作文件和目录的函数一部分放在os模块中,一部分放在os.path模块中,这一点要注意一下。
    查看、创建和删除目录可以这么调用:
    # 查看当前目录的绝对路径:
    >>> 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.join()函数,
    这样可以正确处理不同操作系统的路径分隔符。
    我们把变量从内存中变成可存储或传输的过程称之为序列化,
    在Python中叫pickling,在其他语言中也被称之为serialization,marshalling,flattening等等,都是一个意思。
    序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上。
    反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling。
    Python提供了pickle模块来实现序列化。
    首先,我们尝试把一个对象序列化并写入文件:
    >>> import pickle
    >>> d = dict(name='Bob', age=20, score=88)
    >>> pickle.dumps(d)
    b'x80x03}qx00(Xx03x00x00x00ageqx01Kx14Xx05x00x00x00scoreqx02KXXx04x00x00x00nameqx03Xx03x00x00x00Bobqx04u.'
    pickle.dumps()方法把任意对象序列化成一个bytes,然后,就可以把这个bytes写入文件。或者用另一个方法pickle.dump()直接把对象序列化后写入一个file-like Object:
    >>> f = open('dump.txt', 'wb')
    >>> pickle.dump(d, f)
    >>> f.close()
    看看写入的dump.txt文件,一堆乱七八糟的内容,这些都是Python保存的对象内部信息。
    当我们要把对象从磁盘读到内存时,可以先把内容读到一个bytes,然后用pickle.loads()方法反序列化出对象,
    也可以直接用pickle.load()方法从一个file-like Object中直接反序列化出对象。
    我们打开另一个Python命令行来反序列化刚才保存的对象:
    >>> f = open('dump.txt', 'rb')
    >>> d = pickle.load(f)
    >>> f.close()
    >>> d
    {'age': 20, 'score': 88, 'name': 'Bob'}
    变量的内容又回来了!
    当然,这个变量和原来的变量是完全不相干的对象,它们只是内容相同而已。
    Pickle的问题和所有其他编程语言特有的序列化问题一样,就是它只能用于Python,
    并且可能不同版本的Python彼此都不兼容,因此,只能用Pickle保存那些不重要的数据,不能成功地反序列化也没关系。
    JSON
    如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,
    因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘
    或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非常方便。
    Python内置的json模块提供了非常完善的Python对象到JSON格式的转换。我们先看看如何把Python对象变成一个JSON:
    >>> import json
    >>> d = dict(name='Bob', age=20, score=88)
    >>> json.dumps(d)
    '{"age": 20, "score": 88, "name": "Bob"}'
    dumps()方法返回一个str,内容就是标准的JSON。类似的,dump()方法可以直接把JSON写入一个file-like Object。
    要把JSON反序列化为Python对象,用loads()或者对应的load()方法,前者把JSON的字符串反序列化,
    后者从file-like Object中读取字符串并反序列化:
    >>> json_str = '{"age": 20, "score": 88, "name": "Bob"}'
    >>> json.loads(json_str)
    {'age': 20, 'score': 88, 'name': 'Bob'}
    不过,下次如果遇到一个Teacher类的实例,照样无法序列化为JSON。我们可以偷个懒,把任意class的实例变为dict:
    print(json.dumps(s, default=lambda obj: obj.__dict__))
    因为通常class的实例都有一个__dict__属性,它就是一个dict,用来存储实例变量。
    也有少数例外,比如定义了__slots__的class。
    ==================================================
    有些进程还不止同时干一件事,比如Word,它可以同时进行打字、拼写检查、打印等事情。
    在一个进程内部,要同时干多件事,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”称为线程(Thread)
    由于每个进程至少要干一件事,所以,一个进程至少有一个线程。当然,像Word这种复杂的进程可以有多个线程,多个线程可以同时执行,多线程的执行方式和多进程是一样的,
    也是由操作系统在多个线程之间快速切换,让每个线程都短暂地交替运行,看起来就像同时执行一样
    Python既支持多进程,又支持多线程,我们会讨论如何编写这两种多任务程序。
    ==========================================
    由于线程是操作系统直接支持的执行单元,因此,高级语言通常都内置多线程的支持,Python也不例外,
    并且,Python的线程是真正的Posix Thread,而不是模拟出来的线程。
    Python的标准库提供了两个模块:_thread和threading,_thread是低级模块,threading是高级模块,
    对_thread进行了封装。绝大多数情况下,我们只需要使用threading这个高级模块
    创建一个锁就是通过threading.Lock()来实现:
    balance = 0
    lock = threading.Lock()
    def run_thread(n):
    for i in range(100000):
    # 先要获取锁:
    lock.acquire()
    try:
    # 放心地改吧:
    change_it(n)
    finally:
    # 改完了一定要释放锁:
    lock.release()
    当多个线程同时执行lock.acquire()时,
    只有一个线程能成功地获取锁,然后继续执行代码,其他线程就继续等待直到获得锁为止
    =========================================
    A|B可以匹配A或B,所以[P|p]ython可以匹配'Python'或者'python'。
    ^表示行的开头,^d表示必须以数字开头。
    $表示行的结束,d$表示必须以数字结束
    ===========================
    re模块
    有了准备知识,我们就可以在Python中使用正则表达式了。Python提供re模块,包含所有正则表达式的功能。由于Python的字符串本身也用转义,所以要特别注意:
    s = 'ABC\-001' # Python的字符串
    # 对应的正则表达式字符串变成:
    # 'ABC-001'
    因此我们强烈建议使用Python的r前缀,就不用考虑转义的问题了:
    s = r'ABC-001' # Python的字符串
    # 对应的正则表达式字符串不变:
    # 'ABC-001'
    先看看如何判断正则表达式是否匹配:
    >>> import re
    >>> re.match(r'^d{3}-d{3,8}$', '010-12345')
    <_sre.SRE_Match object; span=(0, 9), match='010-12345'>
    >>> re.match(r'^d{3}-d{3,8}$', '010 12345')
    >>>
    match()方法判断是否匹配,如果匹配成功,返回一个Match对象,否则返回None。
    virtualenv
    每个应用可能需要各自拥有一套“独立”的Python运行环境。
    virtualenv就是用来为一个应用创建一套“隔离”的Python运行环境。
    首先,我们用pip安装virtualenv:
    $ pip3 install virtualenv
    然后,假定我们要开发一个新的项目,需要一套独立的Python运行环境,可以这么做:
    第一步,创建目录:
    Mac:~ michael$ mkdir myproject
    Mac:~ michael$ cd myproject/
    Mac:myproject michael$
    第二步,创建一个独立的Python运行环境,命名为venv:
    Mac:myproject michael$ virtualenv --no-site-packages venv
    Using base prefix '/usr/local/.../Python.framework/Versions/3.4'
    New python executable in venv/bin/python3.4
    Also creating executable in venv/bin/python
    Installing setuptools, pip, wheel...done.
    命令virtualenv就可以创建一个独立的Python运行环境,我们还加上了参数--no-site-packages,这样,已经安装到系统Python环境中的所有第三方包都不会复制过来,这样,我们就得到了一个不带任何第三方包的“干净”的Python运行环境。
    新建的Python环境被放到当前目录下的venv目录。有了venv这个Python环境,可以用source进入该环境:
    Mac:myproject michael$ source venv/bin/activate
    (venv)Mac:myproject michael$
    注意到命令提示符变了,有个(venv)前缀,表示当前环境是一个名为venv的Python环境。
    下面正常安装各种第三方包,并运行python命令:
    (venv)Mac:myproject michael$ pip install jinja2
    ...
    Successfully installed jinja2-2.7.3 markupsafe-0.23
    (venv)Mac:myproject michael$ python myapp.py
    ...
    在venv环境下,用pip安装的包都被安装到venv这个环境下,系统Python环境不受任何影响。
    也就是说,venv环境是专门针对myproject这个应用创建的。
    退出当前的venv环境,使用deactivate命令:
    (venv)Mac:myproject michael$ deactivate
    Mac:myproject michael$
    此时就回到了正常的环境,现在pip或python均是在系统Python环境下执行。
    完全可以针对每个应用创建独立的Python运行环境,这样就可以对每个应用的Python环境进行隔离。
    virtualenv是如何创建“独立”的Python运行环境的呢?
    原理很简单,就是把系统Python复制一份到virtualenv的环境,用命令source venv/bin/activate进入一个virtualenv环境时,
    virtualenv会修改相关环境变量,让命令python和pip均指向当前的virtualenv环境
    小结
    virtualenv为应用提供了隔离的Python运行环境,解决了不同应用间多版本的冲突问题。
    用TCP协议进行Socket编程在Python中十分简单,对于客户端,要主动连接服务器的IP和指定端口,
    对于服务器,要首先监听指定端口,然后,对每一个新的连接,创建一个线程或进程来处理。通常,服务器程序会无限运行下去。
    同一个端口,被一个Socket绑定了以后,就不能被别的Socket绑定了。
    ===================
    $ pip install mysql-connector-python --allow-external
    我们演示如何连接到MySQL服务器的test数据库:
    # 导入MySQL驱动:
    >>> import mysql.connector
    # 注意把password设为你的root口令:
    >>> conn = mysql.connector.connect(user='root', password='password', database='test')
    >>> cursor = conn.cursor()
    # 创建user表:
    >>> cursor.execute('create table user (id varchar(20) primary key, name varchar(20))')
    # 插入一行记录,注意MySQL的占位符是%s:
    >>> cursor.execute('insert into user (id, name) values (%s, %s)', ['1', 'Michael'])
    >>> cursor.rowcount
    1
    # 提交事务:
    >>> conn.commit()
    >>> cursor.close()
    # 运行查询:
    >>> cursor = conn.cursor()
    >>> cursor.execute('select * from user where id = %s', ['1'])
    >>> values = cursor.fetchall()
    >>> values
    [('1', 'Michael')]
    # 关闭Cursor和Connection:
    >>> cursor.close()
    True
    >>> conn.close()
    ===========================================韦玮爬虫课程的python基础================================================
    方向:数据分析与挖掘
        机器学习
        自动化运维
    print()
    注释:1.# 2.''' '''注释法
    数据类型:
    数  字符串  列表  元组  集合  字典
    列表:[]
    元组:()
    字典:{键:值,键:值}
    集合:set()去重
    e=set(“abcdef)
    f=set(“sdfrhg”)
    e-f e中有f中没有的元素

    +号可以用于字符串的链接
    "abc"+"def"

    缩进: tab
    有三种控制流
    1.顺序结构
    2.条件分支结构
    3.循环结构
    whlie现实没有for用的多
    for:遍历列表
    a=[1,'a',23]
    for i in a:
    for:进行常规循环
    for i in range(0,10):
    break 和 continue:中断一次循环,继续下一次循环
    a=["AA","B",'C','D']
    for i in a:
      if(i=='c'):
        contine
      print(i)
    会输出"AA","B",'D' 中断一次c继续
    print(,end="")end=“”代表不换行输出

    print() 换行
    ================================

    系统自带的模块都在安装目录lib目录中

    import 模块名
    from 模块名 import 方法名
    ==============
    模块类别:
    自带模块
    第三方模块 pip安装 whl下载后再用pip安装 直接复制 anaconda

    自定义模块
    ============
    文件操作
    open(文件地址,操作形式)
    / 向左斜杠
    w:写入
    r:读取
    b:二进制
    a+:追加
    ==========================
    异常

    try:
    程序
    except exception as 异常名称err:
    异常处理部分如print(err)

    注意try except的位置,是否可以做到异常后的程序继续

    =======================
    面向对象

    class cl1:
    pass

    构造函数: 类在实例化的时候自动首先触发的方法 初始化
    __init__(self,参数) 两个下划线

    class cl2:
      def __init__(self):
        print(""")

    给类加上参数:构造方法加上参数
    class cl3:
    def __init__(self,name,job):
    print(""")
    =========================
    属性:类里面的变量
    class cl4:
    def __init__(self,name,job):
      self.name=name
      self.job=job
    =======================
    方法:类里面的函数 def 函数名(self,参数)
    class cl5:
      def myfunc1(self):
        print("hello")

    class cl6:
      def __init__(self,name):
        self.name=name
      def myfunc1(self):
        print("hello"+name)
    ===========================

  • 相关阅读:
    sqlite轻量型数据库笔记
    WPF学习之MVVM笔记
    Halcon 圆测量与直线测量
    深入浅出WPF_读书笔记
    研华轴卡PCI1245L配ADAM3956接线板与台达ASD-A2伺服驱动器和松下A5伺服驱动器
    dataGridView添加ComboBox 每行绑定不同的集合,显示默认值
    VS2015 注释英文
    java的安装环境配置详细步骤
    万能正则解析 json 数据 解析成键值对
    http 异步 接收 回传 数据文字和文件流
  • 原文地址:https://www.cnblogs.com/jiang910/p/10441897.html
Copyright © 2011-2022 走看看