Python 3 学习笔记

Python

在 Mac 上安装 Python

brew install python3

# 更新
brew upgrade python3

# 更新 pip
sudo python3 -m pip install --upgrade pip

pip3 install ipython

ipython 的高级用法

用法1
用法2

Python

# _*_ coding:utf-8 _*_
# 一定要写上编码,不然在 python2 中有中文会报错

# 关键字查看
import keyword
keyword.kwlist

# python2 中 raw_input
# input 接收到的都是字符串
age = input('年龄:')
if int(age):
  print('hello {0}'.format(age))
else:
  print('None')

# 没有真正意义上的常量,用大写表示
Name = 'hello'

# 注释

# python 大小写识别
sex = True
type(sex)

str = 'hello'
len(str) # 5

a = 5
b = 2
a // b  # 2 商
a %  b  # 1 余数

字符串(不可变类型)

a = 'helloworld'
a[0] # h
a[-1] # d
a[2:] # lloworld
a[2:5] # llo
a[2:-1] # lloworl
a[2:-1:2] # lool
a[-1::-1] # dlrowolleh
a[-1::-3] # dolh
a[::-1] # dlrowolleh
a.find('o') # 左边找位置4
a.rfind('o') # 右边找位置6
a.index('o') # 位置4
a.find('p') # 查找不存在的返回 -1
a.index('p') # error
a.count('o') # 统计出现的次数 2
a.replace('o', '@') # hell@w@rld
a.replace('o', '@', 1) # hell@world
a.split('o') # 按照 o 切割 ['hell', 'w', 'rld']
a.capitalize() # 将字符串一个字母大写 Helloworld
a.title() # 把字符串的每个单词的首个字母大写
a.startswith('h') # True 以 h 开头
a.endswith('d') # True 以 d 结尾
a.lower() # 全部小写 helloworld
a.upper() # HELLOWORLD
a.center(20) # '     helloworld     '
a.ljust(20) # 'helloworld          '
a.rjust(20) # '          helloworld'
a.lstrip('h') # 删除左边的 h, elloworld
a.rstrip('d') # helloworl
b = a.center(20)
b.strip() # 删除两边的空白 helloworld
a.partition('o') # 以 o 为中心切分成元组 ('hell', 'o', 'world')
a.rpartition('o') # ('hellow', 'o', 'rld')
c = 'hello\nworld'
c.splitlines() # 按照换行符切割 ['hello', 'world']
a.isalpha() # 判断是不是纯字母 True
a.isdigit() # 判断是不是纯数字 False
d = '1i0'
d.isalnum() # 判断既有数字也有字母 True
a.isspace() # 是否包含空格 False
','.join(['hello', 'world']) # hello,world
e = 'qer \tque\t ri qu\te ir\nu qw ru qw ie'
''.join(e.split()) # 'qerqueriqueiruqwruqwie'

列表(可变类型)

# range 在 python2 中数值太大占用的内存也大,3 中解决来这个问题
# 列表生成器
a = [x for x in range(1, 5)]
# [1, 2, 3, 4]
print(a) 

list = ['php', 'python', 'js', 'java']

# True
'js' in list 

# ['php', 'python', 'js', 'java', 100]
list.append(100) 

# ['A', 'php', 'python', 'js', 'java', 100]
list.insert(0, 'A') 

# ['A', 'php', 'python', 'js', 'java', 100, 'Tom', 'Boy']
list.extend(['Tom', 'Boy']) 

# ['A', 'php', 'python', 'js', 'java', 100, 'Tom'] 
list.pop() 

# ['A', 'php', 'python', 'js', 'java', 'Tom']
list.remove(100) 

# ['python', 'js']
list[2:4] 

# ['php', 'python', 'js', 'java', 'Tom']
del list[0] 

# ['Tom', 'java', 'js', 'python', 'php']
list.reverse() 

# 1
list.count('js') 

# ['Tom', 'java', 'js', 'php', 'python']
list.sort() 

list.clear() # []

# 遍历, start 表示下标从 1 开始
for index, value in enumerate(list, start=1):
    print('{0}-{1}'.format(index, value))
else:
    print('='*10)

# 反向遍历
for l in reversed(list):
    print(l)

for l in sorted(list, reverse=True):
   print(l)

# 遍历 2 个列表
names = ['raymond', 'rachel', 'matthew']
colors = ['red', 'green', 'blue', 'yellow']

for name, color in zip(names, colors):
   print(name, '---', color)

# 用 key-value 对构建字典  
# {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'}
dict(zip(names, colors))
# 'blue'
dict(zip(names, colors)).get('matthew', 0)

字典(可变类型)

dict = {'name':'Tom','age':18}

# {'age': 18, 'name': 'Tom', 'phone': 10086}
dict['phone'] = 10086 

# {'age': 18, 'name': 'Tom'}
del dict['phone']

# {'age': 20, 'name': 'Tom'}
dict['age'] = 20

# 20
dict.get('age')

# dict_keys(['name', 'age'])
dict.keys()

# dict_values(['Tom', 20])
dict.values()

# dict_items([('name', 'Tom'), ('age', 20)])
dict.items()

# {'age': 18, 'name': 'Tom', 'new': ['year']}
dict.setdefault('new', []).append('year')

for a, b in dict.items():
    print('%s=>%s'%(a, b))

元组(不可变类型)

# 定义一个要加 ,
demo = (1,)

tuple = (1, 2, 3)

# 3
len(tuple)

# 3
max(tuple)

# 1
min(tuple)

# (1, 2, 3, 4, 5, 6)
tuple + (4, 5, 6)

# True
3 in tuple

for t in tuple:
    print(t)

条件控制

if "" or None or 0 or [] or {}:
    print('-')
else:
    print('+')

函数

def t(a, b=2, c=3):
    print(a, b, c)

# 1 2 3    
t(1)

# 2 2 5 
t(c=5, a=2)

def t(a, b=2, c=3, *args, **kwargs):
    print(a, b, c, args, kwargs)

# 1 2 3 (4, 5, 6) {'one': 1, 'two': 2}
t(1, 2, 3, 4, 5, 6, one=1, two=2)

tuple = (4, 5, 6)
dict = {'one': 1, 'two': 2}
t(1, 2, 3, *tuple, **dict) # 1 2 3 (4, 5, 6) {'one': 1, 'two': 2}

# 匿名函数
sum = lambda x, y: x + y
# 2
print(sum(1, 1))

a = [{'name': 'hello', 'age': 20}, {'name': 'world', 'age': 18}, {'name': 'google', 'age': 10}]
# 排序
a.sort(key = lambda x: x['age'])

# [{'name': 'google', 'age': 10}, {'name': 'world', 'age': 18}, {'name': 'hello', 'age': 20}]
print(a)

变量作用域

def a():
    width = 18
    height = 18
    print(locals())

# {'height': 18, 'width': 18}
a()

动态添加方法

class P(object):
    # 只对当前实例起作用
    __slots__ = ('name', 'say')

    def __init__(self, name):
        self.name = name

import types

def say(self):
    print('{0} {1}'.format(self.name, 'say'))

t = P('Tom')
# 动态添加方法
t.say = types.MethodType(say, t)
t.say() # Tom say

t.age = 10 # 'P' object has no attribute 'age'

引用

a = [1, 2, 3]
b = a
id(a) # 4394537672
id(b) # 4394537672

a.append(4)
a 和 b : [1, 2, 3, 4]

三元表达式

a = 1

# result = x if condition else y

(2, 3)[a != 1] # 2
(2, 3)[a == 1] # 3

递归

def factorial(n):
    if n == 0 or n == 1:
        return 1
    else:
        return (n * factorial(n - 1))

def factorial(n):
    r = 1
    if n > 0:
        for i in range(1, n + 1):
            r *= i
        return r
    elif n == 1:
        return 1
    else:
        return n

n = factorial(5)
print(n) # 120

文件操作

f = open('one.txt','r')

# 返回文件当前位置
f.tell()

# offset -- 开始的偏移量,也就是代表需要移动偏移的字节数
# whence:可选,默认值为 0。给offset参数一个定义,表示要从哪个位置开始偏移;0代表从文件开头开始算起,1代表从当前位置开始算起,2代表从文件末尾算起。
fileObject.seek(offset[, whence])
f.seek(2,0)

class Sample:
    """
    r 只读
    w 写入,如果文件存在就覆盖,无则创建
    a 追加,文件存在指针在结尾,文件不存在则创建写入
    rb 二进制
    wb
    ab
    r+ 打开文件读写,指针在开头
    w+ 打开文件读写,如果文件存在就覆盖,无则创建
    a+ 打开文件读写,文件存在指针在结尾,文件不存在则创建写入
    """
    def __enter__(self):
        self.f = open('one.txt', 'a+')
        return self

    def __exit__(self, type, value, trace):
        self.f.close()
        print("type:", type)
        print("value:", value)
        print("trace:", trace)

    def do_write(self, str):
        self.f.write(str + "\n")

    def do_copy(self):
        old_name = input('复制那个文件?')
        file_name = input('复制到哪里?')
        old_f = open(old_name + '.txt', 'r')
        new_f = open(file_name + '.txt', 'a+')
        cen = old_f.read(1024)
        while len(cen) == 0:
            old_f.close()
            new_f.close()
            break
        new_f.write(cen)

with Sample() as sample:
    sample.do_copy()

OS

import os

# 返回当前工作目录
os.getcwd()

# 改变默认目录
os.chdir('./')

# 列出目录列表
os.listdir('./')

# 重命名文件或目录,从 src 到 dst
os.rename(src, dst)

面向对象

# 类定义
class People(object):
    # 定义基本类属性
    name = ''
    age = 0
    # 定义私有属性,私有属性在类外部无法直接进行访问,不能被继承
    __weight = 0

    # 构造方法,在生成对象时调用
    def __init__(self, n, a, w):
        self.name = n
        self.age = a
        self.__weight = w

    def __str__(self):
        return "%s 说: 我 %d 岁。" %(self.name, self.age)

    @classmethod
    def set_age(cls):
        """ 定义类方法,至少有一个 cls 参数 """
        cls.age = 20

    @staticmethod
    def p():
        """ 定义静态方法,无默认参数 """
        print('静态方法')

    # 私有方法,在类外部无法直接进行访问,不能被继承
    def __say(self):
        return '私有属性__weight: {0}'.format(self.__weight)

    def speak(self):
        """ 定义普通方法,至少有一个 self 参数 """
        s = self.__say()
        print(s)

    # 析构方法,释放对象时使用
    def __del__(self):
        print('-end-'.center(20))

# 单继承示例
class Student(People):
    grade = ''

    def __init__(self, n, a, w, g):
        # 调用父类的构函
        People.__init__(self, n, a, w)
        #super().__init__(self, n, a, w)
        self.grade = g

    # 覆写父类的方法
    def speak(self):
        # 调用父类的方法
        super().speak()
        print("%s 说: 我 %d 岁了,我在读 %d 年级"%(self.name, self.age, self.grade))

# 另一个类,多重继承之前的准备
class Speaker(object):
    topic = ''
    name = ''
    def __init__(self,n,t):
        self.name = n
        self.topic = t
    def speak(self):
        print("我叫 %s,我是一个演说家,我演讲的主题是 %s"%(self.name,self.topic))

# 多重继承
class Sample(Speaker, Student):
    a =''
    def __init__(self, n, a, w, g, t):
        Student.__init__(self, n, a, w, g)
        Speaker.__init__(self, n, t)

# -------------------

# 实例化类
p = People('Tom', 10, 30)

# Tom 说: 我 10 岁。
print(p)

# 私有属性__weight: 30
p.speak()

# -------------------

s = Student('Ken', 10, 60, 3)
s.speak()

# -------------------

test = Sample("Tim", 25, 80, 4, "Python")
test.speak()   # 方法名同,默认调用的是在括号中排前地父类的方法

# -------------------

# 查看对象的引用次数
import sys
num = sys.getrefcount(p)
print(num)

property 的使用

class Test(object):
    """docstring for Test"""
    def __init__(self, arg):
        super(Test, self).__init__()
        self.__arg = arg

    def setArg(self, arg):
        self.__arg = arg

    def getArg(self):
        return self.__arg

    arg = property(getArg, setArg)

class Test1(object):
    """docstring for Test1"""
    def __init__(self, arg):
        super(Test1, self).__init__()
        self.__arg = arg

    @property
    def arg(self):
        return self.__arg

    @arg.setter
    def arg(self, arg):
        self.__arg = arg

t = Test(10)
print(t.arg) # 10
t.arg = 100
print(t.arg) # 100

print('='*20)

t1 = Test1(50)
print(t1.arg) # 50
t1.arg = 500
print(t1.arg) # 500

单例模式

# 类定义
class People(object):
    __instance = None

    def __new__(cls, n):
        """ 单例模式 """
        if cls.__instance == None:
            cls.__instance = object.__new__(cls)
            return cls.__instance
        else:
            return cls.__instance

    # 构造方法,在生成对象时调用
    def __init__(self, n):
        self.name = n

# -------------------

# 实例化类
t = People('Tom')
j = People('Jim')
print(id(t) == id(j)) # True
print(t.name)
print(j.name)

装饰器

def a(fn):
    print('a')
    def aa(*args, **kwargs):
        print('-1-')
        return '<i>' + fn(*args, **kwargs) + '</i>'
    return aa

def b(fn):
    print('b')
    def aa(*args, **kwargs):
        print('-2-')
        return '<b>' + fn(*args, **kwargs) + '</b>'
    return aa

def c(fn):
    print('c')
    def aa(*args, **kwargs):
        print('-3-')
        return '<u>' + fn(*args, **kwargs) + '</u>'
    return aa

# python 解释器执行到这里时,已经进行了装饰,而不是调用的时候才装饰
@a
@b
@c
def test(a, b, c):
    print('-0-')
    return '{0} {1} {2}'.format(a, b, c)

p = test('hello', 'world', '!')
print(p)
"""
c
b
a
-1-
-2-
-3-
-0-
<i><b><u>hello world !</u></b></i>
"""

装饰器参数

def a(str):
    print('a')
    def b(fn):
        print('b')
        def aa(*args, **kwargs):
            print('-1-')
            if str == 'tom':
                return '<i>' + fn(*args, **kwargs) + '</i>'
            else:
                return fn(*args, **kwargs)
        return aa
    return b

# 1) 先执行 a('tom-') 返回 b 这个函数的引用
# @b
# 使用 @b 装饰
@a('tom-')
def test(a, b, c):
    print('-0-')
    return '{0} {1} {2}'.format(a, b, c)

p = test('hello', 'world', '!')
print(p)
"""
a
b
-1-
-0-
hello world !
"""

类当作装饰器

class Test(object):
    """docstring for Test"""
    def __init__(self, fn):
        self.__fn = fn

    def __call__(self):
        print('__call__')
        self.__fn()

@Test
def say():
    print('say')

say()
"""
__call__
say
"""

使用 type 创建类

def printNum(self):
    print(self.num)

# () 代表元组,放继承的类
Test = type('Test', (), {'num': 100, 'printNum': printNum})
t = Test()
t.printNum() # 100

异常

# _*_ coding:utf-8 _*_

class MyError(Exception):
    """ 创建一个用户自定义异常,异常应该继承自 Exception 类 """
    def __init__(self, message):
        self.message = message
    def __str__(self):
        return repr(self.message)

try:
    s = input('你的名字:')
    if len(s) > 3:
        raise MyError('你名字的长度{0}>{1}'.format(len(s), 3))
except ZeroDivisionError as z:
    print(z)
except Exception as e:
    print(e)
else:
    print('success')
finally:
    print('无论在任何情况下都会执行')

程序传参

# one.py
import sys

argv = sys.argv[1]
print(argv)

# python one.py abc
# abc

模块重新导入

# 比如说已导入模块,但是修改了文件
import test
from imp import *
reload(test)

== is

is 是比较两个引用是否指向同一个对象(引用比较)
== 是比较两个对象是否相等

a = [11, 22, 33]
b = [22, 11, 33]
a == b # False
c = a
a == c # True
a is c # True

深拷贝与浅拷贝

# copy.copy 根据是不是可变类型
a = [11, 22, 33]
b = a
id(a) # 4395634568
id(b) # 4395634568

import copy
c = copy.deepcopy(a)
id(a) # 4395634568
id(c) # 4396989320

a.append(44)
a # [11, 22, 33, 44]
c # [11, 22, 33]

生成器

def test():
    i = 0
    while i < 5:
        temp = yield i
        print(temp)
        i += 1

t = test()
print(t.__next__())
print(t.__next__())
print(t.__next__())
print(t.__next__())
print(t.send('haha')) # t.send(None)
"""
0
None
1
None
2
None
3
haha
4
"""

生成器应用(多任务)

def test():
    while True:
        print('-1-')
        yield None

def test1():
    while True:
        print('-2-')
        yield None

t = test()
t1 = test1()

while True:
    t.__next__()
    t1.__next__()

"""
-1-
-2-
-1-
-2-
-1-
-2-
-1-
-2-
-1-
-2-
...
"""

迭代器

from collections import Iterator
# 判断是不是可迭代
isinstance([], Iterator) # False
isinstance(x for x in range(5), Iterator) # True

a = [1, 2, 3]
next(a) # 'list' object is not an iterator
next(iter(a)) # 1

安装 pip

# pip 是 python 的包管理工具

sudo easy_install pip 

pip --version
pip3 --version

安装 Django

sudo pip install Django==1.11.5
# pip 豆瓣源安装
pip install -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com nltk

# pip 阿里云源安装
pip install -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com nltk

查看 Django 版本

>>> import django
>>> django.VERSION
(1, 11, 5, u'final', 0)
>>>

第一个 Django 项目

# 创建项目
django-admin startproject [djblog]

# 启动
python manage.py runserver

# 帮助
cd djblog
python manage.py help 

安装虚拟环境

virtualenv 是一个创建隔绝的 Python 环境的工具。virtualenv 创建一个包含所有必要的可执行文件的文件夹,用来使用 Python 工程所需的包。

pip3 install virtualenv

创建一个独立的 Python 运行环境

# 参数--no-site-packages,已经安装到系统 Python 环境中的所有第三方包都不会复制过来
# /usr/local/bin/python3, 使用 python3 作为 virtualenv 中的 python 解释器

virtualenv --no-site-packages -p /usr/local/bin/python3 venv

source 进入该环境

source venv/bin/activate

# 查看当前安装包
pip list

# 查看当前安装包及版本号
pip freeze

退出当前的 venv 环境

deactivate

# 退出后你可以直接删除对应的虚拟环境目录,不影响其他环境

注意事项

如果没有启动虚拟环境,系统也安装了 pip 工具,
那么套件将被安装在系统环境中,为了避免发生此事,
可以在 ~/.bashrc 文件中加上:
export PIP_REQUIRE_VIRTUALENV=true
或者让在执行 pip 的时候让系统自动开启虚拟环境:
export PIP_RESPECT_VIRTUALENV=true

virtualenvwrapper

virtualenvwrapper 是 virtualenv 的扩展管理包,用于更方便管理虚拟环境,它可以做:

  1. 将所有虚拟环境整合在一个目录下
  2. 管理(新增,删除,复制)虚拟环境
  3. 切换虚拟环境

安装 virtualenvwrapper

pip3 install virtualenvwrapper

Mac pycharm 环境配置

安装 mysqlclient (解决方案)

报错信息:Command "python setup.py egg_info" failed with error code 1 in

sudo xcodebuild -license accept
brew install mysql-connector-c
brew unlink mysql-connector-c
brew link --overwrite mysql-connector-c
pip install mysqlclient

mysql 启动

brew install mysql
brew services start mysql
mysql.server start
mysql -uroot

本机 mysql 环境是 MAMP

# 修改系统配置文件vi ~/.bash_profile 或者有些人是 ~/.profile
export PATH=$PATH:/Applications/MAMP/Library/bin
export PATH="/usr/local/opt/openssl/bin:$PATH"

# 安装
brew install mysql-connector-c

# 解决方案
mysql_config --libs_r
# 输出位置信息
cd /usr/local/Cellar/mysql-connector-c/6.1.11/bin
# sudo vi mysql_config
libs="-L$pkglibdir"
# 改成
libs="$libs -lmysqlclient -lssl -lcrypto"
# :wq! 保存推出

pip install mysqlclient

创建应用

python manage.py startapp [name]

生成数据库表

makemigrations
python manage.py migrate

测试数据

python manage.py shell

创建一个超级管理员

python manage.py createsuperuser

安装 xadmin

# 下载 zip 的压缩包
https://github.com/sshwsfc/xadmin

# 安装依赖包
pip install httplib2 django-formtools django-crispy-forms django-import-export

# 放入项目中,在setting.py
sys.path.insert(0, os.path.join(BASE_DIR, 'xadmin'))

# setting.py
INSTALLED_APPS = [
    ...,
    'xadmin',
    'crispy_forms',
    'import_export'
]

# urls.py
import xadmin
urlpatterns = [
    url(r'^admin/', xadmin.site.urls)
]

本文章首发在 PythonCaff