第一階段——CentOS6_Python3.6.1筆記(尚學堂-Python基礎快速入門)+ 【補充】麥子-Python程序入門與進階

虛擬機環境:html

設置網絡

  1、修改網絡地址
    1.設置網卡爲nat模式
    2.確保物理機啓動dhcp、net服務
    3.編輯文件:vim /etc/sysconfig/network-scripts/ifcfg-eth0
    4.ONBOOT=yes
    5.設置IP:
        static:
            IPADDR=
            NETMASK=
            GATEWAY=
    6.重啓網絡:service network restart
    7.檢查:ping 網關
    8.ping baidu.com
    9.設置DNS服務
        vi /etc/resolv.conf
        nameserver 114.114.114.114

 

Centos修改DNS重啓或重啓network服務後丟失問題解決方法:

vim /etc/sysconfig/network-scripts/ifcfg-eth0

插入如下2條

DNS1=114.114.114.114

DNS2=8.8.8.8

:wq! #保存退出

 

查看網卡UUID

    [root@huis ~]# nmcli con | sed -n '1,2p'

 

桌面與終端切換
    su root
    
    more /etc/init
    init3    #終端
    init5    #桌面

 

目錄名稱    應放置文件的內容    

/boot    開機所需文件——內核,開機菜單及所需配置文件等    

/dev    任何設備與接口都以文件形式存放在此目錄    

/etc    配置文件    

/home    用戶主目錄    

/bin    單用戶維護模式下還可以被操做的命令    

/lib    開機時用到的函數庫及/bin與/sbin下面命令要調用的函數    

/sbin    開機過程當中須要的    

/media    通常掛載或刪除的設備    

/opt    放置第三方的軟件    

/root    系統管理員的主文件夾    

/srv    一些網絡服務的數據目錄    

/tmp    任何人都可使用的「共享」臨時目錄    

/proc    虛擬文件系統,例如系統內核,進程,外部設備及網絡狀態等    

/usr/local    用戶自行安裝的軟件    

/usr/sbin    非系統開機時須要的軟件/命令/腳本    

/usr/share    幫助與說明文件,也可放置共享文件。    

/var    主要存放常常變化的文件,如日誌。    

/lost+found    當文件系統發生錯誤時,將一些丟失的文件片斷存放在這裏  

 

網絡拷貝
    scp -r x/ root@192.168.1.99:/home
   scp root@192.168.1.44:/home/x/1.txt

 

cut命令
    tail -1  /etc/passwd | cut -d':' -f1
    #tail -1 /etc/passwd  打開文件最後一行; | cut -d':'  經過管道根據分界符‘:’進行分割; -f1  分割的第一段

 

文本排序sort
    -n    數值排序
    -r    降序
    -t    字符分隔符
    -k    以哪一個字段爲關鍵字進行排序
    -u    排序後相同的行只顯示一次
    -f    排序時忽略字符大小寫

 

linux shell 轉義符

一些轉義字符的表示的特殊意思

和echo,sed連用時:

\n
表示新行

\r
表示回車

\t
表示水平的製表符

\v
表示垂直的製表符

\b
表示後退符

\a
表示「警告」(蜂鳴或是閃動)

\0xx
翻譯成ASCII碼爲八進制0xx所表示的字符

 

查看文本
    cat、tac、more、less、head、tail、find、grep

管道:| 表示:管道左邊的命令執行的結果傳給右邊的命令。

分屏顯示:    more    less

head    查看前-n行
tail    查看後-n行
tail -f    查看文件尾部,不退出,等待顯示後續追加至此文件的新內容

 

引號
    $ a=10
    1、反引號:``    命令替換     :echo `whoami`
    2、單引號:''    字符串    :echo "$a"    10
    3、雙引號:""    變量替換    :echo '$a'    $a

 

權限:
    用戶管理:useradd,    userdel,    usermod,    passwd,     chsh,    chfn,    finger,    id,    chage

    組管理:groupadd,    groupdel,    groupmod,    gpasswd,

    權限管理:chown,    chgrp,    chmod,    umask

P.S.1:    useradd Leslie
P.S.2:    userdel Leslie
P.S.3:    passwd Leslie;    echo "123123" | passwd --stdin Lesslie #只輸入一次密碼
P.S.5:   id Leslie
P.S.4:   chsh:修改用戶的默認shell;    shfn:修改註釋信息;
P.S.6:    chmod 777 000.txt  #設置爲rwx讀寫執行權限  r=4  w=2  x=1

查看用戶:more /etc/passwd

用戶名:x:用戶ID:組ID:python_CentOS6:用戶home根目錄:/bin/bash

 

建立磁盤

先在虛擬機添加一塊磁盤

》cd /dev
》fdisk sdb
》m
》n    #建立一個分區
》e / p     #e擴展分區;p主分區
》1/2/3/4     #1-4分區號
》1    #扇區起始位置
》786    #扇區結束位置
》m
》w    #寫入分區表並退出

》fdisk -l    #查看分區


》mkfs.ext4/mkfs.ext3 /dev/sdb1    #格式化分區

》mkdir /opt/my_disk
》mount /dev/sdb1 /opt/my_disk/ #掛載

 

系統管理命令

查看進程詳細狀況:    ps -aux    #-a顯示終端因此進程;    -u顯示進程詳細狀態;    -x顯示沒有控制終端的進程;    -w顯示加寬,以便顯示更多信息;    -r只顯示正在運行的進程

動態顯示運行中的進程:    top    #執行top命令後,按下對應的按鍵,對結果進行排序。    M根據內存使用量來排序    P根據CPU佔有率排序    T根據進程運行時間排序    U根據後面輸入的用戶名來篩選進程    K能夠根據後面輸入的PID來殺死進程    q退出    h得到幫助

終止進程:    kill/killall    #》kill -9 PID    殺死指定PID的進程;    》killall tail    殺死全部進程。

關機重啓:    reboot、shutdown、init 0

檢測磁盤空間:    df    #-a顯示全部文件系統的磁盤使用狀況;    -m以1024字節爲單位顯示;    -t顯示各指定文件系統的磁盤空間使用狀況;    -T顯示文件系統

檢測目錄所佔磁盤空間:du

查看或配置網卡信息:    ifconfig    #ipconfig eth0 up/down    啓動/中止指定網卡;    service network restart    重啓全部網卡

查看網絡狀況:    netstat -ntpl

 

壓縮:
tar -zcvf x.tar.gz x/    #z壓縮格式    c壓縮    v壓縮的詳細狀況    x.tar.gz壓縮後的文件    x/要壓縮的那個文件或文件夾

解壓:
tar -zxvf x.tar.gz

 

sed命令下批量替換文件內容   

格式: sed -i "s/查找字段/替換字段/g" `grep 查找字段 -rl 路徑` 文件名

-i 表示inplace edit,就地修改文件

-r 表示搜索子目錄

-l 表示輸出匹配的文件名
s表示替換,d表示刪除

示例:sed -i "s/test1/lgsp_Harold/g"  test00.txt

          把當前目錄下test00.txt裏的test1都替換爲lgsp_Harold

 


軟件安裝管理 安裝軟件步驟:
1、檢查是否已經安裝: rpm -qa | grep jdk #-qa查詢已經安裝的全部包 -qi查詢已經安裝的指定軟件包的詳細信息 -qc查詢已安裝指定的軟件包的配置文件路徑 2、下載軟件包 3、安裝依賴 #rpm -ivh 軟件包 P.S.1: 使用rpm命令安裝軟件不須要指定安裝路徑,rpm文件在製做時已經肯定安裝路徑。

yum install tree/man/ 本地yum源配置:管理rpm軟件包 修改配置本地yum源 yum配置文件: cd
/etc/yum.repos.d/    訪問  https://opsx.alibaba.com/mirror
   centOS幫助》

    一、備份
    mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
    二、下載新的CentOS-Base.repo 到/etc/yum.repos.d/
    CentOS 5
    wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-5.repo
    或者
    curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-5.repo
    CentOS 6
    wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo
    或者
    curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo
    CentOS 7
    wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
    或者
    curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
    三、以後運行yum makecache生成緩存java

    yum repolist  #返回yum列表python

    搭建本地yum源mysql

    放入CentOS-6.9-x86_64-bin-DVD.isolinux

    cd /mnt/c++

    mkdir reposgit

    mount /dev/cdrom /mnt/repos/web

    cd repos/Packages/正則表達式

    cd /etc/yum.repos.d/redis

    cp Centos-6.repo Centos-6.repo.backup

    mv Centos-6.repo my.repo

    vim my.repo

    [base]

    name=CentOS-my  #隨便填

    baseurl=file:///mnt/repos/

    gpgcheck=0  #0不檢測文件是否安全或完整,1檢測。

    gpgkey=http://****  #若是gpgcheck=0,此行刪去

    #其餘配置根據需求自行配置,默認後面多餘配置不須要,全刪。

    #保存退出

    yum clean all

    yum makecache

    yum repolist

    vi /etc/fstab  #自動掛載

    須要下載阿里雲yum源裏面的全部rpm文件:  reposync

    mv my.repo my.repo.backup

    mv Centos-6.repo my.repo.backup Centos-6.repo my.repo

    yum clean all

    yum makecache

    mkdir /opt/repos/

    yum reposync -r base -p /opt/repos/  #下載yum源

 

 

linux-nfs

服務端配置
    1.安裝nfs-utils和rpcbind
    yum install -y nfs-utils rpcbind
    2.設置開機啓動服務
    chkconfig nfs on
    chkconfig rpcbind on
    3.啓動相關服務
    service rpcbind start
    service nfs start
    4.建立共享目錄
    mkdir /share
    5.編輯/etc/exports文件,添加以下內容
    vim /etc/exports
    /share client_ip(rw,no_root_squash,no_subtree_check)

    客戶端的指定方式
    指定ip地址的主機:192.168.44.44
    指定子網中的全部主機:192.168.44.0/24192.168.0,0/255.255.255.0
    指定域名的主機:nfs.test.com
    指定域中的全部主機:*.test.com
    全部主機:.*

    選項說明:
    ro:共享目錄只讀
    rw:共享目錄可讀寫
    all_squash:全部訪問者都映射爲匿名用戶或用戶組
    no_all_squash(默認):訪問用戶先與本機用戶匹配,匹配失敗後,再映射爲匿名用戶或用戶組
    root_squash:未來訪的root用戶映射成匿名用戶或用戶組
    no_root_squash:未來訪的root用戶保持root帳號權限
    anonuid=<UID>:指定匿名訪問用戶的本地用戶UID,默認爲nfsnobody(65534)
    anongid=<GID>:指定匿名訪問用戶的本地用戶組GID,默認爲nfsnobody(65534)
    secure(默認):限制客戶端只能從小於1024的tcp/ip端口鏈接服務器
    insecure:運行客戶端從大於1024的tcp/ip端口鏈接服務器
    sync;將數據同步寫入內存緩衝區與磁盤中,效率低,但能夠保證數據一致性
    async:將數據先保存在內核緩衝區中,必要時才寫入磁盤
    wdelay(默認):檢查是否有相關的寫操做,若是有,則將這些寫操做一塊兒執行,這樣能夠提升效率
    no_wdelay:如有寫操做,則當即執行,應與sync配合使用
    subtree_check(默認):若輸出目錄是一個子目錄,則nfs服務器將檢查其父目錄的權限
    no_subtree_check:即便輸出的目錄是一個子目錄,nfs服務器也不檢查其父目錄的權限,這樣能夠提升效率

    6.刷新配置當即生效
    exportfs -a


客戶端配置
    1.安裝nfs-utils和rpcbind
    yum install nfs-utils repcbind
    2.設置開機啓動服務
    chkconfig nfs on
    chkconfig rpcbind on
    3.啓動服務
    service rpcbind start
    service nfs start
    mkdir -p /mnt/share
    5.掛在目錄
    mount -t  nfs server_ip:/share /mnt/share
    6.查看掛載目錄
    df -h
    7.卸載掛載目錄
    umount /mnt/share
    8.編輯/etc/fstab,開機自動掛載
    vim /etc/fstab
    #在結尾添加一行
    server_ip:/share /mnt/share nfs rw,tcp,intr 0 1

源碼安裝步驟:

1、下載 2、查看源碼(c環境) 3、準備編譯環境(gcc) 4、檢查(依賴,兼容),預編譯 5、編譯 6、安裝 7、配置環境變量 》rpm -qa | grep gcc gcc-4.4.7-18.el6.x86_64 》tar -zxvf Python-3.6.1.tgz
》cd Python-3.6.1 》.
/configure --prefix=/usr/python-3.6.1 #預編譯 》》please run ./configure --enable-optimizations 開啓優化 》yum install zlib* openssl* 》y
》#yum install libffi-devel -y  #Python3.7須要一個新的包libffi-devel,安裝此包以後,再次進行編譯安裝便可。  否則會報ModuleNotFoundError: No module named '_ctypes' 》#.
/configure --prefix=/usr/python-3.7.0 --enable-optimizations #Python3.7.0後續經過pip3 安裝ipython會報找不到SSL,暫未找到解決方法,網上3.6.*的解決方法無效
  》./configure --prefix=/usr/python-3.6.1 --enable-optimizations
  》make #編譯
  》make install #安裝

 

配置python全局環境變量
    》printenv
    》vi ~/.bash_profile    或    vi ~/.bashrc    #修改配置文件
    》PATH=$PATH:/usr/python-3.7.0/bin    #最後一行加這個
    或
    (
    PYTHON_HOME=/usr/python-3.7.0
    PATH=$PATH:$PYTHON_HOME/bin
    )
    》wq!    #保存退出
    》source ~/.bashrc
    》python3

P.S.:環境變量除了配置在~/.bashrc裏面,也能夠配置在/etc/profile。兩者區別:.bashrc爲當前用戶的環境變量配置文件;profile爲整個系統的環境變量配置文件。

 

安裝一個python小工具
    cd /usr/python-3.6.1/bin
    pip3 install ipython

 

解釋器:
》mkdir python
》cd python
》vi Test1.py
#!/usr/python-3.6.1/bin/python
print("hello world")
def main():
    print("結束")
:wq!
》chmod u+x Test1.py
》./Test1.py

 

修改vim製表符空格
》vi ~/.vimrc
set nu
set ts=4
set sw=4

 

python註釋
  #fdff

  '''
  sssss
  ssss
  ddd
  dd
  '''

python編碼
  包含中文時
  #encoding=UTF-8

 

Python關鍵字(保留字):

python3
>>> import keyword
>>> keyword.kwlist
['False', 'None', 'True', 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']

 

money=22
a=44
b="lgsp"
#輸出四位數
print("%04d"%money)
print("%s數字%s字符%s字符"%(money,a,b))
>>>>輸出:
0022
22數字44字符lgsp字符

P.S.1:%s通用,%d數字。若是要填充數字,必須使用%d。每個%表示一個佔位符

#輸出數字包含兩位小數,沒有用0填充
w=3.1415926
print("%.2f"%w)
print("%a%%"%a)
#%%第一個表示轉義符

c=2
c *=1+2-3+4
#c === 8

 

w=float(input("輸入體重:"))
h=float(input("輸入身高:"))
BMI=w/(h**2)
if BMI<18.5:
  print("")
elif 18.5<=BMI<=23.9:
  print("正常")
elif BMI>23.9:
  print("")
print("你的BMI指數:%s"%BMI)

 

i = 1
sum = 0
while i <= 100:
  sum = sum + i
  i += 1
print("%d"%sum)

 

i = 1
sum = 0
while i <= 100:
  if i%2 == 0:
    sum = sum + i
  else:
    pass
  i += 1
print("%d"%sum)

 

y = 1
while y<=10:
  x = 1
  while x<=10:
    print("*",end="")
    x+=1
  print("")
  y+=1
print("結束")

 

x = 1
while x <= 9:
  y = 1
  while y <= x:
    print(x,"*",y,"=",x*y,end="\t")
    y += 1
  print("")
  x += 1
print("結束")

 

age = int(input("輸入:"))
i=1
while True:
  if i==age:
    print("輸出:%d"%i)
    break
  else:
    print("錯了")
  i+=1

 

i=0
while i<10:
  i+=1
  if i%2==0:
    print("%d是偶數"%i)
    continue
  print("當前的i是%dxx"%i)
  print("ok")
else:
  print("else,i爲%d"%i)
print("結束")

 

i=int(input("請輸入行數:"))
a=0
while a<i:
  b=0
  while b<a:
    print(" ",end="")
    b+=1
  c=i-a
  while c>0:
    print("*",end=" ")
    c-=1
  print("")
  a+=1

 

for i in "abcefg":
  print(i)
else:
  print("沒有")

for r in range(1,10):
  print(r)
  

 

a="abcdefg"
i=len(a)
while i>0:
    i-=1
    print(a[i])
my_str="Hello World, My Name Is HuaShuai. My Name Is HuaShuai."
my_str.find("HuaShuai")
my_str.rfind("HuaShuai")
my_str.find("huashuai")
my_str.index("HuaShuai)
my_str.rindex("HuaShuai")
my_str.index("huashuai")
#find找不到返回-1,index找不到報錯
#find,index從坐找;rfind,rindex從右找
my_str.count("HuaShuai")
my_str.replace("HuaShuai","huaShuai")    #所有替換
my_str.replace("HuaShuai","huaShuai",1)    #替換一次
my_str.split(" ")
my_str.split(" ",2)    #下標2,隔成三個段
my_str.partition("World")    #以World做爲切割符,並保留
my_str1="hsad \tasdsadfxc zf dass \tasdas \nasdas das" my_str1.split()
my_str1.split()[-2] title:每一個單詞首字母大寫 capital:字符串第一個字符大寫 startswith:檢查字符串是否以obj開頭,是返回True endswith:檢查字符串是否以obj結束,是返回True file_name
="xxxx.txt" if file_name.endswith(".txt"): print("文本文檔") lower:轉換全部大寫字母爲小寫 upper:轉換全部小寫字母爲大寫 ljust:左對齊 rjust:右對齊 center:居中 a.ljust(50) a.rjust(50) a.center(50) lstrip:去掉左邊空格 rstrip:去掉右邊空格 strip:去掉空格 test_str=" avx " test_str.lstrip() splitlines #按照換行符分割,返回一個包含各行做爲元素的列表 lines="sada\nsndgfgdfg\ndfgfdg\nasdaolzxv" lines.splitlines() isalpha:判斷字符串是否只包含字母,是返回True isdigit:判斷字符串是否只包含數字,是返回True isalnum:判斷字符串是否包含字母或數字,是返回True isspace:判斷是否只包含空格,是返回True join:在每一個元素後面追加一個元素 as=["500","60","990"] "-".join(as)

 

append、extend、insert

num1=[100,200,300,400,"500"]
num1.append("600")
num2=[1,2]
num1.extend(num2)
num1.insert(0,"000")




num1[2]="005"
num1.count("000")
000 in num1
000 not in num1




del、pop、remove
del num1[1]
num1.pop()    #默認刪除最後一個
num1.remove(400)




reverse、sort
num1.reverse()
num1[-1::-1]
num3=[1,3,4,9,50,45,44]
num3.sort()
num3.sort(reverse=True)

 

if 條件表達式:
    pass
elif 條件表達式:
    pass
else:
    pass





while 條件表達式:
    pass
    break
else:
    pass




for 變量(該變量不須要事先聲明) in 字符串或集合
    pass
else:




list
names=[]
names[0]=值



tuple
names=(任何類型)




dist
names={key:value}    #key不能重複,value能夠爲任何類型
names[key]=值




def 函數名():
  pass
def 函數名(參賽1,參賽2,....):
  pass

 

可變類型:【字典、列表】值能夠修改(內存地址不變,所保存的值變化了)、引用能夠修改(變量的內存地址改變了)

不可變類型:【數字、字符串、元組】值不能夠修改,引用能夠修改(=賦值號)

在函數裏面修改全局變量:

  一、當全局變量是可變類型,因此在函數裏面任意修改(值、引用)

  二、若是全局變量是不可變類型,在函數裏面不能修改值,也不能修改引用,除非加上global才能修改引用。

 

def test1(x,y):
  x.replace("c","C")
  y.append(10)
  print("x變量指向的內存地址:%s"%id(x))
  print("y變量指向的內存地址:%s"%id(y))

a="abcdefg"
b=[1,2,3]
print("a變量指向的內存地址:%s"%id(a))
print("b變量指向的內存地址:%s"%id(b))
test1(a,b)

 

def test1(x,y,*args):
  print(x,y)
  print(args)
  sum=x+y
  for i in args:
    sum+=i
  print(sum)

test1(2,3,4,5,6,7)
print("="*50)
def test2(x,*args,**kwargs):
  print(x)
  print(args)
  print(kwargs)
  sum=x
  for i in args:
    sum+=i
  for i in kwargs.values():
    sum+=i
  print(sum)
test2(2,3,4,num1=5,num2=6,num3=7)
print("="*60)
nums=[3,4]
nums2={"num1":5,"num2":6}
test2(2,*nums,**nums2)

 

#遞歸函數
#P.S.1:在函數的內部調用本身自己
#P.S.2:遞歸函數本質是一個方法的循環調用,主要有可能出現死循環
#P.S.3:必定要定義遞歸的邊界(何時退出循環) n
=4 result=1 i=1 while i<=4: result=result*i i+=1 print(result) def test1(n):#定義函數就是計算數字n的階乘 if n==1: return 1 return n*test1(n-1) print(test1(4))

 

#斐波拉契數列
def get_num(n):#獲取斐波拉契數列中第n個數字的值
  if n==1 or n==2:
    return 1
  return get_num(n-1) + get_num(n-2)

nums=[]
for i in range(1,20):
  nums.append(get_num(i))
print(nums)

 

#匿名函數
def test(a,b):
  return a+b
print(test(22,33))
func=lambda a,b:a+b
print(func(22,33))
print("——"*30)


def test1(a,b,func):
  result=func(a,b)
  return result
print(test1(22,33,lambda x,y:x*y))
print("——"*30)


stus=[{"name":"zs","age":"22"},{"name":"lw","age":"44"},{"name":"sv","age":"34"}]
stus.sort(key=lambda x:x["name"])#匿名函數的功能:返回列表中每一個元素(字典)的「name」對應的值
print(stus)
print("——"*30)


def test2(a,b,func):
  result=func(a,b)
  return result
func_new=input("請輸入你的操做:")
func_new=eval(func_new)#把字符串轉換成能夠執行的表達式
print(test2(22,33,func_new))
#控制檯輸入表達式,如:lambda a,b:a+b

 

#數字交換
a=22
b=33

#借用元組
a,b=b,a

#使用中間變量
c=0
c=a
a=b
b=c



#a+=a和a=a+a的區別
def test(num):
  num+=num
  print(num)

a=10
b=[10]
test(a)
test(b)
print(a)
print("——"*30)
print(b)

 

可變類型不能做爲字典的key

 

#打開和關閉文件
# f=open("test1.txt","w")
# f.write("hello\tworld")
# f.close

# f=open("test1.txt","r")
# content=f.read()
# print(content)
# f.close()

#複製文件
source_file="/home/lgsp/Desktop/PythonWorkspace/test1.txt"
#目標文件在當前目錄下,找到原始文件名併到末尾,文件名在原始文件名的前面加上copy-
dest_file="copy-"+source_file[source_file.rfind("/")+1:]
print("目標文件名字:%s"%dest_file)
#打開文件
source_file=open(source_file)
#建立目標文件
dest_file=open(dest_file,"w")
#讀取原始文件
content=source_file.read()
#把讀取的內容寫到目標文件中
dest_file.write(content)
#關閉文件
source_file.close()
dest_file.close()

 

1、獲取當前讀寫的位置tell

#打開一個已經存在的文件
f = open("test.txt","r")
#讀取三個字符
str = f.read(3)
print("讀取的數據是:", str)

#查找當前位置
position = f.tell()
print("當前的文件位置:", position)

#再讀取一個字符
str = f.read(1)
print("當前數據是:", str)

#查找當前位置
position = f.tell()
print("當前的文件位置:", position)




2、定位到某位置
若是在讀寫文件的過程當中,須要從另一個位置進行操做的話,可使用seek(),seek(offset, from)有兩個參數
offset:偏移量
from:方向
        0:表示文件開頭
        1:表示當前位置
        2:表示文件末尾

f.seek(0,0)

f.close()




os模塊
import os
#重命名
os.rename("test1.txt","test2.txt")
#獲取文件絕對路徑
os.path.abspath("test2.txt")
#獲取文件大小
os.path.getsize("test2.txt")


#批量重命名目錄下全部的文件
import os

file_list=os.listdir("test/")
for f in file_list:
  #print(f)
  #從新命名以後目標文件名
  dest_file="re-"+f
  #f爲原始文件名的名字,它不在工做目錄,因此不能使用文件做爲相對路徑
  #f文件的相對路徑爲「test/f。」或者乾脆寫絕對路徑
  #os.rename(f,dest_file)
  #os.rename("test/"+f,"test/"+dest_file)

  #採用絕對路徑的形式寫代碼
  #得到父目錄的絕對路徑  動態獲取絕對路徑
  parent_dir=os.path.abspath("test")
  #文件的絕對路徑=父目錄的絕對路徑+/+文件名
  source_file=os.path.join(parent_dir, f)
  dest_file=os.path.join(parent_dir, dest_file)
  os.rename("test/"+f,"test/"+dest_file)

 

import os

#從/home/python目錄下找包含有test的py文件是哪些?

#包含有test的全部py文件列表
file_list=[]

#遞歸函數,該函數中全部的文件路徑所有采用絕對路徑,parent_dir:文件所在的父目錄的絕對路徑,file_name:表示當前你要處理的文件或者目錄
def find_test(parent_dir,file_name):
  file_abspath=os.path.join(parent_dir,file_name)#當前正在處理的文件或者目錄的絕對路徑
  if os.path.isdir(file_abspath):#判斷當前的文件是一個目錄
    for f in os.listdir(file_abspath):#進入目錄,列出該目錄下全部文件列表
      find_test(file_abspath,f)#遞歸調用本身自己的函數
  else:
    if file_abspath.endswith(".py"):#若是傳入的文件就是一個文件,判斷文件名是否以.py結尾
      if read_and_find_test(file_abspath):#讀取該py結尾的文件,而且看看文件內容中是否包含有test
        file_list.append(file_abspath)
#該函數主要功能:讀取py結尾的文件,而且看看文件內容中是否包含test,若是有就返回True,不然返回False
def read_and_find_test(py_file):
  flag=False#定義一個是否包含test的標記變量,默認文件中不包含test爲False
  f=open(py_file)#打開文件
  while True:#因爲是一行一行的讀取文件,因此須要死循環
    line=f.readline()#讀取其中一行
    if line=='':#文件讀到最後一行,終止循環
      break
    elif "test" in line:
      flag=True
      break
  f.close()
  return flag

# print(read_and_find_test("/home/lgsp/Desktop/PythonWorkspace/test.py"))
find_test("/home/lgsp/Desktop","PythonWorkspace")
print(file_list)

 

import os
def read_stus():
  '''
    zs\t33\t4545423
    ls\t22\t5553344
    ww\t22\t5563320
  '''
  if os.path.exists(file_name):
    f=open(file_name)
    while True:
      student_str=f.readline()
      if student_str=='':
        break
      else:
        student_info_list=student_str.split()
        # print("student_info_list:"+student_info_list)
        student={"name":student_info_list[0],"age":student_info_list[1],"qq":student_info_list[2]}
        # print("student"+student)
        stus.append(student)


def write_student_to_file():
  if os.path.exists(file_name):
    if os.path.exists(backup_file):
      os.remove(backup_file)
    os.rename(file_name,"backup-"+file_name)
  f=open(file_name,"w")
  for student in stus:
    student_str="%s\t%s\t%s"%(student['name'],student['age'],student['qq'])
    f.write(student_str)
    f.write("\n")
  f.close()


def print_menu():
  print("="*30)
  print("學生管理系統".center(30))
  print("輸入1:添加學生")
  print("輸入2:查找學生")
  print("輸入3:修改學生")
  print("輸入4:刪除學生")
  print("輸入5:查看全部學生")
  print("輸入6:退出")

def add_student():
  name=input("請輸入學生姓名:")
  age=int(input("請輸入學生年齡:"))
  qq=input("請輸入學生的QQ號:")

  stu={}#聲明一個字典變量
  stu["name"]=name
  stu["age"]=age
  stu["qq"]=qq
  stus.append(stu)
  print("添加成功")

def search_student(name):
  for item in stus:
    if item["name"]==name.strip():
      print("%s學生存在"%name)
      print_student(item)
      return item
    else:
      print("學生%s沒有找到"%name)

def print_student(item):
  print("%s\t%s\t%s"%(item["name"],item["age"],item["qq"]))

def print_all_students():
  print("序號\t姓名\t年齡\tQQ號")
  for i,item in enumerate(stus,1):
    print("%s\t"%i,end="")
    print_student(item)

def del_student(name):
  student=search_student(name)
  stus.remove(student)
  print("刪除成功")
def main():
  print_menu()
  read_stus()
  while True:
    operate=input("請輸入你想要的操做:")
    if operate=="1":
      add_student()
      write_student_to_file()
    if operate=="2":
      name=input("請輸入要查找的學生姓名:")
      search_student(name)
    if operate=="3":
      pass
    if operate=="4":
      name=input("請輸入要刪除的學生姓名:")
      del_student(name)
      print("刪除學生%s成功"%name)
      write_student_to_file()
    if operate=="5":
      print_all_students()
    if operate=="6":
      break


file_name="stus.json"#存放學生數據的文件
backup_file="backup-stus.json"#存放學生數據的文件
#一個學生一個字典,字典用列表來存儲
stus=[]
main()

 

#定義一個類
class Car:

  def start(self):
    print("汽車啓動")
  
  def print_car_inf(self):
    print("車的名字是:%s,顏色是:%s"%(self.name,self.color))

c=Car()#構建一個對象
c.name="BMW"
c.color="金色"
c2=Car()

c.print_car_inf()
c.start()

 

保留方法:__****__()

class Person:

  def __init__(self):
    self.name="zs"
    self.age="33"
    print("對象初始化")

  def work(self):
    pass

p1 = Person()
print(p1.name)

 

class Person():
  #初始化對象的方法,不是構建對象的方法
  def __init__(self,name,age,height):
    self.name=name
    self.age=age
    self.height=height
  
  def introduce(self):
    print("姓名:%s,年齡:%s"%(self.name,self.age))

p1=Person("zs",15,1.5)
p1.introduce()


'''
  __init__()方法,在建立一個對象時默認被調用,不須要手動調用
  __init__(self)中,默認有1個參數名字爲self,若是在建立對象時傳遞了2個實參,那麼__init__(self)中出了self做爲第一個形參外還須要2個形參,例如__init__(self,x,y)
  __init__(self)中的self參數,不須要開發者傳遞,python解釋器會自動把當前的對象引用傳遞進去
'''

 

class Person():
  #初始化對象的方法,不是構建對象的方法
  def __init__(self,name):
    self.name=name

  #toString()
  def __str__(self):
    return "姓名:%s"%(self.name)
  
  def introduce(self):
    print("姓名:%s"%(self.name))

p1=Person("zs")
print(p1)

'''
  在python中方法名若是是__xxxx__()的,那麼就有特殊的功能,所以叫作「魔法」方法
  當使用print輸出對象的時候,只要本身定義了__str__(self)方法,那麼就會打印從這個方法中return的數據
'''

 

'''
骰子游戲
每次遊戲有2人,每人3顆骰子(dice),估計點數的個數。
'''
import random
class Game:
  def __init__(self,player1,player2):
    self.player1=player1
    self.player2=player2
    print("遊戲初始化成功,能夠開始")

  #開始遊戲
  def start_game(self):
    self.player1.cast()
    self.player2.cast()
    # play1_dice_count_list=[self.player1.dices[0].count,self.player1.dices[1].count,self.player1.dices[2].count]
    # play2_dice_count_list=[self.player2.dices[0].count,self.player2.dices[1].count,self.player2.dices[2].count]
    # print("玩家1拋骰子以後的點數爲:%s"%str(play1_dice_count_list))
    # print("玩家2拋骰子以後的點數爲:%s"%str(play2_dice_count_list))
    print(self.player1)
    print(self.player2)

    def get_win():
      self.player1.guess_dice()
      self.player2.guess_dice()
      #判斷誰贏了

class Player:
  
  def __init__(self,name,sex,*dice):
    self.name=name
    self.sex=sex
    self.dices=dice#表示該玩家擁有的骰子列表(元組)

  #玩家拋骰子
  def cast(self):
    for dice in self.dices:
      dice.move()

    
  #猜點數  
  def guess_dice(self):
    #4個數,2點數
    return (4,2)

  def __str__(self):
    play_dice_count_list=[self.dices[0].count,self.dices[1].count,self.dices[2].count]
    return "姓名爲:%s,投擲的骰子點數信息爲:%s"%(self.name,str(play_dice_count_list))


class Dice:
  def __init__(self):
    self.count=0

  #骰子滾動的方法,滾動以後該骰子的點數肯定了
  def move(self):
    self.count=random.randint(1,6)


#遊戲開始以前準備6顆骰子
d1=Dice()
d2=Dice()
d3=Dice()
d4=Dice()
d5=Dice()
d6=Dice()

#準備兩個玩家,並分配骰子
p1=Player("player1","",d1,d2,d3)
p2=Player("player2","",d4,d5,d6)

#一共要玩5次遊戲
for i in range(1,6):
  print("第%d次遊戲的狀況-------------"%i)
  game=Game(p1,p2)
  game.start_game()
  


#根據業務需求抽象出類
#根據業務需求來分析每一個對象的職責,並在類中定義職責所對應的函數或者方法

 

class User:

  def __str__(self):
    return "用戶名爲:%s,密碼爲:%s"%(self.username,self.password)

  def set_password(self,password):
    if len(password)>=6:
      self.password=password
    else:
      print("密碼:%s,長度不符合規定"%password)


u1=User()
u1.username="華帥"
# u1.password="123456789"
u1.set_password("1236663")
print(u1)

 

私有屬性、私有方法
# 隱藏(私有)屬性   __****
# 若是要輸出隱藏屬性的值,必須在類裏面操做
# 隱藏(私有)方法   __****()


class User:
  def __init__(self,password):
    if len(password)>=6:
      self.__password=password  # 賦值給隱藏屬性
    else:
      print("密碼:%s,密碼不符合規定"%password)

  def __str__(self):
    #調用隱藏方法
    self.__say_hello()

    #返回隱藏屬性的值
    return "__str__輸出隱藏屬性的值:%s"%self.__password

  # 輸出隱藏屬性的值
  def get_password(self):
    return "get_password輸出隱藏屬性的值:%s"%self.__password

  # 隱藏方法
  def __say_hello(self):
    print("隱藏方法的值:" + self.__password)





u1=User("1000233")

# print("直接打印隱藏屬性:"+self.__password)

# 經過方法輸出隱藏屬性的值
print(u1.get_password())


#直接調用隱藏方法
# u1.__say()
print("隱藏方法在只能在類裏面調用;在方法__str__裏面調用")



print(u1)

 

建立對象後,python解釋器默認調用__init__()方法;
當刪除一個對象時,python解釋器也會默認調用__del__()方法
當內存中構建一個對象數據的時候回調__init__()方法
當內存中銷燬(釋放)一個對象時回調__del__()方法
class User:
  def __init__(self):
    print("對象初始化")

  def __del__(self):
    print("對象即將被銷燬,內存回收")


#new一個對象就調用__init__方法
u1=User()

u2=u1

#del內置的函數,刪除內存中的一個對象
del u1

print("--"*30)

del u2
print("++"*30)

#當有1個變量保存了對象的引用時,此對象的引用計數就會加1
#當使用del刪除變量指向的對象時,若是對象的引用計數不是1,好比3,那麼此時只會讓這個引用技術減1,即變成2,當再次調用del時,變成1,若是再調用1次del,此時會真的把對象進行刪除。
#當整個程序執行完了,也會把對象進行刪除。

 

繼承

class Animal:
  
  def __init__(self):
    print("動物的初始化")
    self.name="動物"
  def eat(self):
    print("吃飯")

  def sleep(self):
    print("睡覺")


class Dog(Animal):
  def __init__(self,name):
    print("狗初始化")
    self.name=name
  def shout(self):
    print("旺旺叫")

class Cat(Animal):
  # def __init__(self):
  #   print("貓初始化")
  def catch(self):
    print("抓老鼠")


dog = Dog("小白")
print(dog.name)
dog.eat()

cat = Cat()
print(cat.name)

 

私有方法和私有屬性不能夠被繼承

class Animal:
  
  def __init__(self):
    print("動物的初始化")
    # self.name="動物"
    self.__name="動物"

  def eat(self):
    print("吃飯")

  def sleep(self):
    print("動物的名字:%s"%self.__name)
    print("睡覺")


class Dog(Animal):
  def __init__(self):
    print("狗初始化")
    # self.name=name
  def shout(self):
    print("旺旺叫")



dog = Dog()
# print(dog.__name)
dog.eat()
dog.sleep()

 

多繼承

class Animal:
  
  def __init__(self):
    print("動物的初始化")
    # self.name="動物"
    self.__name="動物"
  def eat(self):
    # print("動物的名字:%s"%self.__name)
    print("吃飯")

  def sleep(self):
    print("睡覺")


class Dog(Animal):
  def __init__(self,name):
    print("狗初始化")
    self.name=name
  def shout(self):
    print("旺旺叫")

class Cat(Animal):
  # def __init__(self):
  #   print("貓初始化")
  def catch(self):
    print("抓老鼠")


class ZangAo(Dog):
  def fight(self):
    print("戰鬥")




dog = Dog("小白")
# print(dog.name)
dog.eat()

cat = Cat()
# print(cat.name)
# cat.eat()


za = ZangAo("藏獒")
za.eat()

 

#多繼承
class A:
  def test(self):
    print("A----test()")

class B:
  def test(self):
    print("B----test()")

class C(A,B):
  def test1(self):
    print("C----test1()")

c=C()
print("多繼承時,方法調用優先順序以繼承順序有關,除去自身的方法,優先調用第一個類的繼承")
print(C.__mro__)#打印繼承調用的優先順序

c.test()  #調用A的

 

方法重寫

#重寫父類方法與調用父類方法
#重寫父類方法
#所謂重寫,就是子類中,有一個和父類相同名字的方法,在子類中的方法會覆蓋掉父類中同名的方法。

class Animal:
  #父類定義init方法
  def __init__(self):
    print("動物的初始化")
    # self.name="動物"
    self.color="黃色"
  def eat(self):
    # print("動物的名字:%s"%self.__name)
    print("吃飯")

  def sleep(self):
    print("睡覺")


class Dog(Animal):
  #__init__方法和父類的__init__名字同樣,因此叫方法的重寫。
  def __init__(self,name):
    super().__init__()  #主動調用父類的init方法
    print("狗初始化")
    self.name=name
  def shout(self):
    print("旺旺叫")

  def eat(self):
    super().eat() #調用父類的eat方法
    print("狗本身的get方法")

class Cat(Animal):
  #重寫父類__init__方法
  def __init__(self):
    print("貓初始化")
  def catch(self):
    print("抓老鼠")


class ZangAo(Dog):
  def fight(self):
    print("戰鬥")



dog = Dog("小白") #若是子類中對某個方法重寫了,優先調用子類本身自己的方法
#雖然init方法重寫了,但是還想自動調用父類的init方法

print(dog.name)
print(dog.color)  #若是子類沒有super().__init__(),父類的對象屬性不能繼承

dog.eat()

 

多態

#多態
class F1():
  def show(self):
    print("F1.show")

class S1(F1):
  def show(self):
    print("S1.show")

class S2(F1):
  def show(self):
    print("S2.show")

def Func(obj):
  obj.show()


s1_obj = S1()
Func(s1_obj)

s2_obj = S2()
Func(s2_obj)

 

實例對象和類對象之間的區別

一、類屬性屬於類

二、類屬性的訪問,能夠經過類名,也能夠經過對象

三、類屬性的修改和刪除,只能經過類名

#類屬性:所屬類,這個類下全部的對象均可以共享這個類屬性。

class User(object):
  name="zs" #公共的類屬性
  __assword="123456"  #私有的類屬性

  def __init__(self,sex,username):
    self.sex=sex
    self.username=username

class QQ_User(User):
  pass

u1=User("","Leslie")
print("對象直接調用類屬性")
print(u1.name)

print("name從父類繼承過來的,因爲name屬於類屬性,能夠直接經過子類來訪問,也能夠經過類的對象來訪問。")
print(QQ_User.name)

print("若是隻能經過對象修改,僅僅給該對象定義了一個對象屬性name,並賦值爲「ww」")
u.name="ww" #本質上沒有修改類屬性,僅僅給該對象定義了一個對象屬性name,並賦值爲「ww」
print(u.name)

print("類屬性修改,只能經過類來修改")
User.name='zl'
print(u.name )


del u.name  # 本質上刪除了對象的name屬性,並無刪除類的屬性
print(User.name)

 

類方法、靜態方法

 

class A(object):

  name="zs"

  def test1(self):
    print("-------------A 的test1方法")

  #類方法必定要在方法的上面加上一個修飾器(java註解),類方法的參數cls,表明當前的類
  @classmethod
  def test2(cls):
    cls.name='ww'
    print("-------------A 的test2方法")

  #靜態方法,屬於類。沒有默認傳遞的參數(self\cls),能夠經過類對象來調用,也能夠經過類名來調用
  @staticmethod
  def test3():
    A.name="ls"
    print("-------------A 的test3方法")

a = A()
a.test2()
A.test2()
print("類方法打印")
print(A.name)


A.test3()
print("靜態方法打印")
print(A.name)

 

設計模式:(__new__())方法

# __new__
class User(object):
  
  def __init__(self,username,password):
    self.username=username
    self.password=password
    print("對象已經構建好,由解釋器自動回調的init方法,對象初始化")

  #new方法是當對象構建的時候由解釋器自動回調的方法。該方法必須返回當前類的對象。
  def __new__(cls,username,password):
    print("User類的對象開始構建")
    return object.__new__(cls)


  def __str__(self):
    return "用戶名:%s,密碼:%s"%(self.username, self.password)

u=User("zs","1234")
print(u)

#__new__()必需要有返回值,返回實例化出來的實例,須要注意的是,能夠return父類__new__()出來的實例,也能夠直接將object的__new__()出來的實例返回。

#__init__()有一個參數self,該self參數就是__new__()返回的實例,__init__()在__new__()的基礎上能夠完成一些其它初始化的動做,__init__()不須要返回值。

#若__new__()沒有正確返回當前類cls的實例,那__init__()將不會被調用,即便是父類的實例也不行。

 

特殊方法名      默認的參數         功能描述
__init__()    self              初始化當前對象
__str__()     self              打印從這個方法中return的數據(打印當前對象)
__del__()     self              刪除當前對象
__new__()     cls               實例化對象

 

單例模式:確保一個類只有一個實例,並且自行實例化並向整個系統提供這個實例,這個類稱爲單例類,單例模式是一種對象建立型模式

單例模式一

# 單例模式
class User(object):
  def __init__(self,name):
    self.name=name

  

u1 = User("zs")
u2 = User("ls")


print(u1==u2)# ==判斷表達式若是返回True,這兩個對象是一個對象,並內存地址相同
print("u1對象的內存地址:%s,u2對象的內存地址:%s"%(id(u1),id(u2)))
# 單例模式
class User(object):

  __instance=None # 私有類屬性

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

  @classmethod
  def get_instance(cls,name):
    if not cls.__instance:  # 若是__instance爲None
      cls.__instance=User(name)
    return cls.__instance
  

# u1 = User("zs")
# u2 = User("ls")

u1 = User.get_instance("zs")
u2 = User.get_instance("ls")
print(u1==u2)# ==判斷表達式若是返回True,這兩個對象是一個對象,並內存地址相同
print("u1對象的內存地址:%s,u2對象的內存地址:%s"%(id(u1),id(u2)))

 

單例模式二

# 單例模式
class User(object):

  __instance=None # 私有類屬性

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

  def __new__(cls,name):
    if not cls.__instance:  # 保證object.__new__()方法只會調用一次
      cls.__instance=object.__new__(cls)  #建立當前類的對象並賦值給__instance
    return cls.__instance


u1 = User("zs")
u2 = User("ls")

print(u1==u2)# ==判斷表達式若是返回True,這兩個對象是一個對象,並內存地址相同
print("u1對象的內存地址:%s,u2對象的內存地址:%s"%(id(u1),id(u2)))

 

工廠模式

#工廠模式
class Person(object):
  def __init__(self,name):
    self.name=name

  def work(self):
    print(self.name + "開始工做了")
    #person完成work,須要使用一把斧頭

    #在原始社會,人須要一把石斧
    # aux = StoneAxe("花崗岩斧頭")
    # aux.cut_tree()

    #使用鋼鐵的斧頭
    axe = SteelAxe("加爵斧頭")
    axe.cut_tree()

class Axe(object):
  def __init__(self,name):
    self.name=name

  def cut_tree(self):
    print("%s斧頭開始砍樹"%self.name)

class StoneAxe(Axe):
  def cut_tree(self):
    print("使用石頭作的斧頭砍樹")

class SteelAxe(Axe):
  def cut_tree(self):
    print("使用鋼鐵作的斧頭砍樹")



# p = Person("原始人")
# p.work()

p = Person("現代人")
p.work()

 

#簡單工廠模式:Simple Factory模式不是獨立存在的設計模式,他是Factory Method模式的一種簡單的、特殊的實現。他也被稱爲靜態工廠模式,一般建立者的建立方法被設計爲static方便調用。
class Person(object):
  def __init__(self,name):
    self.name=name

  def work(self,axe_type):
    print(self.name + "開始工做了")
    #person完成work,須要使用一把斧頭

    #在原始社會,人須要一把石斧
    # aux = StoneAxe("花崗岩斧頭")
    # aux.cut_tree()

    #使用鋼鐵的斧頭
    # axe = SteelAxe("加爵斧頭")
    
    
    #已經有工廠
    axe = Factory.create_axe(axe_type)
    axe.cut_tree()

class Axe(object):
  def __init__(self,name):
    self.name=name

  def cut_tree(self):
    print("%s斧頭開始砍樹"%self.name)

class StoneAxe(Axe):
  def cut_tree(self):
    print("使用石頭作的斧頭砍樹")

class SteelAxe(Axe):
  def cut_tree(self):
    print("使用鋼鐵作的斧頭砍樹")



#工廠類
class Factory(object):
  # 生產斧頭,根據用戶指定的類型來生產
  @staticmethod
  def create_axe(type):
    if type=="stone":
      return StoneAxe("花崗岩斧頭")
    elif type=="steel":
      return SteelAxe("加爵斧頭")
    else:
      print("傳入的類型不對")

# p = Person("原始人")
# p.work()

p = Person("現代人")
p.work("stone")

 

全局函數模式:

#全局函數
class Person(object):
  def __init__(self,name):
    self.name=name

  def work(self,axe_type):
    print(self.name + "開始工做了")
    #person完成work,須要使用一把斧頭

    #在原始社會,人須要一把石斧
    # aux = StoneAxe("花崗岩斧頭")
    # aux.cut_tree()

    #使用鋼鐵的斧頭
    # axe = SteelAxe("加爵斧頭")
    
    
    axe=create_axe(axe_type)
    axe.cut_tree()

class Axe(object):
  def __init__(self,name):
    self.name=name

  def cut_tree(self):
    print("%s斧頭開始砍樹"%self.name)

class StoneAxe(Axe):
  def cut_tree(self):
    print("使用石頭作的斧頭砍樹")

class SteelAxe(Axe):
  def cut_tree(self):
    print("使用鋼鐵作的斧頭砍樹")



#全局函數-替代了以前的工廠類
  # 生產斧頭,根據用戶指定的類型來生產
def create_axe(type):
  if type=="stone":
    return StoneAxe("花崗岩斧頭")
  elif type=="steel":
    return SteelAxe("加爵斧頭")
  else:
    print("傳入的類型不對")

# p = Person("原始人")
# p.work()

p = Person("現代人")
p.work("stone")

 

工廠方法模式

#簡單工廠模式:Simple Factory模式不是獨立存在的設計模式,他是Factory Method模式的一種簡單的、特殊的實現。他也被稱爲靜態工廠模式,一般建立者的建立方法被設計爲static方便調用。
class Person(object):
  def __init__(self,name):
    self.name=name

  def work(self):
    print(self.name + "開始工做了")
    #person完成work,須要使用一把斧頭

    #在原始社會,人須要一把石斧
    # aux = StoneAxe("花崗岩斧頭")
    # aux.cut_tree()

    #使用鋼鐵的斧頭
    # axe = SteelAxe("加爵斧頭")
    
    
    #已經有工廠,person去找工廠生產一把斧頭
    factory=Stone_Axe_Factory()
    axe = factory.create_axe()
    axe.cut_tree()

class Axe(object):
  def __init__(self,name):
    self.name=name

  def cut_tree(self):
    print("%s斧頭開始砍樹"%self.name)

class StoneAxe(Axe):
  def cut_tree(self):
    print("使用石頭作的斧頭砍樹")

class SteelAxe(Axe):
  def cut_tree(self):
    print("使用鋼鐵作的斧頭砍樹")



#工廠類
class Factory(object):
  # 生產斧頭,根據用戶指定的類型來生產
  def create_axe(self):
    pass

class Stone_Axe_Factory(Factory):
  def create_axe(self):
    return StoneAxe("花崗岩斧頭")

class Steel_Axe_Factory(Factory):
  def create_axe(self):
    return SteelAxe("鋼鐵斧頭")


# p = Person("原始人")
# p.work()

p = Person("現代人")
p.work()

'''
工廠方法模式去掉了簡單工廠模式中工廠方法的靜態方法,使得它能夠被子類繼承。對於python來講,就是工廠類被具體工廠繼承。這樣在簡單工廠模式裏集中在工廠方法上的壓力能夠由工廠方法模式裏不一樣的工廠子類來分擔。

抽象的工廠類提供了一個建立對象的方法,也叫作工廠方法。

1、抽象的工廠角色(Factory):這是工廠方法模式的核心,它與應用程序無關。是具體工廠角色必須實現的接口或者必須繼承的父類。
2、具體工廠角色(Stone_Axe_Factory,Steel_Axe_Factory):它含有和具體業務邏輯有關的代碼。由應用程序調用以建立對應的具體產品的對象。
3、抽象產品角色(Axe):它是具體產品繼承的父類或者是實現的接口。在python中抽象產品通常爲父類。
4、具體產品角色(Stone_Axe,Steel_Axe):具體工廠角色所建立的對象就是此角色的實例。由一個具體類實現。
'''

工廠方法模式去掉了簡單工廠模式中工廠方法的靜態方法,使得它能夠被子類繼承。對於python來講,就是工廠類被具體工廠繼承。這樣在簡單工廠模式裏集中在工廠方法上的壓力能夠由工廠方法模式裏不一樣的工廠子類來分擔。

抽象的工廠類提供了一個建立對象的方法,也叫作工廠方法。
一、抽象的工廠角色:這是工廠方法模式的核心,它與應用程序無關。是具體工廠角色必須實現的接口或者必須繼承的父類。
二、具體工廠角色:它含有和具體業務邏輯有關的代碼。由應用程序調用以建立對應的具體產品的對象。
三、抽象產品角色:它是具體產品繼承的父類或者是實現的接口。在python中抽象產品通常爲父類。
四、具體產品角色:具體工廠角色所建立的對象就是此角色的實例。由一個具體類實現。

 

異常捕獲

# 異常捕獲
try: 
  print(a)
  i=1/0 #第4行沒有執行
except (NameError,ZeroDivisionError) as ex: # 要捕獲的異常並賦值給ex,ex表明剛剛捕獲的異常對象
  print("出現異常了") #捕獲到異常以後不會回頭繼續執行以前的代碼
  print(ex)
# 異常基本寫法
a="123"
f=open("text.txt","w")
try:
  f.write("hellio\n")
  # f.write("world %d"%a)
except Exception as ex: #Exception 捕獲全部異常。
  print(ex)
else: # 沒有異常的狀況會自動執行的代碼
  print("else")
finally: # 最終要執行的代碼,無論前面是否出現exception
  print("finally")
  f.close()
# 嵌套異常捕獲
a="123"
f=None
try:
  f=open("text2.txt")
  try:
    content=f.read()
    content.index("hadoop")
  # except ValueError as ex:
  except Exception as ex:
    print(ex)
  finally:
    print("最裏層的finally")
except FileNotFoundError as ex:
  print(ex)
else: # 沒有異常的狀況會自動執行的代碼
  print("else")
finally: # 最終要執行的代碼,無論前面是否出現exception
  print("finally")
  if f:
    f.close()
# 異常傳遞
a="123"
f=None
try:
  f=open("text.txt")
  try:
    content=f.read()
    content.index("hello")
    i = 1/0
  except ValueError as ex:
  # except Exception as ex: #捕獲全部異常類型
    print(ex)
  finally:
    print("最裏層的finally")
except (FileNotFoundError,ZeroDivisionError) as ex:
  print(ex)
  print("外面的try捕獲異常")
else: # 沒有異常的狀況會自動執行的代碼
  print("else")
finally: # 最終要執行的代碼,無論前面是否出現exception
  print("finally")
  if f:
    f.close()
# 自定義異常
class PasswordException(Exception):
  def __init__(self,pw,min_length):
    self.password=pw
    self.min_length=min_length

  def __str__(self):
    return "%s密碼錯誤,密碼的最小長度爲%s"%(self.password,self.min_length)

def reg(username,password):
  if len(password)<6:
    raise PasswordException(password,6) #拋出你指定的異常
  else:
    print("用戶名爲:%s,密碼爲:%s"%(username,password))


try:
  reg("zs","1234")
except Exception as ex: #兩個except 會按照順序先執行第一,若是第一個知足異常類型條件,進入第一excep。不會進入後面的except。
  print("第一個except")
  print(ex)
except PasswordException as ex:
  print("第二個except")
  print(ex)
'''
try:是異常捕獲開始的代碼,try放在特別關心的那段代碼前面
pass1:若是這行代碼出現異常,那麼後面的代碼不會運行
pass2
pass3
except:異常的類型 as ex:捕獲某種類型的異常
except....多個except。按照順序依次比對類型

else:沒有異常時執行

finally:無論有沒有異常都會執行
'''
 
 
模塊

'''
導入方式
import 模塊名:import modname
import random
print(random.randint(0,5))
 
能夠定義別名:import random as rm



from 模塊名 import 函數名:from modname import name1[,name2[,...nameN]]
from random import randint
print(randint(0,5))

from 模塊名 import *
'''
# 模塊

#寫一個工具方法,判斷字符是否爲null,當字符串爲None、'''     '爲null
def isnull(str):
  if not str:
    return True
  elif str.strip()=='':
    return True
  else:
    return False

def test1():
  print("-----------test1-------------")
#使用本身製做的模塊

# import Test38_2_1 as t38_2_1
from Test38_2_1 import isnull,test1
'''
from module1 import *
from module2 import *
#若是兩個模塊中方法名字相同,則在後面引入的覆蓋前面引入的
'''

a='22'
# print(t38_2_1.isnull(a))
print(isnull(a))
test1()

 

包引入

# P.S.1:在python2下,包裏面必須有一個__init__.py的文件,不然沒法正常引入,這個文件能夠沒有內容。
# import my_package.Test38_2_1
from my_package import Test38_2_1

# my_package.Test38_2_1.test1()
Test38_2_1.test1()


# 有__init__.py文件在python3中沒有錯,爲了兼容python二、python3,包的目錄下必須新建一個init文件

 

模塊的發佈和安裝

# 模塊的發佈和安裝
# setup.py

from distutils.core import setup

setup(name="壓縮包的名字",version="版本",description="描述",author="做者",author="郵箱",py_modules=['包名1.模塊名1','包名1.模塊名2','包名2.模塊名1'])



# 進到這個包裏執行    python3 setup.py build    構建模塊

# 生成發佈壓縮包   python3 setup.py sdist

# 安裝
# 1、找到模塊的壓縮包(拷貝到其餘地方)
# 2、解壓
# 3、進入文件夾
# 4、執行命令:python3 setup.py install(若是在install的時候,執行目錄安裝,可使用python3 setup.py install --prefix=安裝路徑)

 

給程序傳參

# 給程序傳參數
import sys
print(sys.argv)
print(sys.argv[1])

 

列表推導式&&set集合

# 列表推導式
#所謂的列表推導式,就是指的輕量級循環建立列表
a=[ i for i in range(1,10)]

a=[ (x,y) for x in range(1,4) for y in range(1,5) ]


#生成一個[[1,2,3],[4,5,6],[7,8,9]....]的列表,最大值在100之內
a=[1,2,3]
b=[ [a[0]+i,a[1]+i,a[2]+i] for i in range(0,98) if i%3==0 ]
b=[ [1+i,2+i,3+i] for i in range(0,98) if i%3==0 ]


#set:集合類型
'''
列表(list)      a=[]                按照前後順序,有下標位[index],元素能夠重複,可變類型(增刪改查)
元組(tuple)     a=()                按照前後順序,有下標位[index],元素能夠重複,不可變類型(只能查)
字典(dict)      a={key:value}       沒有前後順序,沒有下標,key不可重複,value能夠重複,可變類型
集合(set)       a=set() \\a={}      沒有前後順序,沒有下標,元素不可重複,可變類型
'''
# 集合
a={1,2,3,4,5}
a.add(6)  #a={1,2,3,4,5,6}
a.add(6)  #a={1,2,3,4,5,6}  不可重複
a={1,2,2,1,2,2,1,1,1,2,2,2,1,1,}  #a={1,2}
# 相互轉換
l=list(a)
s=set(l)
t=tuple(s)

 

#去重

a=[1,2,3,4,5,6,1,2,3,4]
#可使用set去重


def change_list(li):
  temp=[]
  for i in li:
    if i not in temp:
      temp.append(i)
  return temp

if __name__=="__main__":
  print(change_list(a))

 

#寫出一個函數,給定參賽n,生成n個元素值爲1~n的列表,元素順序隨機,但值不重複
import random
def create_list(n):
  temp=[]
  while True:
    if len(temp)==n:
      break
    i=random.randint(1,n)
    if i not in temp:
      temp.append(i)
  return temp

if __name__=="__main__":
  print(create_list(8))

 

#在不使用第三個變量狀況下交換兩個變量值
a=10
b=5
a = a+b   #取兩個數的和
b = a-b   #而後a-b等於a而後賦值給b
a = a-b   #而後a-b等於b而後賦值給a,完成值的交換

#或者
a,b = b,a

 

def extendList(val,list=[]):
  list.append(val)
  return list

list1 = extendList(10)
list2 = extendList(123,['a','b','c'])
list3 = extendList('a')

print("list1=%s"%list1)   #[10,a]
print("list2=%s"%list2)   #['a','b','c',123]
print("list3=%s"%list3)   #[10,a]

#第一次調用extendList方法和第三次調用的時候,兩次調用list形參指向的內存地址是同樣的

 

坦克大戰

# coding=utf-8
# Version:python3.6.1
__date__ = '2018/9/20 18:51'
__author__ = 'Lgsp_Harold'

import pygame, sys, time
from random import randint
from pygame.locals import *


# 坦克大戰主窗口
class TankMain(object):
    width = 600
    height = 500
    my_tank_missile_list = []  # 我方子彈列表
    my_tank = None
    # enemy_list = [] # 敵方坦克列表
    wall=None
    enemy_list = pygame.sprite.Group()  # 敵方坦克的組
    explode_list = []
    enemy_missile_list=pygame.sprite.Group()

    # 開始遊戲的方法
    def startGame(self):
        pygame.init()  # pygame模塊初始化,加載系統的資源
        # 建立一個窗口,窗口大小(寬,高)、窗口的特性(0,RESIZEBLE,RULLscreem)
        screem = pygame.display.set_mode((TankMain.width, TankMain.height), 0, 32)
        pygame.display.set_caption("坦克大戰")

        #   建立一堵牆
        TankMain.wall = Wall(screem,65,160,30,120)

        # my_tank=My_Tank(screem) # 建立一個我方坦克,坦克顯示在屏幕的中下部位置
        TankMain.my_tank = My_Tank(screem)  # 建立一個我方坦克,坦克顯示在屏幕的中下部位置
        if len(TankMain.enemy_list)==0:
            # enemy_list=[]
            for i in range(1, 6):   #   遊戲開始時初始化5個敵方坦克
                # TankMain.enemy_list.append(Enemy_Tank(screem))
                TankMain.enemy_list.add(Enemy_Tank(screem))  # 把敵方坦克放到組裏面

        while True:
            if len(TankMain.enemy_list) < 5:
                TankMain.enemy_list.add(Enemy_Tank(screem))  # 把敵方坦克放到組裏面
            # color RGB(0,0,0)
            # 設置窗口屏幕背景顏色
            screem.fill((0, 0, 0))

            # 面向過程的寫法
            # pygame.draw.rect(screem,(0,255,0),Rect(400,30,100,30),5)

            # 顯示左上角的文字
            for i, text in enumerate(self.write_text(), 0):
                screem.blit(text, (0, 5 + (15 * i)))

            #   顯示遊戲中的牆,而且對牆和其餘對象進行碰撞檢測
            TankMain.wall.display()
            TankMain.wall.hit_tank()

            self.get_event(TankMain.my_tank,screem)  # 獲取事件,根據獲取事件進行處理
            if TankMain.my_tank:
                TankMain.my_tank.hit_enemy_missile()    #   我方坦克和敵方的炮彈碰撞檢測
            if TankMain.my_tank and TankMain.my_tank.live:
                TankMain.my_tank.display()  # 在屏幕上顯示我方坦克
                TankMain.my_tank.move()  # 在屏幕上移動的我方坦克
            else:
                # del(TankMain.my_tank)
                # TankMain.my_tank=None
                # print("Game Over")
                # sys.exit()
                TankMain.my_tank=None
            #   顯示和隨機移動全部的敵方坦克
            for enemy in TankMain.enemy_list:
                enemy.display()
                enemy.random_move()
                enemy.random_fire()

            #  顯示全部的我方炮彈
            for m in TankMain.my_tank_missile_list:
                if m.live:
                    m.display()
                    m.hit_tank()    # 炮彈打中敵方坦克
                    m.move()
                else:
                    TankMain.my_tank_missile_list.remove(m)

            #  顯示全部的敵方炮彈
            for m in TankMain.enemy_missile_list:
                if m.live:
                    m.display()
                    m.move()
                else:
                    TankMain.enemy_missile_list.remove(m)

            for explode in TankMain.explode_list:
                explode.display()

            # 顯示重置
            time.sleep(0.05)  # 每次休眠0.05秒跳到下一幀
            pygame.display.update()

    # 獲取全部的事件(敲擊鍵盤,鼠標點擊事件)
    def get_event(self, my_tank,screem):
        for event in pygame.event.get():
            if event.type == QUIT:  # 程序退出
                self.stopGame()
            if event.type == KEYDOWN and (not my_tank) and event.key == K_n:
                TankMain.my_tank = My_Tank(screem)
            if event.type == KEYDOWN and my_tank:
                if event.key == K_LEFT or event.key == K_a:
                    my_tank.direction = "L"
                    my_tank.stop = False
                    # my_tank.move()
                if event.key == K_RIGHT or event.key == K_d:
                    my_tank.direction = "R"
                    my_tank.stop = False
                    # my_tank.move()
                if event.key == K_UP or event.key == K_w:
                    my_tank.direction = "U"
                    my_tank.stop = False
                    # my_tank.move()
                if event.key == K_DOWN or event.key == K_s:
                    my_tank.direction = "D"
                    my_tank.stop = False
                    # my_tank.move()
                if event.key == K_ESCAPE:
                    self.stopGame()
                if event.key == K_SPACE:
                    m = my_tank.fire()
                    m.good = True  # 我方坦克發射的炮彈,好炮彈
                    TankMain.my_tank_missile_list.append(m)

            if event.type == KEYUP and my_tank:
                if event.key == K_LEFT or K_RIGHT or K_UP or K_DOWN:
                    my_tank.stop = True

            if event.type == MOUSEBUTTONUP:
                pass

    # 關閉遊戲
    def stopGame(self):
        sys.exit()

    # 在遊戲窗口內左上角顯示文字內容
    def write_text(self):
        font = pygame.font.SysFont("方正蘭亭超細黑簡體", 16)  # 定義一個字體
        # 文字,抗鋸齒,字體顏色
        text_sf1 = font.render("敵方坦克數量爲:%d" % len(TankMain.enemy_list), True, (255, 0, 0))  # 根據字體建立一個文件的圖像
        text_sf2 = font.render("我方坦克炮彈數量爲:%d" % len(TankMain.my_tank_missile_list), True, (255, 0, 0))  # 根據字體建立一個文件的圖像
        return text_sf1, text_sf2


# 坦克大戰遊戲中全部對象的父類
class BaseItem(pygame.sprite.Sprite):
    def __init__(self, screem):
        pygame.sprite.Sprite.__init__(self)
        # 全部對象共享的屬性
        self.screem = screem

    # 把坦克對應圖片顯示在遊戲窗口上
    # 在遊戲屏幕中顯示當前遊戲的對象
    def display(self):
        if self.live:
            self.image = self.images[self.direction]
            self.screem.blit(self.image, self.rect) #   把圖片畫在屏幕上


# 坦克公共父類
class Tank(BaseItem):
    # 定義類屬性,全部坦克對象高和寬都是同樣
    width = 50
    height = 50

    def __init__(self, screem, left, top):
        super().__init__(screem)
        # self.screem=screem  # 坦克在移動或者顯示過程當中須要用到當前遊戲的屏幕
        self.direction = 'D'  # 坦克的方向,默認方向向下(上下左右)
        self.speed = 5  # 坦克移動的速度
        self.stop = False
        self.images = {}  # 坦克的全部圖片,key:方向,value:圖片路徑(surface)
        self.images['L'] = pygame.image.load("../img/p1tankL.gif")
        self.images['R'] = pygame.image.load("../img/p1tankR.gif")
        self.images['U'] = pygame.image.load("../img/p1tankU.gif")
        self.images['D'] = pygame.image.load("../img/p1tankD.gif")
        self.image = self.images[self.direction]  # 坦克的圖片由方向決定
        self.rect = self.image.get_rect()
        self.rect.left = left
        self.rect.top = top
        self.live = True  # 決定坦克是否消滅了
        self.oldTop=self.rect.top
        self.oldLeft=self.rect.left

    def stay(self):
        self.rect.left=self.oldLeft
        self.rect.top=self.oldTop

    # 坦克移動方法
    def move(self):
        if not self.stop:  # 若是坦克不是中止狀態
            self.oldLeft=self.rect.left
            self.oldTop=self.rect.top
            if self.direction == "L":  # 若是坦克的方向向左,那麼只須要改坦克的left就能夠了,left在減小
                if self.rect.left > 0:  # 判斷坦克是否在左邊的邊界上
                    self.rect.left -= self.speed
                else:
                    self.rect.left = 0
            elif self.direction == "R":
                if self.rect.right < TankMain.width:
                    self.rect.right += self.speed
                else:
                    self.rect.right = TankMain.width
            elif self.direction == "U":
                if self.rect.top > 0:
                    self.rect.top -= self.speed
                else:
                    self.rect.top = 0
            elif self.direction == "D":
                if self.rect.bottom < TankMain.height:
                    self.rect.bottom += self.speed
                else:
                    self.rect.bottom = TankMain.height

    def fire(self):
        m = Missile(self.screem, self)
        return m


# 我方坦克類
class My_Tank(Tank):
    def __init__(self, screem):
        super().__init__(screem, 275, 400)  # 建立一個我方坦克,坦克顯示在屏幕的中下部位置
        self.stop = True
        self.live = True

    def hit_enemy_missile(self):
        hit_list=pygame.sprite.spritecollide(self,TankMain.enemy_missile_list,False)
        for m in hit_list:  #   我方坦克中彈
            m.live=False
            TankMain.enemy_missile_list.remove(m)
            self.live=False
            explode = Explode(self.screem,self.rect)
            TankMain.explode_list.append(explode)


# 敵方坦克類
class Enemy_Tank(Tank):

    def __init__(self, screem):
        super().__init__(screem, randint(1, 5) * 100, 200)
        self.speed = 3
        self.step = 12  # 坦克按照某個方向移動的步數
        self.get_random_direction()

    def get_random_direction(self):
        r = randint(0, 4)  # 獲得一個坦克移動方向和中止的隨機數
        if r == 4:
            self.stop = True
        elif r == 2:
            self.direction = "L"
            self.stop = False
        elif r == 0:
            self.direction = "R"
            self.stop = False
        elif r == 1:
            self.direction = "U"
            self.stop = False
        elif r == 3:
            self.direction = "D"
            self.stop = False

    #   敵方坦克按照一個肯定的隨機方向,連續移動12步,而後再次改變方向
    def random_move(self):
        if self.live:
            if self.step == 0:
                self.get_random_direction()
                self.step = 12
            else:
                self.move()
                self.step -= 1

    #隨機開火
    def random_fire(self):
        r=randint(0,50)
        if r==10:
            m=self.fire()
            TankMain.enemy_missile_list.add(m)
        else:
            return

# 炮彈類
class Missile(BaseItem):
    width = 5
    height = 5

    def __init__(self, screem, tank):
        super().__init__(screem)
        self.tank = tank
        self.direction = tank.direction  # 炮彈的方向由所發射的坦克方向決定
        self.speed = 12  # 炮彈移動的速度
        enemymissileImg = pygame.image.load("../img/enemymissile.gif")
        self.images = {}  # 炮彈的全部圖片,key:方向,value:圖片路徑(surface)
        self.images['L'] = enemymissileImg
        self.images['R'] = enemymissileImg
        self.images['U'] = enemymissileImg
        self.images['D'] = enemymissileImg
        self.image = self.images[self.direction]  # 坦克的圖片由方向決定
        self.rect = self.image.get_rect()  # 炮彈的邊界
        #   炮彈座標
        self.rect.left = tank.rect.left + (tank.width - self.width) / 2
        self.rect.top = tank.rect.top + (tank.height - self.height) / 2
        self.live = True  # 決定炮彈是否消滅了
        self.good = False

    def move(self):
        if self.live:  # 若是炮彈還存在
            if self.direction == "L":  # 若是坦克的方向向左,那麼只須要改坦克的left就能夠了,left在減小
                if self.rect.left > 0:  # 判斷坦克是否在左邊的邊界上
                    self.rect.left -= self.speed
                else:
                    self.live = False
            elif self.direction == "R":
                if self.rect.right < TankMain.width:
                    self.rect.right += self.speed
                else:
                    self.live = False
            elif self.direction == "U":
                if self.rect.top > 0:
                    self.rect.top -= self.speed
                else:
                    self.live = False
            elif self.direction == "D":
                if self.rect.bottom < TankMain.height:
                    self.rect.bottom += self.speed
                else:
                    self.live = False

    #   炮彈擊中坦克,第一種我方炮彈擊中敵方坦克;第二種敵方炮彈擊中我方坦克
    def hit_tank(self):
        if self.good:  # 若是炮彈是我方的炮彈
            hit_list = pygame.sprite.spritecollide(self,TankMain.enemy_list,False)
            for e in hit_list:
                e.live=False
                TankMain.enemy_list.remove(e)   # 若是敵方坦克被擊中,從列表中刪除敵方坦克
                self.live=False
                expload = Explode(self.screem,e.rect)   # 產生一個爆炸對象
                TankMain.explode_list.append(expload)


# 爆炸類
class Explode(BaseItem):
    def __init__(self, screem, rect):
        super().__init__(screem)
        self.live = True
        self.images = [pygame.image.load("../img/blast1.gif"),\
                       pygame.image.load("../img/blast2.gif"),\
                       pygame.image.load("../img/blast3.gif"),\
                       pygame.image.load("../img/blast4.gif"),\
                       pygame.image.load("../img/blast5.gif"),\
                       pygame.image.load("../img/blast6.gif"),\
                       pygame.image.load("../img/blast7.gif"),\
                       pygame.image.load("../img/blast8.gif")]
        self.step = 0
        self.rect = rect  # 爆炸的位置和發生爆炸前,炮彈碰到的坦克位置同樣。在構建爆炸的時候把坦克的rect傳遞進來。

    # display方法在整個遊戲運行過程當中,循環調用,每隔0.1秒調用一次
    def display(self):
        if self.live:
            if self.step == len(self.images):  # 最後一張爆炸圖片已經顯示
                self.live = False
            else:
                self.image = self.images[self.step]
                self.screem.blit(self.image, self.rect)
                self.step+=1
        else:
            pass    #   刪除該對象


#   遊戲中的牆
class Wall(BaseItem):
    def __init__(self,screem,left,top,width,height):
        super().__init__(screem)
        self.rect=Rect(left,top,width,height)
        # self.left=left
        # self.top=top
        # self.width=width
        # self.height=height
        self.color=(255,0,0)
    def display(self):
        self.screem.fill(self.color,self.rect)

    #針對牆和其餘坦克或者炮彈的碰撞檢測
    def hit_tank(self):
        if TankMain.my_tank:
            is_hit=pygame.sprite.collide_rect(self,TankMain.my_tank)
            if is_hit:
                TankMain.my_tank.stop=True
                TankMain.my_tank.stay()

        if len(TankMain.enemy_list)!=0:
            hit_list=pygame.sprite.spritecollide(self,TankMain.enemy_list,False)
            for e in hit_list:
                e.stop=True
                e.stay()

        #   敵方炮彈擊中牆,子彈消失
        if TankMain.enemy_missile_list:
            enemy_missile_hit_list=pygame.sprite.spritecollide(self,TankMain.enemy_missile_list,False)
            for e in enemy_missile_hit_list:
                e.stop=True
                e.live=False

        #   我方炮彈擊中牆,子彈消失
        if TankMain.my_tank_missile_list:
            my_tank_missile_hit_list=pygame.sprite.spritecollide(self,TankMain.my_tank_missile_list,False)
            for e in my_tank_missile_hit_list:
                e.stop=True
                e.live=False



tankMain = TankMain()
tankMain.startGame()

if __name__ == '__main__':
    pass

 

查看模塊搜索路徑
import sys
sys.path

添加搜索路徑
sys.path.append('/home/sxt/xxx')
sys.path.insert(0,'/home/sxt/xxx')  # 能夠確保先搜索這個路徑

從新導入模塊
from imp import *
reload(模塊名)

查看python全部的modules:help("modules")

help(sys)
dir(sys)


循環導入
#把import語句放置在函數中
例子:一個系統由兩部分組成,包括A主模塊和B模塊。
其中A模塊包含a1()和a2(),B模塊包含b1(),而且在b1()中會用到a1()。

# A.py
from b1 import B
def a1():
    print("enter a1")
 
def a2():
    print("-------Enter a2-------")
    b1()
    print("++++++++Exit a2+++++++")
 
control()

# B.py
import A
def b1():
    print("enter B calling a1")
    A.a1()

執行A.py
從Traceback看,兩個模塊互相導入,形成導入循環錯誤。

方案:把B.py中的導入模塊語句放在函數中
# B.py
def b1():
    import A
    print("enter B calling ctlCommon")
    A.a1()




is和==
is:是比較兩個引用是否指向了同一個對象(引用比較)
==:是比較兩個對象是否相等(值比較)
例子:
a=[1,2,3]
b=a
a==b  =>  True
a is b  =>  True

c=a[:]
c  =>  [1,2,3]
a==c  =>  True
a is c  =>  False

a=100
b=100
a==b  =>  True
a is b  => True

c=1000
d=1000
c==d  =>  True
c is d  =>  False
'''
Integer a=100實際在內部作了
Integer a = Integer.valueOf(100)的操做。
看Integer.class源碼
這個方法的首先斷言了IntegerCache.high的值大於等於127(關於這裏assert 大於等於127解釋請看補充),不然退出方法。
接着if條件內i須要在low值和high值之間。

能夠看到low爲-128,即if條件須要i在-128和127之間,那麼返回i+128做爲整型數組 cache的下標,用來放在緩存中。這樣也就是說任意一個相同數值的Integer的數,若是在-128和127之間,那麼它們之間的內存地址是相同的。
這也就解釋了爲何Integer a=100,b=100時候a==b返回true。
而若是if條件不知足則返回new Integer(i)。
此時不放入緩存,也就是說不在-128和127範圍內的數它們的內存地址是不相同的,這也就解釋了爲何Integer c=1000,d=1000時候c==d返回false。

補充:
補充說明assert斷言IntegerCache.high的值大於等於127才執行該方法。
看源碼能夠知道high自己沒有值,是h=127賦給它的,而h的值在這以前可能會改變。也就是說緩存上限的127實際上是能夠改變,能夠從VM這個java.lang.Integer.IntegerCache.high中讀取爲上限,可是須要知足這個上限的值確實在-128和127之間。也就是說緩存的容量實際上是能夠改變的。基於這個特色,若是緩存的容量在-128到127之間,那麼咱們爲了使用內存數據的高效性,能夠將範圍內大小的Integer放在同一緩存數組中,而不在範圍內的則不放在緩存數組中,這也就是爲何下面的ValueOf方法中須要斷言assert high值>=127的緣由。
'''


淺拷貝:是對於一個對象的頂層拷貝,通俗的理解是:拷貝了引用,並無拷貝內容

深拷貝:是對於一個對象全部層次的拷貝(遞歸)

import copy
——copy.deepcopy()#深拷貝
——copy.copy()#淺拷貝

淺拷貝對不可變類型和可變類型的copy不一樣(例如=列表和元組)

分片表達式能夠賦值一個序列
字典的copy方法能夠拷貝一個字典
有些內置函數能夠生成拷貝(list)

a=[1,2,3]
b=[4,5,6]
c=[a,b]
c  =>  [[1,2,3],[4,5,6]]
d=c
d  =>  [[1,2,3],[4,5,6]]
a.append(7)
c  =>  [[1,2,3,7],[4,5,6]]
d  =>  [[1,2,3,7],[4,5,6]]
import copy
e=copy.deepcopy(c)
e  =>  [[1,2,3,7],[4,5,6]]
b.append(8)
c  =>  [[1,2,3,7],[4,5,6,8]]
e  =>  [[1,2,3,7],[4,5,6]]

f=copy.copy(c)
f  =>  [[1,2,3,7],[4,5,6,8]]
a.append(9)
c  =>  [[1,2,3,7,9],[4,5,6,8]]
f  =>  [[1,2,3,7,9],[4,5,6,8]]



類的數據隱藏(數據私有化)
XX:公有變量
_X:單前置下劃線:私有化屬性或方法
__XX:雙前置下劃線:避免與子類中的屬性命名衝突,沒法在外部直接訪問(名字重整因此訪問不到)
__XX__:雙先後下劃線:用戶名字空間的魔法對象或屬性。例如:__init____不要本身發明這樣的名字。
XX__:單後置下劃線:用於避免與Python關鍵詞的衝突

經過name mangling(名字重整)目的就是以防子類意外重寫基類的方法或者屬性。如:_Class__object機制就能夠訪問private了
class Test(object):
    def __init__(self):
        self.__num=100

t = Test()
print(t.__num)



爲私有屬性添加getter和setter方法
class Test(object):
    def __init__(self):
        self.__num=100

    def getNum(self):
        return self.__num

    def setNum(self,num):
        if num<100:
            self.__num=num
t = Test()
t.setNum(20)
print(t.getNum())




class Test(object):
    def __init__(self):
        self.__num=100

    def getNum(self):
        return self.__num

    def setNum(self,num):
        if num<100:
            self.__num=num

    num=property(getNum,setNum)
t = Test()
t.num(20)
print(t.num())



property用法
使用property升級getter和setter方法
num=property(getNum,setNum)

使用property取代getter和setter方法
@property
@num.setter

class Test(object):
    def __init__(self):
        self.__num=100

    @property
    def num(self):
        return self.__num
    @num.setter
    def num(self,num):
        if num<100:
            self.__num=num
t = Test()
t.num(20)
print(t.num())



進制、位運算
有符號數和無符號數的概念
原碼、反碼、補碼
——規則:
正數:原碼=反碼=補碼
負數:反碼=符號位不變,其餘位取反
補碼=反碼+1
1的原碼:0000 0000 0000 0001
-1的原碼:1000 0000 0000 0001
-1的反碼:1111 1111 1111 1110
-1的補碼:1111 1111 1111 1111
-負數的補碼轉換原碼的規則:
原碼=補碼的符號位不變 —> 數據位取反 —> 尾+1
-1的補碼:1111 1111 1111 1111
取反:1000 0000 0000 0000
-1的原碼:1000 0000 0000 0001


口訣:除2取餘,按位取反

十六進制hex()
十進制int()
八進制oct()
二進制bin()

字節byte=8位bit
1024byte=1kb
1024kb=1mb
1024mb=1gb
1024gb=1tb

有符號的數:最高位表明符號位  1負數 0正數

 

位運算

位運算
  &按位與
  |按位或
  ^按位異或
  ~按位取反
  <<按位左移
  >>按位右移
用途:直接操做二進制,省內存,效率高

例:
5
0000 0101
左移:
000 01010    10
00 010100    20
num << n   ==>   num*2n

右移:
00000 010    2
000000 01    1
num >> n   ==>   num/2n      (整除)

num=5
num<<1    =>    10
num<<2    =>    20
num>>1    =>    2
num>>2    =>    1


位與
5   0000 0101
3   0000 0011
1   0000 0001

位或
5   0000 0101
3   0000 0011
7   0000 0111

異或
5   0000 0101
3   0000 0011
6   0000 0110

取反
5   0000 0101
-5  1111 1010

 

生成器
第一種方式
  在Python中,一邊循環一邊計算的機制,稱爲生成器:generator
  建立生成器:G=(x for x in range(5))
  能夠經過next()函數得到生成器的下一個返回值
  沒有更多的元素時,拋出Stoplteration的異常
  生成器也可使用for循環,由於生成器也是可迭代對象



第二種方式
def fib(times):       #斐波拉契數列
  n=0
  a,b=0,1
  while n<times:
    yield b   #後面的語句先不執行
    a,b=b,a+b   #交換
    n+=1
  return 'done'


使用__next__()方法
使用send()方法
——next()等價於send(None)
def gen():
  i=0
  while i<5:
    temp=yield i
    print(temp)
    i+=1

生成器的特色:
1、節約內存
二、迭代到下一次的調用時,所使用的參數都是第一次所保留下來的。
def fib(times):
  n=0
  a,b=0,1
  while n<times:
    print(b)
    a,b=b,a+b
    n=n+1
  return "done"

fib(5)
def fib(times):
  n=0
  a,b=0,1
  while n<times:
    yield b
    a,b=b,a+b
    n=n+1
  return "done"

g = fib(5)
next(g)
for x in g:
  print(x)


'''
0,1
1,1
1,2
2,3
3,5
'''
def fib(times):
  n=0

  a,b=0,1
  while n<times:
    yield b
    a,b=b,a+b
    n=n+1
  return "done"

i=0
m=5
z=10
g1 = fib(m)
#next(g1)
while i < m:
  print(g1.__next__())
  i+=1

g2 = fib(z)
g2.send(None)
g2.send("lgsp_Harold")
def gen(times):
  n=0
  while n < times:
    temp = yield n*2    #temp用於接收傳過來的參數
    print(temp)
    n=n+1
  return "done"

g = fib(5) g.send(None) g.send("lgsp_Harold")

 

迭代器

迭代是訪問集合元素的一種方式。迭代器是一個能夠記住遍歷的位置的對象。迭代器只能往前不會後退。

可選迭代對象(Iterable)
——集合數據類型,如list、tuple、dict、set、str等
——生成器帶yield的generator function


如何判斷對象可迭代?
——from collections import Iterable
——isinstance([],Iterator)

迭代器(Iterator):能夠被next()函數調用並不斷返回下一個值的對象稱爲迭代器
——from collections import Iterable
——isinstance((x for x in range(10)),Iterator)
——iter()函數:將可迭代對象轉換成迭代器

 

命名空間(namespace)
——防止命名衝突

全局變量和局部變量
——函數內的變量叫局部變量
——函數外的變量叫全局變量
——globals()和locals()
——局部變量和全局變量的衝突(LEGB原則)
locals -> enclosing function(閉包) -> globals -> builtins(內建)
查看內建模塊dir(__builtin__)

 

閉包

內部函數對外部函數做用域裏變量的引用(非全局變量),則稱內部函數爲閉包

#定義一個函數

def test(number):
  #在函數內部再定義一個函數,而且這個函數用到了外邊函數的變量
  def test_in(number_in):
    print("in test_in 函數,number_in is %d" %number_in)
    return number+number_in

  #其實這裏返回的就是閉包的結果
  return test_in


閉包的應用
def line_conf(a,b):
  def line(x):
    return a*x+b
  return line

line1=line_conf(1,1)
line2=line_conf(4,5)

print(line1(5))
print(line2(5))
def fun3():
  def fun4():
    print("fun4")
  return fun4


ret=fun3()
ret()
def outter(num):
  def inner(num_in):
    print("num_in is %d"%num_in)
    return num+num_in
  return inner

#outter(10)(20)

fun=outter(10)
fun(20)

 

裝飾器
  裝飾器其實就是一個閉包,把一個函數當作參數而後返回一個替代版函數
  裝飾器有2個特性:
    1、能夠把被裝飾的函數替換成其餘函數
    2、能夠在加載模塊的時候當即執行

def w1(func):
  def inner():
    #驗證1
    #驗證2
    #驗證3
    func()
  return inner

@w1
def f1():
  print("f1")



裝飾器(decorator)功能
  1、引入日誌
  2、函數執行時間統計
  3、執行函數前預備處理
  4、執行函數後清理功能
  5、權限校驗等場景
  六、緩存
def doca(func):
  def wrapper():
    print(func.__name__)
    func()
  return wrapper

def fun1():
  print("----1----")

ret=doca(fun1)
ret()


@doca
def fun2():
  print("----2----")

fun2()
#裝飾器例子:

#定義函數:完成包裹數據
def makeBold(fn):
  def wrapped():
    return "<b>" + fn() + "</b>"
  return wrapped

#定義函數:完成包裹數據
def makeItalic(fn):
  def wrapped():
    return "<i>" +  fn() + "</i>"
  return wrapped

@makeBold
def test1():
  return "hello world-1"

@makeItalic
def test2():
  return "hello world-2"

@makeBold
@makeItalic
def test3():
  return "hello world-3"


print(test1())
print(test2())
print(test3())
#裝飾器對有參函數進行裝飾
from time import ctime,sleep
def timefun(func):
  def wrappedfunc(a,b):
    print("%s called at %s"%(func.__name__,ctime()))
    print(a,b)
    func(a,b)
  return wrappedfunc

@timefun
def foo(a,b):
  print(a+b)

foo(3,5)
sleep(2)
foo(2,4)



#裝飾器對無參函數進行裝飾
from time import ctime,sleep
def timefun(func)
  def wrappedfunc():
    print("%s called at %s"%(func.__name__,ctime()))
    func()
  return wrappedfunc

@timefun
def foo():
  print("I am foo")

foo()
sleep(2)
foo()



#裝飾器對不定長參數函數進行裝飾
from time import ctime,sleep
def timefun(func):
  def wrappedfunc(*args, **kwargs):
    print("%s call at %s"%(func.__name__,ctime()))
    func(*args, **kwargs)
  return wrappedfunc

@timefun
def foo(a,b,c):
  print(a+b+c)

foo(3,5,7)
sleep(2)
foo(2,4,9)




#裝飾器對帶有返回值的函數進行裝飾
from time import ctime,sleep
def timefun(func):
  def wrappedfunc():
    print("%s called at %s"%(func.__name__, ctime))
    ret=func()
    return ret
  return wrappedfunc

@timefun
def foo():
  print("I am foo")

@timefun
def getInfo():
  return "----lgsp_Harold----"



#通用裝飾器
# 不定長參數、帶有返回值

 

class Person():
  def __init__(self,name,age):
    self.name=name
    self.age=age

p1 = Person("Harold","44")
p2 = Person("Leslie","19")

Person.addr="北京"    # 爲對象動態添加屬性

p1.addr
p2.addr




# 實例方法
def run(self,speed):
  print("%s在移動,速度%d KM/H"%(self.name,self.speed))


import types    # 爲對象添加實例方法
p1.run =  types.MethodType(run,p1)
p1.run(180)




# 類方法
@classmethod    
def fun1(cls):
  print("ClassMethod")

Person.fun1=fun1  # 爲類添加類方法

p1.fun1()




# 靜態方法
@staticmethod
def fun2(a,b):
  return a+b

Person.fun2=fun2
print(p1.fun2(2,3))

print(p2.fun2(2,3))




# 限制修改對象的屬性
class Student(object):
  __slots__=("name","age")

stu = Student()
stu.name="Harold"
stu.age=22

stu.score=222
【
Traceback(most recent call last):
AttributeError:Student object has no attribute 'score'

p.s.:__slots__定義的屬性僅對當前類實例起做用,對繼承的子類是不起做用的
】




# 類裝飾器
裝飾器函數實際上是這樣一個接口約束,它必須接受一個callable對象做爲參數,而後返回一個callable對象。
通常callable對象都是函數,但也有例外。只要某個對象重寫了__call__()方法,那麼這個對象就是callable的
class Test():
  def __call__(self):
    print("call me")

t = Test()
t()   # call me


class Test(object):
  def __init__(self,func):
    print("---初始化---")
    print("func name is %s"%func.__name__)
    self.__func = func

  def __call__(self):
    print("裝飾器中的功能")
    self.__func()

@Test   # 生成Test的一個對象,因此會調用__init__方法,而且把下面裝飾的函數做爲參數傳進去
def test():
  print("test")

test()    # 若是把這句註釋,從新運行程序,依然會看到「---初始化---」;調用Test的一個對象的__call__方法





對象池
python爲了優化速度,使用了小整數[-5,257)對象池,避免爲整數頻繁申請和銷燬內存空間
同理,單個字符也提供對象池,常駐內存
每個大整數,均建立一個新的對象
對於字符串,單個單詞,不可修改,默認開啓intern機制,採用引用計數機制共用對象,引用計數爲0則銷燬



垃圾回收GC
Garbage collection(垃圾回收)
——爲新生成的對象分配內存
——識別那些垃圾對象
——從垃圾對象那回收內存

Python採用的是引用計數機制爲主,標記-清除和分代收集兩種機制爲輔的策略


Python裏每個東西都是對象,它們的核心就是一個結構體:PyObject

C語言
typedef struct_object{
  int ob_refcnt;
  struct_typeobject*ob_type;
}PyObject;
#define Py_INCREF(op)((op)->ob_refcnt++)    //增長計數
#define Py_DECREF(op) \    //減小計數
if(--(op)->ob_refcnt!=0) \
  ; \
else \
  __Py_Dealloc((PyObject *)(op))



引用計數

引用計數機制的優勢
——簡單
——實時性:一旦沒有引用,內存就直接釋放。不像其餘機制等到特定時間。實時性還帶來一個好處,處理回收內存的時間分攤到了平時。

引用計數機制的缺點
——維護引用計數消耗資源
——循環引用


致使引用計數+1的狀況
——對象被建立,例如a=23
——對象被引用,例如b=a
——對象被做爲參數,傳入到一個函數中,例如func(a)
——對象做爲一個元素,存儲在容器中,例如list1=[a,a]


致使引用技術-1的狀況
——對象的別名被顯式銷燬,例如del a
——對象的別名被賦予新的對象,例如a=24
——一個對象離開它的做用域,例如f函數執行完畢時,func函數中的局部變量(全局變量不會)
——對象所在的容器被銷燬,或從容器中刪除對象



查看一個對象引用次數
a=1000
import sys
sys.getrefcount(a)
 



引用計數的缺陷是循環引用的問題
import gc
class ClassA():
  def __init__(self):
    print("object born,id:%s"%str(hex(id(self))))

  def f2():
    while True:
      c1=ClassA()
      c2=ClassA()
      c1.t=c2
      c2.t=c1
      del c1
      del c2

    #把python的gc關閉
    gc.disable()
    f2()

執行f2(),進程佔用的內存會不斷增大



有三種狀況會觸發垃圾回收:
1、調用gc.collect()
2、當gc模塊的計數器達到閥值的時候
3、程序退出的時候


垃圾回收後的對象會放在gc.garbage列表裏面
gc.get_threshold()獲取的gc模塊中自動執行垃圾回收的頻率
gc.set_threshold(threshold0[,threshold1[,threshold2]])設置自動執行垃圾回收頻率
gc.get_count()獲取當前自動執行垃圾回收的計數器,返回一個長度爲3的列表
gc.collect([generation])顯示進行垃圾回收,能夠輸入參數,0表明只檢查第一代的對象,1表明檢查1、二代對象,2表明檢查1、2、三代的對象,若是不傳參數,執行一個full collection,也就是等於傳2。返回不可達(unreachable objects)對象的數目
gc模塊惟一處理不了的是循環引用的類都有__del__方法,因此項目中要避免定義__del__方法




內建屬性
__init__              構造初始化函數                     建立實例後,賦值時使用,在__new__後
__new__               生成實例所需屬性                   建立實例時
__class__             實例所在類                         實例.__class__
__str__               實例字符串表示,可讀性              print(類實例),如沒實現,使用repr結果
__repr__              實例字符串表示,準確性              類實例 回車或者print(repr(類實例))
__del__               析構                               del刪除實例
__dict__              實例自定義屬性                      vars(實例__dict__)
__doc__               類文檔,子類不繼承                  help(類或實例)
__getattribute__      屬性訪問攔截器                      訪問實例屬性時
__bases__             類的全部父類構成元素                類名.__bases__


屬性訪問攔截器
class School(object):
  def __init__(self,subject1):
    self.subject1=subject1
    self.subject2="cpp"

  # 重寫屬性訪問時攔截器,打log
  def __getattribute__(self,obj):
    if obj=="subject1":
      print("log subject1")
      return "redirect python"
    else: # 測試註釋掉這2行試試(注意,若是註釋後面的兩行,其餘屬性會不能正常訪問)
      return object.__getattribute__(self,obj)

s=School("python")
print(s.subject1)
print(s.subject2)



使用屬性訪問攔截器的坑
class Person(object):
  def __getattribute__(self,obj):
    print("--test--")
    if obj.startswith("a"):
      retu "haha"
    else:
      return self.test

  def test(self):
    print("heihei")

t.Person()
t.a   # 返回haha
t.b   # 會讓程序死掉




dir(__builtins__)

range(start,stop[,step])計數從start開始,默認從0開始,到stop結束,但不包括stop;每次跳躍的間距默認爲1

map(function,sequence[,sequence,...])根據提供的函數對指定序列作映射

filter(function or None,sequence)對指定序列執行過濾操做

reduce(function, sequence[,initial])對參數序列中元素進行累積


# 函數須要一個參數
map(lambda x: x*x,[1,2,3])
# 結果爲:[1,4,9]

# 函數須要兩個參數
map(lambda x,y: x+y,[1,2,3],[4,5,6])
# 結果爲[5,7,9]

def f1(x,y):
  return(x,y)

l1=[0,1,2,3,4,5,6]
l2=["sun","M","T","W","T","F","S"]
l3=map(f1,l1,l2)
print(list(l3))
# 結果爲:[(0,"sum"),(1,"M"),(2,"T"),(3,"W"),(4,"T"),(5,"F"),(6,"S")]




filter 返回一個filter對象,是一個迭代器

f=filter(lambda x: x%2,[1,2,3,4])
for item in f:
  print(item)

f=filter(None, "hello")
for item in f:
  print(item)





  在python3裏,reduce()函數已經被從全局名字空間裏移除了,它如今被放置在functools模塊裏
  ——from functools import reduce

  reduce(lambda x,y: x+y,[1,2,3,4])
  10

  reduce(lambda x,y:x+y[1,2,3,4],5)
  15

  reduce(lambda x,y:x+y,['aa','bb','cc'],'dd')
  'ddaabbcc'




偏函數
functools
functools是python2.5被引入的,一些工具函數放在此包裏
-import functools
dir(functools)

partial函數(偏函數)
——把一個函數的某些參數設置默認值,返回一個新的函數,調用這個新的函數會更簡單

wraps函數
——使用裝飾器時,被裝飾後的函數其實已是另一個函數了,(函數名等函數屬性會發生改變)
——wraps的裝飾器能夠消除這樣的反作用



import functools
def showarg(*args,**kwargs):
  print(args)
  print(kwargs)

  p1=functools.partial(showarg,1,2,3)
  p1()    =>    (1,2,3)   {}
  p1(4,5,6)     =>      (1,2,3,4,5,6)   {}
  p1(a='python',b='Harold')     =>      (1,2,3)   {'a':'python','b':'Harold'}

  p2=functools.partial(showarg,a=3,b='linux')
  p2()    =>      ()    {'a'=3,'b'='linux'}
  p2(1,2)     =>    (1,2)   {'a'=3,'b'='linux'}
  p2(a='python',b='Harold')     =>      ()    {'a':'python','b':'Harold'}






消除裝飾器的反作用
import functools
def note(func):
  "note function"
  @functools.wraps(func)    # 消除裝飾器的反作用
  def wrapper():
    "wrapper function"
    print('note something')
    return func()
  return wrapper

@note
def test():
  "test function"
  print("I am test")

test()
print(test.__doc__)     # "test function"





經常使用標準模塊
標準庫                 說明
builtins              內建函數默認加載
os                    操做系統接口
sys                   Python自身運行環境
functools             經常使用的工具
json                  編碼和解碼json對象
logging               記錄日誌,調試
multiprocessing       多進程
threading             多線程
copy                  拷貝
time                  時間
datetime              日期和時間
calendar              日曆
hashlib               加密算法
random                生成隨機數
re                    字符串正則匹配
socket                標準的BSD Sockets API


經常使用第三方模塊
擴展庫                   說明
requests                使用的是urllib3,繼承urllib2的全部特性
urllib                  基於http的高層庫
scrapy                  爬蟲
beautifulsoup4          HTML/XML的解析器
celery                  分佈式任務調度模塊
redis                   緩存
Pillow(PIL)             圖像處理
xlsxwriter              僅寫excle功能,支持xlsx
xlwt                    僅寫excle功能,支持xls,2013或更早版office
xlrd                    僅讀excle功能
elasticsearch           全文搜索引擎
pymysql                 數據庫鏈接庫
mongoengine/pymongo     mongodbpython接口
matplotlib              畫圖
numpy/scipy             科學計算
django/tornado/flask    web框架
xmltodict               xml轉dict
SimpleHTTPServer        簡單地HTTP Server,不使用Web框架
gevent                  基於協程的Python網絡庫
fabric                  系統管理


pdb調試
執行時調試
python -m pdb some.py

交互調試
import pdb
pdb.run("testfun(args)")

程序裏埋點
import pdb
pdb.set_trace()


pdb調試
命令                簡寫命令          做用
break               b                設置斷點
continue            c                繼續執行程序
list                l                查看當前行的代碼段
step                s                進入函數
return              r                執行代碼直到從當前函數返回
quit                q                停止並退出
next                n                執行下一行
print               p                打印變量值
help                h                幫助
args                a                查看傳入參數
回車                                  重複上一條命令
break               b                顯示全部斷點
break lineno        b lineno         在指定行設置斷點
break file:lineno   b file:lineno    在指定文件的行設置斷點
clear num                            刪除斷點
bt                                   查看函數調用棧幀
def note(func):
  def inner():
    "inner"     # 文檔註釋
    print("note----inner")
    return func()
  return inner


@note
def fun():
  "fun"
  print("I am fun")

fun()
print(fun.__doc__)    #inner






# 消除裝飾器反作用
import functools
def note(func):
  @functools.wraps(func)    # 消除裝飾器反作用
  def inner():
    "inner"     # 文檔註釋
    print("note----inner")
    return func()
  return inner


@note
def fun():
  "fun"
  print("I am fun")

fun()
print(fun.__doc__)    #fun

 

多進程
在Unix/Linux操做系統中,提供一個fork()系統函數,它很是特殊
——普通的函數調用,調用一次,返回一次,可是fork()調用一次,返回兩次,由於操做系統自動把當前進程(稱爲父進程)複製了一份(稱爲子進程),而後分別在父進程和子進程內返回
——子進程永遠返回0,而父進程返回子進程ID
——一個父進程能夠fork出不少子進程,因此父進程要記下每個子進程的ID,而子進程只須要調用getppid()就能夠拿到父進程ID
——父進程、子進程執行順序沒有規律,徹底取決於操做系統的調度算法

import os
import random
import time
#coding=utf-8
from multiprocessing import Pool, Process

pid = os.fork()
if pid<0:
  print("fork()調用失敗。")
elif pid==0:
  print("我是子進程(%s),個人父進程是(%s)"%(os.getpid(),os.getppid()))
  x+=1
else:
  print("我是父進程(%s),個人子進程是(%s)"%(os.getpid(),pid))

print("父子進程均可以執行這裏的代碼")




進程不能共享全局變量
num=100
pid = os.fork()
if pid<0:
  print("fork()調用失敗。")
elif pid==0:
  time.sleep(2)
  num+=1
  print("我是子進程(%s),個人父進程是(%s),num:%s"%(os.getpid(),os.getppid(),num))
  x+=1
else:
  time.sleep(3)
  print("我是父進程(%s),個人子進程是(%s),num:%s"%(os.getpid(),pid,num))

print("父子進程均可以執行這裏的代碼")




多個fork()的問題
pid = os.fork()
if pid = 0:
  print("子進程11")
else:
  print("父進程11")

pid = os.fork()
if pid = 0:
  print("子進程22")
elseprint("父進程22")




經過process建立子進程
因爲Python是跨平臺的,天然也應該提供一個跨平臺的多進程支持。
multiprocessing模塊就是跨平臺版本的多進程模塊
multiprocessing模塊提供了一個Process類來表明一個進程對象
# 子進程要執行的代碼
def run_proc(name):
  print("子進程運行中,name=%s,pid=%d..."%(name,os.getpid()))
if __name__=="__main__":
  print("父進程%s."%os.getpid())
  p=Process(target=run_proc,args=("test",))
  print("子進程將要執行")
  p.start()
  p.join()
  print("子進程已結束")




建立子進程時,只須要傳入一個執行函數和函數的參數,建立一個Process實例,用start()方法啓動,這樣建立進程比fork()還要簡單。
Process([group[,target[,name[,args[,kwargs]]]]])
target:表示這個進程實例所調用對象
args:表示調用對象的位置參數元組
kwargs:表示調用對象的關鍵字參數字典
name:爲當前進程實例的別名
group:大多數狀況下用不到
join()方法能夠等待子進程結束後再繼續往下運行,一般用於進程間的同步


Process類經常使用方法:
is_alive():判斷進程實例是否還在執行
join([timeout]):是否等待進程實例執行結束,或等待多少秒
start():啓動進程實例(建立子進程)
run():若是沒有給定target參數,對這個對象調用start()方法時,就將執行對象中的run()方法
terminate():無論任務是否完成,當即終止


Process類經常使用屬性:
name:當前進程實例別名,默認爲Process-N,N爲從1開始遞增的整數
pid:當前進程實例的PID值





進程池
當須要建立的子進程數量不夠時,能夠直接利用multiprocessing中的Process動態生成多個進程,但若是是上百甚至上千個目標,手動去建立進程的工做量巨大,此時就能夠用到multiprocessing模塊提供的Pool方法
初始化Pool時,能夠指定一個最大進程數,當有新的請求提交到Pool中時,若是池尚未滿,那麼就會建立一個新的進程用來執行該請求;但若是池中的進程數已經達到指定的最大值,那麼該請求就會等待,直到池中有進程結束,纔會建立新的進程來執行


def worker(msg):
  t_start=time.time()
  print("%s開始執行,進程號爲%s"%(msg.os,getpid()))
  # random.random()隨機生成0~1之間的浮點數
  time.sleep(random.random()*2)
  t_stop=time.time()
  print(msg,"執行完畢,耗時%0.2f"%(t_stop-t_start))

  pool = Pool(3)  # 定義一個進程池,最大進程數3
  for i in range(0,10):
    # pool.apply_async(需調用的目標,(傳遞給目標的參數元組,))
    # 每次循環將會用空閒出來的子進程去調用目標
    pool.apply_async(worker,(i,))

print("_________start_________")
pool.close()  # 關閉進程池,關閉後po不在接收新的請求
pool.join() # 等待po中全部子進程執行完成,必須放在close語句以後,
print("__________end____________")




進程池使用細節
multiprocessing.Pool經常使用函數解析:
——apply_async(func[,args[,kwds]]):使用非阻塞方式調用func(並行執行,堵塞方式必須等待上一個進程退出才能執行下一個進程),args爲傳遞給func的參數列表,kwds爲傳遞給func的關鍵字參數列表;
——apply(func[,args[,kwds]]):使用阻塞方式調用func
——close():關閉Pool,使其再也不接受新的任務;
——terminate():無論任務是否完成,當即終止
——join():主進程阻塞,等待子進程的退出,必須在close()或terminate()以後使用




進程池中的消息隊列
下面的實例代碼吧。
# 經過Process建立子進程
from multiprocessing import Process
import os
import time
def fun(name):
  time.sleep(3)
  print("子進程id:%d,父進程id:%d,name:%s"%(os.getpid(),os.getppid(),name))    # 子進程打印

print("父進程")
# 建立子進程
p = Process(target=fun,args=("test",))
# 開始執行子進程
p.start()
# 父進程等待子進程結束
p.join()
print("子進程已結束")   # 父進程打印
# Process的經常使用方法和屬性
from multiprocessing import Process
import time

def fun(name,num,**kwargs):
  time.sleep(2)
  print("子進程:name:%s,num:%s"%(name,num))
  for k,v in kwargs.items():
    print("%s:%s"%(k,v))


print("父進程")
p=Process(target=fun,name="p1",args=("test",10),kwargs={"a":10,"b":20})
p.start()
p.join()
print("子進程的名字:%s,id:%s"%(p.name,p.pid))
p.terminate()
print("子進程已結束")



# _______________________________________________________________________________


from multiprocessing import Process
import time

def fun(name,num,**kwargs):
  time.sleep(4)
  print("子進程:name:%s,num:%s"%(name,num))
  for k,v in kwargs.items():
    print("%s:%s"%(k,v))


print("父進程")
p=Process(target=fun,name="p1",args=("test",10),kwargs={"a":10,"b":20})
p.start()
p.join(2)
print("子進程的名字:%s,id:%s"%(p.name,p.pid))
p.terminate()       # 終止進程
print("子進程已結束")
# 子類化Process
from multiprocessing import Process
import os
import time

# 定義本身的繼承類
class MyProcess(Process):
  def __init__(self,interval):
    super().__init__()
    self.interval=interval

  def run(self):
    print("子進程")
    startTime=time.time()
    time.sleep(self.interval)
    stopTime=time.time()
    print("子進程id:%d,父進程id:%d,執行了%ds"%(os.getpid(),os.getppid(),stopTime-startTime))

print("主進程")
startTime=time.time()
p=MyProcess(2)
p.start()
p.join()
stopTime=time.time()
print("子進程已結束,花費了%ds"%(stopTime-startTime))
# 同時建立多個進程

from multiprocessing import Process
import os
import time

# 定義本身的繼承類
class MyProcess(Process):
  def __init__(self,interval):
    super().__init__()
    self.interval=interval

  def run(self):
    print("子進程")
    startTime=time.time()
    time.sleep(self.interval)
    stopTime=time.time()
    print("子進程id:%d,父進程id:%d,執行了%ds"%(os.getpid(),os.getppid(),stopTime-startTime))

print("主進程")
startTime=time.time()
childs=[]
for x in range(5):
  p=MyProcess(x+1)
  p.start()
  childs.append(p)
  # p.join()
for item in childs:
  item.join()
stopTime=time.time()
print("子進程已結束,花費了%ds"%(stopTime-startTime))
# 異步

from multiprocessing import Pool
import time,os

def worker(msg):
  print("子進程pid:%d"%os.getpid())
  startTime=time.time()
  time.sleep(2)
  stopTime=time.time()
  print("子進程msg:%s,花費的時間:%d"%(msg,stopTime-startTime))

# 建立進程池
pool = Pool(3)
for i in range(10):
  pool.apply_async(worker,(i,))     # 異步請求

# 關閉進程池
pool.close()
# 父進程等待進程池的結束
pool.join()
print("進程池已結束")


# ——————————————————————————————————————————————————————————————————————————————————————


# 同步

from multiprocessing import Pool
import time,os

def worker(msg):
  print("子進程pid:%d"%os.getpid())
  startTime=time.time()
  time.sleep(2)
  stopTime=time.time()
  print("子進程msg:%s,花費的時間:%d"%(msg,stopTime-startTime))

# 建立進程池
pool = Pool(3)
for i in range(10):
  pool.apply(worker,(i,))     # 同步請求

# 關閉進程池
pool.close()
# 父進程等待進程池的結束
pool.join()
print("進程池已結束")
from multiprocessing import Process,Queue
import os,time,random

def write(q):
  for item in "ABC":
    print("正在往消息隊列寫入%s"%item)
    q.put(item)
    time.sleep(random.random())

def reader(q):
  while True:
    if not q.empty():
      item = q.get()
      print("從消息隊列讀出%s"%item)
      time.sleep(random.random())
    else:
      break

# 建立消息隊列
q=Queue()
# 建立寫入進程
pw=Process(target=write,args=(q,))
pw.start()
pw.join()
# 建立讀進程
pr=Process(target=reader,args=(q,))
pr.start()
pr.join()

print("全部數據已讀完")











from multiprocessing import Pool,Manager
import os,time,random

def write(q):
  for item in "ABC":
    print("正在往消息隊列寫入%s"%item)
    q.put(item)
    time.sleep(random.random())

def reader(q):
  while True:
    if not q.empty():
      item = q.get()
      print("從消息隊列讀出%s"%item)
      time.sleep(random.random())
    else:
      break

# 建立消息隊列
q=Manager.Queue()
#建立進程池
pool=Pool(3)
# 建立寫入進程
pool.apply(write,(q,))
# 建立讀進程
pool.apply(reader,(q,))

pool.close()
pool.join()


print("全部數據已讀完")

 

多線程

線程:是進程中一個「單一的連續控制流程」(a single sThread,equential flow of control)/執行路徑
——線程又被稱爲輕量級進程。
——Threads run at the same time, independently of one another
——一個進程可擁有多個並行的(concurrent)線程
——一個進程中的線程共享相同的內存單元/內存地址空間->能夠訪問相同的變量和對象,並且它們從同一堆中分配對象->通訊、數據交換、同步操做
——因爲線程間的通訊是在同一個地址空間上進行的,因此不須要額外的通訊機制,這就使得通訊更簡便並且信息傳遞的速度更快

線程和進程的區別
——進程是系統進行資源分配和調度的一個獨立單位
——進程在執行過程當中擁有獨立的內存單元,而多個線程共享內存,從而極大的提升了程序的運行效率
——一個程序至少有一個進程,一個進程至少有一個線程
——線程是進程的一個實體,是cpu調度和分派的基本單位,它是比進程更小的,能獨立運行的基本單位
——線程本身基本上不擁有系統資源,又擁有一點在運行中必不可少的資源(如程序計數器,一組寄存器和棧),可是它可與同屬一個進程的其餘的線程共享進程所擁有的所有資源
——線程的劃分尺度小於進程(資源比進程少),使得多線程程序的併發性高
——線程不能獨立執行,必須依存在進程中
線程和進程在使用上各有優缺點:線程執行開銷小,但不利於資源的管理與保護;而進程正相反。


線程和進程的根本區別:
進程:做爲資源分配單位
線程:調度和執行的單位



多線程
Python的thread模塊是比較底層的模塊
Python的threading模塊是對thread作了一些包裝的,能夠更加方便的被使用

#coding=utf-8
import threading
import time

def saySorry():
  print("親愛的,我錯了,我能吃飯了嗎?")
  time.sleep(2)

if __name__=="__main__":
  for i in range(5):
    t=threading.Thread(target=saySorry)
    t.start()     # 啓動線程,讓線程開始執行



查看線程的數量
#coding=utf-8
import threading,time

def sing():
  for i in range(3):
    print("正在唱歌……%s"%i)
    time.sleep(2)

def dance():
  for i in range(3):
    print("正在跳舞……%s"%i)
    time.sleep(2)

if __name__=="__main__":
  print("開始:%s"%ctime())
  t1=threading.Thread(target=sing)
  t2=threading.Thread(target=dance)

  t1.start()
  t2.start()

  while True:
    length=len(threading.enumerate())
    print("當前運行的線程數爲:%s"%length)
    if length<=1:
      break
    time.sleep(1)



線程的子類化
使用threading模塊時,每每會定義一個新的子類class,只要繼承threading.Thread就能夠了,而後重寫run方法

#coding=utf-8
import threading,time

class MyThread(threading.Thread)
def run(self)
  for i in range(3):
    time.sleep(1)
    msg="I'm"+self.name+"@"+str(i)    # name屬性中保存的是當前線程的
    print(msg)

if __name__=='__main__':
  t=MyThread()
  t.start()



線程的幾種狀態
多線程程序的執行順序是不肯定的。當執行到sleep語句,線程將被阻塞(Blocked),到sleep結束後,線程進入就緒(Runnable)狀態,等待調度。而線程調度將自行選擇一個線程執行。代碼中只能保證每一個線程都運行完整個run函數,可是線程的啓動順序、run函數中每次循環的執行順序都不能肯定。



線程共享全局變量
在一個進程內的全部線程共享全局變量,可以在不適用其餘方式的前提下完成多線程之間的數據共享,(這點要比多進程要好)
缺點就是,線程對全局變量隨意修改可能形成多線程之間對全局變量的混亂(即線程非安全)

from threading import Thread
import time

g_num=100
def work1():
  global g_num
  for i in range(3):
    g_num+=1
  
  print("____in work1,g_num is %d____"%(g_num))

def work2():
  global g_num
  print("____in work2,g_num is %d____"%g_num)

print("線程建立以前,g_num is %d----"%g_num)
t1=Thread(target=work1)
t1.start()
# 延時一會,保證t1線程中的事情作完
time.sleep(1)
t2=Thread(target=work2)
t2.start()




線程同步問題
當多個線程幾乎同時修改某一個共享數據的時候,須要進行同步控制
線程同步可以保證多個線程安全訪問競爭資源,最簡單的同步機制是引入互斥鎖
互斥鎖保證了每次只有一個線程進行寫入操做,從而保證了多線程狀況下數據的正確性
某個線程要更改共享數據時,先將其鎖定,此時資源的狀態爲「鎖定」,其餘線程不能更改;直到該線程釋放資源,將資源的狀態變成「非鎖定」,其餘的線程才能再次鎖定該資源
threading模塊中定義了Lock類,能夠方便的處理鎖定

g_num+=1
g_num=g_num+1
g_num原來存放在內存

操做分紅三步
1、cpu得先從內存將g_num的值讀到寄存器
2、在寄存器中將讀出的數加1
3、將寄存器中的值寫回到內存




線程同步,給線程加鎖

建立鎖
mutex=threading.Lock()

鎖定
mutex.acquire([blocking])
——若是設定blocking爲True,則當前線程會堵塞,直接獲取到這個鎖爲止(若是沒有指定,那麼默認爲True)
——若是設定blocking爲False,則當前線程不會堵塞

釋放
mutex.release()


from threading import Thread,Lock
import time

g_num=0

def test1():
  global g_num
  for i in range(1000000):
    mutexFlag=mutex.acquire(True)
    if mutexFlag:
      g_num+=1
      mutex.release()
  print("----test1----g_num=%d"%g_num)

def test2():
  global g_num
  for i in range(1000000):
    mutexFlag=mutex.acquire(True) # True表示堵塞
    if mutexFlag:
      g_num+=1
      mutex.release()
print("test2-----g_num=%d"%g_num)

# 建立一個互斥鎖
# 默認是未上鎖的狀態
mutex=Lock()
p1=Thread(target=test1)
p1.start()
p2=Thread(target=test2)
p2.start()
print("g_num---%d---"%g_num)




死鎖
在線程間共享多個資源的時候,若是兩個線程分別佔有一部分資源而且同時等待對方的資源,就會形成死鎖
進入到了死鎖狀態,可使用ctrl+z退出

import threading,time
class MyThread1(threading.Thread):
  def run(self):
    if mutexA.acquire():
      print(self.name+"---------do1-------up----------")
      time.sleep(1)
      if mutexB.acquire():
        print(self.name+"-------do1------down------")
        mutexB.release()
      mutexA.release()

class MyThread2(threading.Thread):
  def run(self):
    if mutexB.acquire():
      print(self.name+"-----do2--------up------")
      time.sleep(1)
      if mutexA.acquire():
        print(self.name+"---do2--down-----")
        mutexA.release()
    mutexB.release()

if __name__=="__main__":
  mutexA=threading.Lock()
  mutexB=threading.Lock()

  t1=MyThread1()
  t2=MyThread2()
  t1.start()
  t2.start()




# 經過鎖控制線程的執行順序
from threading import Thread,Lock
from time import sleep

class Task1(Thread):
  def run(self):
    while True:
      if lock1.acquire():
        print("Task1")
        sleep(1)
        lock2.release()

class Task2(Thread):
  def run(self):
    while True:
      if lock2.acquire():
        print("Task2")
        sleep(1)
        lock3.release()

class Task3(Thread):
  def run(self):
    while True:
      if lock3.acquire():
        print("Task3")
        sleep(1)
        lock1.release()

# 使用Lock建立出的鎖默認沒有鎖上
lock1=Lock()
# 建立另外一把鎖,而且鎖上
lock2=Lock()
lock2.acquire()
# 建立另一把鎖,而且鎖上
lock3=Lock()
lock3.acquire()

t1=Task1()
t2=Task2()
t3=Task3()
t1.start()
t2.start()
t3.start()




使用queue在多線程中傳遞數據

線程同步
Python的Queue模塊中提供了同步、線程安全的隊列類,包括:
FIFO(先入先出)隊列Queue
LIFO(後入先出)隊列LifoQueue

這些隊列都實現了鎖原語(能夠理解爲原子操做,即要麼不作,要麼就作完),可以在多線程中直接使用。


import threading,time
# Python2中
# from Queue import Queue
# Python3中
from queue import Queue
class Producer(threading.Thread):
  def run(self):
    global queue
    count=0
    while True:
      if queue.qsize()<1000:
        for i in range(100):
          count = count+1
          msg="生成產品"+str(count)
          queue.put(msg)
          print(msg)

      time.sleep(0.5)


class Consumer(threading.Thread):
  def run(self):
    global queue
    while True:
      if queue.qsize()>100:
        for i in range(3):
          msg=self.name+"消費了"+queue.get()
          print(msg)

      time.sleep(1)

if __name__=="__main__":
  queue=Queue()
  for i in range(500):
    queue.put("初始產品"+str(i))
  for i in range(2):
    p=Producer()
    p.start()

  for i in range(5):
    c=Consumer()
    c.start()




ThreadLocal變量
一個ThreadLocal變量雖然是全局變量,但每一個線程都只能讀寫本身線程的獨立副本,互不干擾。ThreadLocal解決了參數在一個線程中各個函數之間互相傳遞的問題。
能夠理解爲全局變量local_school是一個dict,能夠綁定其餘變量。
ThreadLocal最經常使用的地方就是爲每一個線程綁定一個數據庫鏈接,HTTP請求,用戶身份信息等,這樣一個線程的全部調用到的處理函數均可以很是方便地訪問這些資源。


import threading
# 建立全局ThreadLocal對象:
local_school=threading.local()
def process_student():
  # 獲取當前線程關聯的student
  std=local_school.student
  print("Hello,%s (in %s)"%(std,threading.current_thread().name))

def process_thread(name):
  # 綁定ThreadLocal的student:
  local_school.student=name
  process_student()

t1=threading.Thread(target=process_thread,args=("zhangsan",),name="t1")
t1=threading.Thread(target=process_thread,args=("老王",),name="t2")

t1.start()
t2.start()
t1.join()
t2.join()
# 多線程
import threading,time

def fun(num):
  print("線程執行%d"%num)
  time.sleep(2)

for i in range(5):
  t=threading.Thread(target=fun,args=(i+1,))
  t.start()

print("主線程結束")
# 查看線程的數量
import threading,time

def sing():
  for i in range(3):
    print("唱歌")
    time.sleep(1)

def dance():
  for i in range(3):
    print("跳舞")
    time.sleep(2)


st=threading.Thread(target=sing)
dt=threading.Thread(target=dance)

st.start()
dt.start()

while True:
  length=len(threading.enumerate())
  print("當前線程數:%s"%length)
  if length<=1:
    break
  time.sleep(0.5)
#線程的子類化
import threading,time

class MyThread(threading.Thread):
  def __init__(self,num,str1):
    super().__init__()
    self.num = num
    self.str1 = str1

  def run(self):
    for i in range(4):
      time.sleep(1)
      msg="i am "+self.name+"@"+str(i)+"num:"+str(self.num)+"str1:"+self.str1
      print(msg)

if __name__=="__main__":
  for i in range(5):
    t=MyThread(10,"abc")
    t.start()
# 線程共享全局變量
import threading,time
# 線程共享全局變量
g_num=100
def work1():
  global g_num
  for i in range(3):
    g_num+=1
    print("in work1,g_num=%d"%g_num)

def work2():
  print("in work2,g_num=%d"%g_num)

print("主線程,g_num=%d"%g_num)


w1=threading.Thread(target=work1)
w1.start()
time.sleep(1)

w2=threading.Thread(target=work2)
w2.start()
print("主線程,g_num=%d"%g_num)
# 線程採用傳參的方式使用全局變量
import threading,time
# 線程共享全局變量
g_num=100
def work1(num):
  for i in range(3):
    num+=1
    print("in work1,num=%d"%num)

def work2(num):
  print("in work2,num=%d"%num)

print("主線程,g_num=%d"%g_num)


w1=threading.Thread(target=work1,args=(g_num,))
w1.start()
time.sleep(1)

w2=threading.Thread(target=work2,args=(g_num,))
w2.start()
print("主線程,g_num=%d"%g_num)




# ____________________________________________________

import threading,time
# 線程共享全局變量
g_num=[11,22,33]

def work1(num):
  for i in range(3):
    num.append(44)
    print("in work1,num=%s"%num)

def work2(num):
  print("in work2,num=%s"%num)

print("主線程,g_num=%s"%g_num)


w1=threading.Thread(target=work1,args=(g_num,))
w1.start()
time.sleep(1)

w2=threading.Thread(target=work2,args=(g_num,))
w2.start()
print("主線程,g_num=%s"%g_num)
import threading,time

g_num=0

def worker():
  global g_num
  for i in range(20000000):
    g_num+=1


for i in range(2):
  t=threading.Thread(target=worker)
  t.start()

print("main thread: g_num=%s"%g_num)
import threading,time

g_num=0
# 建立互斥鎖
mutex=threading.Lock()
def worker():
  global g_num
  for i in range(20000000):
    #加鎖
    flag=mutex.acquire(False)
    if flag:
      g_num+=1
      # 解鎖
      mutex.release()

ths=[]
for i in range(2):
  t=threading.Thread(target=worker)
  t.start()
  ths.append(t)

for t in ths:
  t.join()

print("main thread: g_num=%s"%g_num)
import threading,time

class MyThread1(threading.Thread):
  def run(self):
    if mutexA.acquire():
      print("thread1 do something...")
      time.sleep(2)
      if mutexB.acquire():
        print("thread1 get mutexB")
        mutexB.release()
      mutexA.release()


class MyThread2(threading.Thread):
  def run(self):
    if mutexB.acquire():
      print("thread2 do something...")
      time.sleep(2)
      if mutexA.acquire():
        print("thread2 get mutexA")
        mutexA.release()
      mutexB.release()

mutexA=threading.Lock()
mutexB=threading.Lock()

t1=MyThread1()
t1.start()

t2=MyThread2()
t2.start()
import threading,time

class Task1(threading.Thread):
  def run(self):
    while True:
      if lock1.acquire():
        print("Task1")
        time.sleep(1)
        lock2.release()


class Task2(threading.Thread):
  def run(self):
    while True:
      if lock2.acquire():
        print("Task2")
        time.sleep(1)
        lock3.release()


class Task3(threading.Thread):
  def run(self):
    while True:
      if lock3.acquire():
        print("Task3")
        time.sleep(1)
        lock1.release()


lock1=threading.Lock()
lock2=threading.Lock()
lock2.acquire()
lock3=threading.Lock()
lock3.acquire()

t1=Task1()
t2=Task2()
t3=Task3()

t1.start()
t2.start()
t3.start()
import threading,time
from queue import Queue

class Producter(threading.Thread):
  def run(self):
    while True:
      if queue.qsize()<1000:
        for x in range(100):
          msg="產品"+str(x)
          print("%s建立了%s"%(self.name,msg))
          queue.put(msg)
        time.sleep(1)


class Consumer(threading.Thread):
  def run(self):
    while True:
      if queue.qsize()>100:
        for x in range(3):
          msg=queue.get()
          print("%s消費了%s"%(self.name,msg))
        time.sleep(0.5)

queue=Queue()

for i in range(500):
  msg="產品"+str(i)
  queue.put(msg)

for i in range(2):
  t=Producter()
  t.start()

for i in range(5):
  c=Consumer()
  c.start()
import threading

localSchool=threading.local()

def processStudent():
  name=localSchool.student
  print("Hello %s in %s"%(name,threading.current_thread().name)


def processThread(name):
  localSchool.student=name
  processStudent()

t1=threading.Thread(target=processThread,args=("zhangsan",),name="t1")
t2=threading.Thread(target=processThread,args=("lisi",),name="t2")

t1.start()
t2.start()

 

socket-udp
socket-tcp



建立Socket

——import socket
——socket.socket(AddressFamily,Type)
——說明:函數socket.socket建立一個socket,返回該socket的描述符
——該函數帶有兩個參數
AddressFamily:能夠選擇AF_INET(用於Internet進程間通訊)或者AF_UNIX(用於同一臺機器進程間通訊),實際工做經常使用AF_INET
Type:套接字類型,能夠是SOCK_STREAM(流式套接字,主要用於TCP協議)或者SOCK_DGRAM(數據報套接字,主要用於UDP協議)



TCP與UDP的區別
1、基於鏈接與無鏈接
2、對系統資源的要求(TCP較多,UDP少)
3、UDP程序結構較簡單
4、流模式與數據報模式
5、TCP保證數據正確性,UDP可能丟包,TCP保證數據順序,UDP不保證



UDP編程

發送數據
from socket import *
# 一、建立套接字
udpSocket=socket(AF_INET,SOCK_DGRAM)
# 二、準備接收方地址
sendAddr=('192.168.1.111',8080)
# 三、從鍵盤獲取數據
sendData=raw_input("請輸入要發送的數據:")
# 四、發送數據到指定的電腦上
udpSocket.sendto(sendData,sendAddr)     # udpSocket.sendto(b"this is a test.",sendAddr)
# 五、關閉套接字
udpSocket.close()


接收數據
from socket import *
# 一、建立套接字
udpSocket=socket(AF_INET,SOCK_DGRAM)
# 二、準備接收方的地址
sendAddr=('192.168.1.103',8080)
# 三、從鍵盤獲取數據
sendData=input("請輸入要發送的數據:")
# 四、發送數據到指定的電腦上
udpSocket.sendto(byte(sendData,encoding="utf-8"),sendAddr)     # udpSocket.sendto(b"this is a test.",sendAddr)
# 五、等待接收對方發送的數據
recvData=udpSocket.recvfrom(1024)   # 1024表示本次接收的最大字節數
# 六、顯示對方發送的數據
print(recvData) 
# 七、關閉套接字
udpSocket.close()



綁定信息
from socket import *
# 一、建立套接字
udpSocket=socket(AF_INET,SOCK_DGRAM)
# 二、綁定本地的相關信息,若是一個網絡程序不綁定,則系統會隨機分配
bindAddr=("",7788)  # ip地址和端口號,ip通常不用寫,表示本機的任何一個ip
udpSocket.bind(bindAddr)
# 三、準備接收方的地址
sendAddr=('192.168.1.103',8080)
# 四、從鍵盤獲取數據
sendData=raw_input("請輸入要發送的數據:")
# 五、發送數據到指定的電腦上
udpSocket.sendto(sendData,sendAddr)     # udpSocket.sendto(b"this is a test.",sendAddr)
# 六、等待接收對方發送的數據
recvData=udpSocket.recvfrom(1024)   # 1024表示本次接收的最大字節數
# 七、顯示對方發送的數據
print(recvData) 
# 八、關閉套接字
udpSocket.close()




echo服務器
綁定信息
from socket import *
# 一、建立套接字
udpSocket=socket(AF_INET,SOCK_DGRAM)
# 二、綁定本地的相關信息,若是一個網絡程序不綁定,則系統會隨機分配
bindAddr=("",7788)  # ip地址和端口號,ip通常不用寫,表示本機的任何一個ip
udpSocket.bind(bindAddr)
num=1
while True:
  recvData=udpSocket.recvfrom(1024)   # 1024表示本次接收的最大字節數
  #三、將接收到的數據再發送給對方
  udpSocket.sendto(recvData[0],recvData[1])
  #四、統計信息
  print('已經將接收到的第%d個數據返回給對方,內容爲:%s'%(num,recvData[1])) 
  num+=1
#五、關閉套接字
udpSocket.close()



聊天室
from socket import *
from time import ctime

udpSocket=socket(AF_INET,SOCK_DGRAM)
bindAddr=("",5533)
udpSocket.bind(bindAddr)
while True:
  recvData=udpSocket.recvfrom(1024)
  print('【%s】%s:%s'%(ctime(),recvData[1][0],recvData[0]))

udpSocket.close()
# UDP發送

from socket import *
# 一、建立套接字
udpSocket=socket(AF_INET,SOCK_DGRAM)
# 二、準備接收方地址
sendAddr=('192.168.234.1',8080)
# 三、發送數據到指定的電腦上
udpSocket.sendto(b"this is a test.",sendAddr)
# 四、關閉套接字
udpSocket.close()
# UDP接收

from socket import *
# 一、建立套接字
udpSocket=socket(AF_INET,SOCK_DGRAM)
# 二、準備接收方地址
sendAddr=('192.168.234.1',8080)
# 三、發送數據到指定的電腦上
udpSocket.sendto(b"this is a test.",sendAddr)
# 四、等待接收對方發送的數據
recvData=udpSocket.recvfrom(1024)   # 1024表示本次接收的最大字節數
# 五、顯示對方發送的數據
print(recvData) 
# 六、關閉套接字
udpSocket.close()
# echo服務器
from socket import *
# 一、建立套接字
udpSocket=socket(AF_INET,SOCK_DGRAM)
# 二、綁定本地的相關信息,若是一個網絡程序不綁定,則系統會隨機分配
bindAddr=('',9998)  # ip地址和端口號,ip通常不用寫,表示本機的任何一個ip
udpSocket.bind(bindAddr)


num=1

while True:
  recvData=udpSocket.recvfrom(1024)
  #三、將接收到的數據再發送給對方
  udpSocket.sendto(recvData[0],recvData[1])
  #四、統計信息
  print('已經將接收到的第%d個數據返回給對方,內容爲:%s'%(num,recvData[0])) 
  num+=1
#五、關閉套接字
udpSocket.close()
# 聊天室
from socket import *
import time
# 一、建立套接字
udpSocket=socket(AF_INET,SOCK_DGRAM)
# 二、綁定本地的相關信息,若是一個網絡程序不綁定,則系統會隨機分配
bindAddr=('',9884)  # ip地址和端口號,ip通常不用寫,表示本機的任何一個ip
udpSocket.bind(bindAddr)



while True:
  recvData=udpSocket.recvfrom(1024)


  print('%s--%s:%s,'%(time.ctime(),recvData[1][0],recvData[0])) 

#五、關閉套接字
udpSocket.close()

 

TFTP下載過程:udp  69端口
1、客戶端發送請求:下載仍是上傳(操做類型)、文件名。
2、服務器收到請求確認:若是下載文件沒有,會發出錯信息;若是下載文件有,發確認信息,或直接發文件的一部分給你。
3、客戶端收到服務器數據後:若是收到文件數據,須要發確認的消息給服務器,而且要將數據寫入本地文件;若是收到出錯信息,直接停止下載過程。
4、循環過程:服務器發文件的一部分,客戶端收到確認,直到文件發完。
5、若是文件已經結束,應該有一個文件結束的標誌。


操做碼
1——讀請求,即下載
2——寫請求,即上傳
3——表示數據包,即DATA
4——確認碼,即ACK
5——錯誤

讀寫請求
操做碼|文件名|0|模式|0

數據包
操做碼|塊編碼|數據

ACK
操做碼|塊編碼

ERROR
操做碼|差錯碼|差錯信息|0



Struct模塊使用
p.s.1:
struct.pack("打包的格式",1,"文件名",0,"模式",0)
struct.pack("!H8sb5sb",1,"test.jpg",0,"octet",0)


struct.pack("!HH",4,p_num)
cmdTuple=struct.unpack("!HH",recvData[:4])
# 給服務器發送請求

from socket import *
import struct

udpSocket=socket(AF_INET,SOCK_DGRAM)
tftpAddr=("192.168.44.1",69)
msg=struct.pack("!H8sb5sb",1,b"test.gif",0,b"octet",0)

udpSocket.sendto(msg,tftpAddr)
udpSocket.close()
# 接收服務器的返回信息

from socket import *
import struct

udpSocket=socket(AF_INET,SOCK_DGRAM)
tftpAddr=("192.168.44.1",69)
msg=struct.pack("!H8sb5sb",1,b"test.gif",0,b"octet",0)

udpSocket.sendto(msg,tftpAddr)

recvData=udpSocket.recvfrom(1024)
print(recvData)

udpSocket.close()





# 接收服務器的返回信息並解包

from socket import *
import struct

udpSocket=socket(AF_INET,SOCK_DGRAM)
tftpAddr=("192.168.44.1",69)
msg=struct.pack("!H9sb5sb",1,b"test1.gif",0,b"octet",0)

udpSocket.sendto(msg,tftpAddr)

recvData=udpSocket.recvfrom(1024)
data=struct.unpack("!HH",recvData[0][:4])
print(recvData)
if data[0]==5:
  print("%s"%recvData[0][4:].decode())

udpSocket.close()
# 接收服務器的返回信息並解包

from socket import *
import struct

udpSocket=socket(AF_INET,SOCK_DGRAM)
tftpAddr=("192.168.44.1",69)

fileName="test.gif"
fmt=str.format("!H%dsb5sb"%len(fileName))

# 發請求
msg=struct.pack(fmt,1,fileName.encode(),0,b"octet",0)

udpSocket.sendto(msg,tftpAddr)


# 解包
recvData=udpSocket.recvfrom(1024)
data=struct.unpack("!HH",recvData[0][:4])
print(recvData)

if data[0]==5:    # 出錯信息
  print("%s"%recvData[0][4:].decode())
elif data[0]==3:    # 正常的數據
  f=open(fileName,"wb")
  f.write(recvData[0][4:])

udpSocket.close()
# 接收服務器的返回信息並解包

from socket import *
import struct

udpSocket=socket(AF_INET,SOCK_DGRAM)
tftpAddr=("192.168.44.1",69)


fileName=input("請輸入文件名:")
fmt=str.format("!H%dsb5sb"%len(fileName))

# 發請求
msg=struct.pack(fmt,1,fileName.encode(),0,b"octet",0)

udpSocket.sendto(msg,tftpAddr)

f=None

while True:
  # 解包
  recvData=udpSocket.recvfrom(1024)
  data=struct.unpack("!HH",recvData[0][:4])
  print(recvData)

  dataType=data[0]
  dataNo=data[1]
  
  if dataType==5:    # 出錯信息
    print("%s"%recvData[0][4:].decode())
    break
  elif dataType==3:    # 正常的數據
    dataLen=len(recvData[0][4:])
    if dataNo==1:
      f=open(fileName,"wb")
      f.write(recvData[0][4:])
    else:
      f.write(recvData[0][4:])

    # 給服務器發確認包
    msg=struct.pack("!HH",4,dataNo)
    udpSocket.sendto(msg,recvData[1])

    # 收到數據包中的數據的長度若是小於512,就認爲文件已經接收完畢
    if dataLen<512:
      f.close()
      break
  else:
    break

udpSocket.close()

 

TCP服務器

TCP服務器流程以下:
1、socket建立一個套接字
2、bind綁定ip和port
3、listen使套接字變爲能夠被動連接
4、accept等待客戶端的連接
五、recv/send接收發送數據

from socket import *
# 建立socket
tcpSerSocket = socket(AF_INET,SOCK_STREAM)
# 綁定本地信息
address = ('',7788)
tcpSerSocket.bind(address)
# 使用socket建立的套接字默認的屬性是主動的,使用listen將其變爲被動的,這樣就能夠接收
tcpSerSocket.listen(5)
# 若是有新的客戶端來連接服務器,那麼就產生一個新的套接字專門爲這個客戶端服務器
# newSocket用來爲這個客戶端服務
# tcpSerket就能夠省下來專門
newSocket,clientAddr = tcpSerSocket.accept()
# 接收對方發送過來的數據,最大接收1024個字節
recvData=newSocket.recv(1024)
print '接收到的數據爲:',recvData
# 發送一些數據到客戶端
newSocket.send("thank you!")
# 關閉爲這個客戶端服務的套接字,只要關閉了,就意味着不能再爲這個客戶端服務了
newSocket.close()
# 關閉監聽套接字,只要這個套接字關閉了,就意味着整個程序不能再接收任何新的客戶端的鏈接
tcpSerSocket.close()




select  多路複用
設備操做認爲是一種文件操做

三個標準的輸入輸出設備
stdin
stdout
stderr

socket的收發也能夠看作文件的讀寫




單進程服務器-select版
import select,socket,sys

server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
serverAddr=('',9898)
server.bind(serverAddr)
server.listen(5)
inputs=[server,sys.stdin]
running=True
while True:
  #調用select函數,阻塞等待
  readable,writeable,exceptional=select.select(inputs,[],[])
  # 數據抵達,循環
  for sock in readable:
    #監聽到有新的鏈接
    if sock==server:
      conn,addr=server.accept()
      #select監聽的socket
      inputs.append(conn)
    #監聽到鍵盤有輸入
    elif sock == sys.stdin:
      cmd=sys.stdin.readline()
      running=False
      break
    #有數據到達
    else:
      #讀取客戶端連接發送的數據
      data = sock.recv(1024)
      if data:
        sock.send(data)
      else:
        #移除select監聽的socket
        inputs.remove(sock)
        sock.close()
    #若是檢測到用戶輸入敲擊鍵盤,那麼就退出
    if not running:
      break
    server.close()



單進程服務器epoll版
import socket,select

#建立套接字
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#設置能夠重複使用綁定的信息
s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
#綁定本機信息
s.bind('',8899)
#變爲被動
s.listen(10)
#建立一個epoll對象
epoll=select.epoll()
#測試,用來打印套接字對應的文件描述符
# print s.fileno()
# print select.EPOLLIN|select.EPOLLET
#註冊事件到epoll中
# epoll.register(fd[,eventmask])
#注意,若是fd已經註冊過,則會發生異常
#將建立的套接字添加到epoll的事件監聽中
epoll.register(s.fileno(),select.EPOLLIN|select.EPOLLET)
connections={}
addresses={}
#循環等待客戶端的到來或者對方發送數據
while True:
  #epoll 進行fd掃描的地方——未指定超時時間則爲阻塞等待
  epoll_list=epoll.poll()
  #對事件進行判斷
  for fd,events in epoll_list:
    #prind fd
    #print events
    #若是是socket建立的套接字被激活
    if fd==s.fileno():
      conn,addr=s.accept()
      print('有新的客戶端到來%s'%str(addr))
      #將conn和addr信息分別保存起來
      connections[conn.fileno()]=conn
      addresses[conn.fileno()]=addr
      #向epoll中註冊鏈接socket的可讀事件
      epoll.register(conn.fileno(),select.EPOLLIN|select.EPOLLET)
    elif events=select.EPOLLIN:
      #從激活fd上接收
      recvData=connections[fd].recv(1024)
      if len(recvData)>0:
        print("recv:%s"%recvData)
      else:
        #從epoll中移除該鏈接fd
        epoll.unregister(fd)
#server側主動關閉該鏈接fd
connections[fd].close()
print("%s--offline--"%str(addresses[fd]))
# TCP服務器
from socket import *

serverSocket=socket(AF_INET,SOCK_STREAM)

#綁定地址
serverAddr=('',9999)
serverSocket.bind(serverAddr)

#監聽listening
serverSocket.listen(5)

#接收客戶端鏈接
clientSocket,clientAddr = serverSocket.accept()

#與客戶端通訊
recvData = clientSocket.recv(1024)
print(recvData)

clientSocket.send(b"Hello")

#關閉socket
clientSocket.close()
serverSocket.close()
# TCP客戶端
from socket import *

clicketSocket = socket(AF_INET,SOCK_STREAM)

#鏈接服務器
serverAddr=('',9999)
clicketSocket.connect(serverAddr)
#發送數據
clicketSocket.send(b"hello")
#收數據
recvData=clicketSocket.recv(1024)
print(recvData)


clicketSocket.close()
# TCP服務器多線程版
from socket import *

serverSocket=socket(AF_INET,SOCK_STREAM)

#綁定地址
serverAddr=('',9999)
serverSocket.bind(serverAddr)

#監聽listening
serverSocket.listen(5)

while True:
  #接收客戶端鏈接
  clientSocket,clientAddr = serverSocket.accept()
  print("接收到客戶端:%s"%clientAddr[0])

  #與客戶端通訊
  # recvData = clientSocket.recv(1024)
  # print(recvData)

  # clientSocket.send(b"Hello")

  #關閉socket
  clientSocket.close()
serverSocket.close()
#epoll版服務器
from socket import *
import select,sys
serverSocket=socket(AF_INET,SOCK_STREAM)



serverSocket.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
serverAddr=('',8899)
serverSocket.bind(serverAddr)

serverSocket.listen(5)
#建立epoll對象
epoll = select.epoll()
#向epoll註冊設備
epoll.register(serverSocket.fileno(),select.EPOLLIN|select.EPOLLET)
epoll.register(sys.stdin.fileno(),select.EPOLLIN|select.EPOLLET)

connections={}
clientAddrs={}
while True:
  running=True
  # 使用epoll查看每一個設備的狀態,將有事件發生的設備放入列表
  pollList=epoll.poll()
  for fd,event in pollList:
    if fd == serverSocket.fileno():   #處理服務器(接收客戶端鏈接)
      clientSocket,clientAddr = serverSocket.accept()
      print("接收到新的連接:%s"%clientAddr[0])
      connections[clientSocket.fileno()]=clientSocket
      clientAddrs[clientSocket.fileno()]=clientAddr
      epoll.register(clientSocket.fileno(),select.EPOLLIN|select.EPOLLET)
    elif fd==sys.stdin.fileno():    #處理用戶鍵盤輸入
      cmd=sys.stdin.readline()
      running=False
      break
    else:   #處理客戶端socket
      recvData=connections[fd].recv(1024)
      if recvData:
        print("接收到數據:%s"%recvData)
        connections[fd].send(recvData)
      else:   #客戶端已經斷開
        connections[fd].close()
        print("%s客戶端關閉"%clientAddrs[fd][1])
        epoll.unregister(fd)
  if running==False:
    break

serverSocket.close()
# TCP客戶端
from socket import *

clicketSocket = socket(AF_INET,SOCK_STREAM)

#鏈接服務器
serverAddr=('',9999)
clicketSocket.connect(serverAddr)

while True:
  msg=input(">>")
  #發送數據
  clicketSocket.send(msg.encode())
  #收數據
  recvData=clicketSocket.recv(1024)
  print("<<%s"%recvData)

  if msg=="byb":
    break

clicketSocket.close()
# TCP服務器多線程版
from socket import *
import threading
def clientProcess(clientSocket):
  while True:
    #與客戶端通訊
    recvData = clientSocket.recv(1024)
    print(recvData)

    clientSocket.send(recvData)
    if recvData.decode()=="byb":
      break

  #關閉socket
  clientSocket.close()

serverSocket=socket(AF_INET,SOCK_STREAM)

#綁定地址
serverAddr=('',9999)
serverSocket.bind(serverAddr)

#監聽listening
serverSocket.listen(5)

while True:
  #接收客戶端鏈接
  clientSocket,clientAddr = serverSocket.accept()
  print("接收到客戶端:%s,port:%s"%(clientAddr[0],clientAddr[1]))

  clientThread=threading.Thread(target=clientProcess,args=(clientSocket,))
  clientThread.start()
  
serverSocket.close()
# TCP服務器多進程版
from socket import *
import multiprocessing
def clientProcess(clientSocket):
  while True:
    #與客戶端通訊
    recvData = clientSocket.recv(1024)
    print(recvData)

    clientSocket.send(recvData)
    if recvData.decode()=="byb":
      break

  #關閉socket
  clientSocket.close()

serverSocket=socket(AF_INET,SOCK_STREAM)

#綁定地址
serverAddr=('',9999)
serverSocket.bind(serverAddr)

#監聽listening
serverSocket.listen(5)

while True:
  #接收客戶端鏈接
  clientSocket,clientAddr = serverSocket.accept()
  print("接收到客戶端:%s,port:%s"%(clientAddr[0],clientAddr[1]))

  client_Process=multiprocessing.Process(target=clientProcess,args=(clientSocket,))
  client_Process.start()
  
serverSocket.close()
#select版服務器
from socket import *
import select,sys
serverSocket=socket(AF_INET,SOCK_STREAM)



serverSocket.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
serverAddr=('',8899)
serverSocket.bind(serverAddr)

serverSocket.listen(5)

inputList=[serverSocket,sys.stdin]

while True:
  running=True
  # 使用select查看每一個設備的狀態,並根據狀態將設備放入不一樣的列表
  readable,writeable,exceptionable=select.select(inputList,[],[])
  for sock in readable:
    if sock == serverSocket:
      clientSocket,clientAddr = sock.accept()
      print("接收到新的連接:%s"%clientAddr[0])
      inputList.append(clientSocket)
    elif sock==sys.stdin:
      cmd=sys.stdin.readline()
      running=False
      break
    else:
      recvData=sock.recv(1024)
      if recvData:
        print("接收到數據:%s"%recvData)
        sock.send(recvData)
      else:
        sock.close()
        inputList.remove(sock)
  if running==False:
    break

serverSocket.close()
#epoll版服務器
from socket import *
import select,sys
serverSocket=socket(AF_INET,SOCK_STREAM)



serverSocket.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
serverAddr=('',8899)
serverSocket.bind(serverAddr)

serverSocket.listen(5)
#建立epoll對象
epoll = select.epoll()
#向epoll註冊設備
epoll.register(serverSocket.fileno(),select.EPOLLIN|select.EPOLLET)
epoll.register(sys.stdin.fileno(),select.EPOLLIN|select.EPOLLET)

connections={}
clientAddrs={}
while True:
  running=True
  # 使用epoll查看每一個設備的狀態,將有事件發生的設備放入列表
  pollList=epoll.poll()
  for fd,event in pollList:
    if fd == serverSocket.fileno():   #處理服務器(接收客戶端鏈接)
      clientSocket,clientAddr = serverSocket.accept()
      print("接收到新的連接:%s"%clientAddr[0])
      connections[clientSocket.fileno()]=clientSocket
      clientAddrs[clientSocket.fileno()]=clientAddr
      epoll.register(clientSocket.fileno(),select.EPOLLIN|select.EPOLLET)
    elif fd==sys.stdin.fileno():    #處理用戶鍵盤輸入
      cmd=sys.stdin.readline()
      running=False
      break
    else:   #處理客戶端socket
      recvData=connections[fd].recv(1024)
      if recvData:
        print("接收到數據:%s"%recvData)
        connections[fd].send(recvData)
      else:   #客戶端已經斷開
        connections[fd].close()
        print("%s客戶端關閉"%clientAddrs[fd][1])
        epoll.unregister(fd)
  if running==False:
    break

serverSocket.close()

 

協程

比線程更小的執行單元
某個函數,能夠在任何地方保存當前函數的一些臨時變量等信息,而後切換到另一個函數中執行
協程本身主動讓出CPU
協程的切換隻是單純的操做CPU的上下文,比線程的切換更快速
1:N模式。所謂1:就是一個線程做爲一個容器裏面放置多個協程
IO密集型的程序和CPU密集型程序


import time
def A():
  while True:
    print("-------A")
    yield
    time.sleep(3)

def B():
  while True:
    print("------B")
    c.next()
    time.sleep(4)

if __name__=="__main__":
  a=A()
  B(a)


協程-greenlet
python中的greenlet模塊對協程進行了封裝
安裝模塊:pip3 install greenlet
from greenlet import greenlet
import time
def test1():
  while True:
    print "A"
    gr2.switch()
    time.sleep(2)

def test2():
  while True:
    print "B"
    gr1.switch(2)

# 協程切換器
gr1=greenlet(test1)
gr2=greenlet(test2)
#切換到gr1中運行
gr1.switch()



協程-gevent
安裝模塊:pip3 install gevent
python中還有一個比greenlet更強大的而且可以自動切換任務的模塊,gevent
原理是當一個greenlet遇到IO(指的是input output輸入輸出,好比網絡、文件操做等)操做時,好比訪問網絡,就自動切換到其餘greenlet,等IO操做完成,再在適當的時候切換回來繼續執行

gevent切換執行
# coding=utf-8
import gevent
def f(n):
  for i in range(n)
  print gevent.getcurrent(),i

g1=gevent.spawn(f,5)
g2=gevent.spawn(f,5)
g3=gevent.spawn(f,5)

g1.join()
g2.join()
g3.join()



協程-併發下載器
from gevent import monkey
import gevent,urllib2

# 有IO要作時須要這一句
monkey.patch_all()


def myDownLoad(url):
  print('GET:%s'%url)
  resp=urllib2.urlopen(url)
  data=resp.read()
  print("%d bytes received from %s."%(len(data),url))

gevent.joinall([
  gevent.spawn(myDownLoad,'http://www.baidu.com/'),
  gevent.spawn(myDownLoad,'http://www.sina.com/'),
  gevent.spawn(myDownLoad,'http://www.yahoo.com/'),
])


協程-tcp版服務器
import sys,time,gevent
from gevent import socket,monkey

monkey.patch_all()
def handle_request(conn):
  while True:
    data=conn.recv(1024)
    if not data:
      conn.close()
      break
    print("recv:",data)
    conn.send(data)

def server(port):
  s=socket.socket()
  s.bind('',port)
  s.listen(5)
  while True:
    cli,addr=s.accept()   #接收客戶端鏈接
    gevent.spawn(handle_request,cli)    #生成一個協程

if __name__=='__main__':
  server(7788)





正則表達式:Python中須要經過正則表達式對字符串進行匹配的時候,可使用re模塊
import re
# 使用match方法進行匹配操做
result=re.match(正則表達式,要匹配的字符串)
#若是上一步匹配到數據的話,可使用group方法提取數據
result=re.group()
re.match是用來進行正則匹配檢查的方法,若字符串匹配正則表達式,則match方法返回匹配對象(Match Object),不然返回None(注意不是空字符串"")
匹配對象Match Object具備group方法,用來返回字符串的匹配部分


字符      功能
表示字符
.               匹配任意1個字符(除了\n)
[]              匹配[]中列舉的字符
\d              匹配數字,即0-9
\D              匹配非數字,即不是數字
\s              匹配空白,即空格,tab鍵
\S              匹配非空白
\w              匹配單詞字符,即a-z,A-Z,0-9,_
\W              匹配非單詞字符
表示數量
*               匹配前一個字符出現0次或者無限次,便可有可無
+               匹配前一個字符出現1次或者無限次,即至少有1次
?              匹配前一個字符出現1次或者0次,即要麼有1次,要麼沒有
{m}             匹配前一個字符出現m次
{m,}            匹配前一個字符至少出現m次
{m,n}           匹配前一個字符出現從m到n次
表示邊界
^               匹配字符串開頭
$               匹配字符串結尾
\b              匹配一個單詞的邊界
\B              匹配非單詞邊界
匹配分組
|               匹配左右任意一個表達式
(ab)            將括號中字符做爲一個分組
\num            引用分組num匹配到的字符串
(?P<name>)      分組起別名
(?P=name)       引用別名爲name分組匹配到的字符串




P.S.1# 若是hello的首字符小寫,那麼正則表達式須要小寫的h
ret=re.match("h","hello Python")
ret.group()
# 若是hello的首字符大寫,那麼正則表達式須要大寫的H
ret=re.match("H","Hello Python")
ret.group()
# 大小寫h均可以的狀況
ret = re.match("[hH]","hello Python")
ret.group()
ret = re.match("[hH]","Hello Python")
ret.group()
# 匹配0到9第一種寫法
ret = re.match("[0123456789]","7Hello Python")
ret.group()
# 匹配0到9第二種寫法
ret = re.match("[0-9]","7Hello Python")
ret.group()



原始字符串
Python 中字符串前面加上r表示原聲字符串
正則表達式裏使用「\」做爲轉義字符
-假如你須要匹配文本中的字符「\」,那麼使用正則表達式裏須要4個反斜槓「\\」:前兩個和後兩個分別用於在編程語言裏轉義成反斜槓,轉換成兩個反斜槓後再在反斜槓後再在正則表達式裏轉義成一個反斜槓

Python裏的原聲字符串很好地解決了這個問題,有了原始字符串,你不再用擔憂是否是漏寫了反斜槓
-ret=re.match(r"c:\\a","c:\\a\\b\\c")
ret.group()




P.S.2:
ret = re.match("\d{11}","13256489561")
ret.group


P.S.3# 經過引用分組中匹配到的數據便可,可是要注意是元字符串
ret = re.match(r"<([a-zA-Z]*)>\w*</\1>","<html>gg</html>")
ret.group()
# 若是2對<>中的數據不同,就沒法匹配出來
ret = re.match(r"<([a-zA-Z]*)>\w*</\1>","<html>gg</body>")
ret.group()




re模塊的其餘用法
search搜索符合特徵的字符串
—— ret = re.search(r"\d+","閱讀次數爲9999")
   ret.group()

findall找出全部符合特徵的字符串
—— ret = re.findall(r"\d+","python=9999,c=7890,c++=12345")

sub將匹配到的數據進行替換
—— ret = re.sub(r"\d+",'998',"python=997")

split根據匹配進行切割字符串,並返回一個列表
—— ret = re.split(r":| ","info:xiaoZhang 33 shandong")



貪婪和非貪婪
Python里正則表達式數量詞默認是貪婪的(在少數語言裏也多是默認非貪婪),老是嘗試匹配儘量多的字符

非貪婪則相反,老是嘗試匹配儘量少的字符

在「*」,「?」,「+」,「{m,n}」後面加上?,使貪婪變成非貪婪
—— re.match(r"aa(\d+)","aa2345ss").group(1)
>>2345
—— re.match(r"aa(\d+?)","aa2345ss").group(1)
>>2
—— re.match(r"aa(\d+)ss","aa2345ss").group(1)
>>2345
—— re.match(r"aa(\d+?)ss","aa2345ss").group(1)
>>2345
# greenlet實現協程
from greenlet import greenlet
import time
def test1():
  while True:
    print "A"
    gr2.switch()
    time.sleep(2)

def test2():
  while True:
    print "B"
    gr1.switch(2)

# 協程切換器
gr1=greenlet(test1)
gr2=greenlet(test2)
#切換到gr1中運行
gr1.switch()
# gevent實現協程
import gevent

def fun(num):
  for i in range(num):
    print("%s%s"%(gevent.getcurrent(),str(i)))


g1=gevent.spawn(fun,5)
g2=gevent.spawn(fun,5)
g3=gevent.spawn(fun,5)

g1.join()
g2.join()
g3.join()
# gevent的自動切換
import gevent

def fun(num):
  for i in range(num):
    print("%s%s"%(gevent.getcurrent(),str(i)))
    #模擬一個費時的任務,注意必須用gevent中的sleep
    gevent.sleep(1)


g1=gevent.spawn(fun,5)
g2=gevent.spawn(fun,5)
g3=gevent.spawn(fun,5)

g1.join()
g2.join()
g3.join()
# gevent下載器
from gevent import monkey
import gevent,urllib

# 須要讓gevent可以自動處理io事件,必須先打補丁
monkey.patch_all()


def myDownLoad(url):
  print('GET:%s'%url)
  resp=request.urlopen(url)
  data=resp.read()
  print("%d bytes received from %s."%(len(data),url))

gevent.joinall([
  gevent.spawn(myDownLoad,'http://www.baidu.com/'),
  gevent.spawn(myDownLoad,'http://www.sina.com/'),
  gevent.spawn(myDownLoad,'http://www.yahoo.com/')
])
# 協程-tcp服務器
from gevent import socket,monkey
import gevent

#打補丁
monkey.patch_all()

#客戶端處理
def handleRequest(conn):
  while True:
    #接數據
    data=conn.recv(1024)
    if not data:
      conn.close()
      break
    else:
      print("收到數據:%s"%data)
      conn.send(data)

# 建立服務器
def server(port):
  s=socket.socket()
  # s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
  s.bind('',port)
  s.listen(5)
  while True:
    cli,addr=s.accept()
    gevent.spawn(handleRequest,cli)

if __name__=="__main__":
  server(7788)
# 未使用正則的寫法
def
isPhone(num): # 判斷長度是否是11位 if len(num) !=11: return False # 判斷是否是都是數字 if not str.isdigit(num): return False # 判斷前三位是否是正確的號段 li = ['137','138','187'] if num[:3] not in li: return False return True print(isPhone('1374567')) print(isPhone('137fde43454')) print(isPhone('13788899964')) print(isPhone('15688888996'))

 

Mysql安裝

查詢是否安裝:rpm -qa | grep mysql
安裝服務端和客戶端:yum -y install mysql-server mysql

服務啓動腳本查詢:cd /etc/init.d/
服務啓動:service mysqld start

做爲系統項跟隨系統啓動:chkconfig mysqld on
查詢跟隨系統啓動項:chkconfig --list

顯示mysql相關網絡信息:netstat -ntpl | grep mysql

關於linux下mysql亂碼:安裝默認是希臘編碼
修改方法:# vi /etc/my.cnf
[mysqld]下添加
default-character-set=utf8
而後重啓服務:service mysqld restart


【

初始化數據庫安全設置:
安裝完mysql-server 能夠運行mysql_secure_installation。運行mysql_secure_installation會執行幾個設置:
  a)爲root用戶設置密碼
  b)刪除匿名帳號
  c)取消root用戶遠程登陸
  d)刪除test庫和對test庫的訪問權限
  e)刷新受權表使修改生效

經過這幾項的設置可以提升mysql庫的安全。建議生產環境中mysql安裝這完成後必定要運行一次mysql_secure_installation,詳細步驟請參看下面的命令:

[root@localhost ~]# mysql_secure_installation
NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MySQL
SERVERS IN PRODUCTION USE! PLEASE READ EACH STEP CAREFULLY!
In order to log into MySQL to secure it, we'll need the current
password for the root user. If you've just installed MySQL, and
you haven't set the root password yet, the password will be blank,
so you should just press enter here.

Enter current password for root (enter for none):                           <–初次運行直接回車

OK, successfully used password, moving on…
Setting the root password ensures that nobody can log into the MySQL
root user without the proper authorisation.

Set root password? [Y/n]                                                     <– 是否設置root用戶密碼,輸入y並回車或直接回車
New password: <– 設置root用戶的密碼
Re-enter new password:                                                       <– 再輸入一次你設置的密碼

Password updated successfully!
Reloading privilege tables..
… Success!
By default, a MySQL installation has an anonymous user, allowing anyone
to log into MySQL without having to have a user account created for
them. This is intended only for testing, and to make the installation
go a bit smoother. You should remove them before moving into a
production environment.

Remove anonymous users? [Y/n]                                                 <– 是否刪除匿名用戶,生產環境建議刪除,因此直接回車

… Success!
Normally, root should only be allowed to connect from 'localhost'. This
ensures that someone cannot guess at the root password from the network.

Disallow root login remotely? [Y/n] n                                          <–是否禁止root遠程登陸,根據本身的需求選擇Y/n並回車,建議禁止

… Success!
By default, MySQL comes with a database named 'test' that anyone can
access. This is also intended only for testing, and should be removed
before moving into a production environment.

Remove test database and access to it? [Y/n] n                                  <– 是否刪除test數據庫

- Dropping test database…
… Success!
- Removing privileges on test database…
… Success!
Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.

Reload privilege tables now? [Y/n] y                                            <– 是否從新加載權限表

… Success!
Cleaning up…
All done! If you've completed all of the above steps, your MySQL
installation should now be secure.
Thanks for using MySQL!

[root@localhost ~]#mysql -uroot -p
....
mysql>grant all on *.* to root@'%' identifide by '你的數據庫密碼'                <- 設置一個root用戶容許遠程的其餘機器登錄
....
關閉防火牆:service iptables stop
禁止防火牆開機啓動:chkconfig iptables off
P.S.2:生產模式下,通常不容許關閉防火牆,正確方法是在防火牆加入開放3306端口規則,添加方法看下面P.S.1

】



P.S.1:
Windows下Navicat鏈接虛擬機CentOS中的MySql
【

首先配置CentOS下防火牆iptables規則:
# vim /etc/sysconfig/iptables
向其中加入下列規則:
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 3306 -j ACCEPT

說明:防火牆開放http用的80端口和鏈接MySql的3306端口。

P.S.1.1:新加的規則寫在-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT  以後

# service iptables restart
而後配置MySQL容許遠程登錄:
先在CentOS中鏈接Mysql數據庫
# mysql -u root -p 
執行
> GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '你的數據庫root密碼,若是沒運行mysql_secure_installation設置,密碼爲空' WITH GRANT OPTION;
再執行下
> flush privileges;
刷新一下權限,不用重啓MySql服務。
最後配置工做完成,打開Windows下的Navicat就能夠直接鏈接到CentOS下的數據庫了。

】

cmd客戶端鏈接
mysql的bin目錄下:mysql -u root -p -h 192.168.234.44
-u:用戶名
-p:密碼
-h:host服務端地址




SQL語言分類
——DQL(數據查詢語言):select

——DML(數據操做語言):insertupdatedelete

——DDL(數據定義語言):createalterdrop

——DCL(數據控制語言):grantrevoke

——TCL(事務控制語言):SAVEPOINT、ROLLBACKSET TRANSACTIONCOMMIT


DDL:
數據庫操做
  建立數據庫:create database 數據庫名 charset=utf8;
  刪除數據庫:drop database 數據庫名;
  切換數據庫:use 數據庫名;
  查看當前選擇的數據庫:select database()

表操做
  查看當前數據庫中全部的表:show tables;
  建立表、設置auto_increment自動增加:create table 表名(列及類型);
  P.S.3:
    create table infomation(
      id int auto_increment primary key,
      name varchar(20) not null
    )
  修改表:alter table 表名 add|change|drop|modify 列名 類型;
  P.S.4:
    alter table infomation add birthday datetime;
    alter table infomation change 原字段 新字段 varchar(100) not null;
    alter table infomation modify id int(4) auto_increment;
  刪除表:drop table 表名;
  查看錶結構:desc 表名;
  更改表名稱;rename table 原表名 to 新表名;
  查看錶的建立語句:show create table '表名';


DML、DQL:
  查詢:select * from 表名;
  增長:
    全列插入:insert into 表名 values(....);
      insert into infomation values(1,'harold','sh',0)
    缺省插入:insert into 表名 (列1,....) values (值1,....);
      insert into infomation (id,name) values (2,'ZH');
    同時插入多條數據:insert into 表名 [列名] values (....),(....),....;或insert into 表名 (列1,列2,列3....) values (值1),(值2),(值3),....;
      insert into infomation (id,name) values (3,'WW'),(4,'SL');
      insert into infomation values (3,'WW','BJ',0),(4,'SL','SH',1);
  修改:update 表名 set 列1=值1,.... where 條件
  刪除:delete from infomation where address='BJ'


備份與恢復
  數據備份:
    進入mysql庫目錄:cd /var/lib/mysql
    運行mysqldump命令:mysqldump -uroot -p 數據庫名 > ~/Desktop/back.sql
  數據恢復:
    鏈接MySQL,建立數據庫
    退出鏈接,執行命令:mysql -uroot -p 數據庫名 < ~/Desktop/back.sql


P.S.5:
  若是存在一個sql腳本文件,直接執行該文件:source sql文件的路徑

去重查詢:
  select distinct deptno from emp;

排序:asc\desc
  select name,sal from emp order by sal asc

分頁查詢:
  select * from emp limit 第幾條數據開始,讀取多少條數據;
  P.S.6select * from emp limit 0,5;

 

聚合函數和內置函數

聚合:
  爲了快速獲得統計數據,提供了5個聚合函數
  count(*)表示計算總行數,括號中寫星與列名,結果是相同的

  count(列)、max(列)、min(列)、sum(列)、avg(列)

內置函數:
  拼接:concat
  截取:left(str,len)返回字符串str左端len個字符;right(str,len)返回字符串str右端len個字符;substring(str,pos,len)返回字符串str的位置pos起len個字符【select substring('abc123',2,3);】。
  字符串拼接:select concat (ename,'的工資是:',sal) from emp;
  去除空格:ltrim(str)返回刪除了左空格的字符str;rtrim(str)返回刪除了右空格的字符串str;trim([方向 remstr from] str)方向包括:both、leading、trailing,表示兩側、左、右。
  日期格式化:data_format(date,format)
    format參數可用的值以下:
      獲取年:%Y,返回4位的整數
      獲取年:%y,返回2位的整數
      獲取月:%m,返回1-12的整數
      獲取日:%d,返回整數
      獲取時:%h,返回1-12的整數
      獲取分:%i,返回0-59的整數
      獲取秒:%s,返回0-59的整數
      P.S.1select date_format('2018-11-22','%Y %m %d');
        當前日期:select current_date();
        當前時間:select current_time();
        當前日期時間:select now();



分組查詢和過濾
  GROUP BY 字句將表中數據分紅若干小組
  存在group by分組,select查詢列不能寫group by之外的字段,除非這些用在聚合函數中。

  語法格式:
  ——select column, group_function(column)
  ——from table
  ——[where condition]
  ——[group by group_by_expression]
  ——[order by column]
  使用舉例:
    ——select deptno,avg(sal) from emp group by deptno;
    ——select deptno,job,count(*),avg(sal) from emp group by deptno,job;

having過濾:
  對分組查詢結果進行過濾,要使用having從句
  having從句過濾分組後的結果,它只能出如今group by從句以後,而where從句要出如今group by從句以前。
  where過濾行,having過濾分組,having支持全部where操做符
  語法格式:
    ——select column,group_function(column)
    ——from table
    ——[where condition]
    ——[group by group_by_expression]
    ——[having group_condition]
    ——[order by column]
過濾分組以後的結果
  使用舉例:
  統計,每一個部門的人數,最高工資,最低工資,平均工資,可是部門的平均工資小於2000的不要統計
    ——select deptno, count(1), max(sal), min(sal), avg(sal) from emp group by deptno having avg(sal) > 2000
  列出工資最小值小於2000的職位
    ——select deptno,job from emp group by job having min(sal) < 2000
  統計人數小於4的部門的平均工資
    ——select avg(sal) from emp group by deptno having count(1) < 4
  統計各部門的最高工資,排除最高工資小於3000的部門 
    ——select max(sal) from emp group by deptno having max(sal) >= 3000
  列出每一年入職的人數和最高工資
    ——select count(1), year(hiredate), max(sal) from emp group by year(hiredate)


表的約束
  主鍵約束(Primary Key):要求主鍵列數據惟一,不容許爲空。主鍵能夠包含表的一列或多列,若是包含表的多列,則須要在表級定義。
  
  惟一約束(Unique):要求該列惟一,容許爲空
  
  檢查約束(Check):某列取值範圍限制、格式限制等,如年齡的約束

  非空約束(not null):某類內容不能爲空

  外鍵約束(Foreign Key):用於兩表間創建關係,須要指定引用主表的那列。外鍵一般用來約束兩個表之間的數據關係,定義外鍵的那張表稱爲子表,另外一張表稱爲主表。在表的建立過程當中,應該先建立主表,後建立字表。


  主鍵約束:從功能上看至關於非空且惟一;一個表只容許一個主鍵;一個表多是由兩個或者兩個以上的字段組成主鍵——聯合主鍵;主鍵是表中可以惟一肯定一個行數據的字段;主鍵字段能夠是單字段或者是多字段的組合。
  create table t3(
    id number, --primary key,
    constraint t3_pk primary key(id)
  );
  
  惟一性約束:
  create table employees(
    id number(6),
    name varchar(50),
    email varchar(45)
    CONSTRAINT emp_email_uk UNIQUE(email)
  );
  
  Check約束:
  create table emp3(
    id number(4) primary key,
    age number(2) check(age > 0 and age < 100),
    salary number(7,2),
    constraint salary_check check(salary>0)
  );

  外鍵約束:
    外鍵是表中的一個列,其值必須在另外一個表的主鍵或者惟一鍵中列出;
    做爲主鍵的表稱爲「主表」,做爲外鍵的關係成爲「依賴表」;
    外鍵參照的是主表的主鍵或惟一鍵;
    對於主表的刪除和修改主鍵值的操做,會對依賴關係產生影響,已刪除爲例;當要刪除主表的某個記錄(即刪除一個主鍵值,那麼對依賴的影響可採起下列3種作法:
      RESTRICT方式:只有當依賴表中沒有一個外鍵值與要刪除的主表中主鍵值相對應時,才能夠執行刪除操做。
      CASCADE方式:將依賴表中全部外鍵值與主表中要刪除的主鍵值相對應的記錄一塊兒刪除。
      SET NULL方式:將依賴表中全部與主表中被刪除的主鍵值相對應的外鍵值設爲空值
      ——FOREIGN KEY (字段名) REFERENCES 表名(字段名)
      ——[ON DELETE[CASCADE|SET NULL]]如省略on短句,缺省爲第一種處理方式。
    )

    添加約束:
    ——ALTER TABLE 表名
      ADD CONSTRAINT 約束名 約束類型 具體的約束說明

    刪除約束
    ——ALTER TABLE 表名
      DROP CONSTRAINT 約束名

    能夠添加或刪除約束,但不能修改。

    P.S.2create table 表一(
        id int(8) primary ket,
        name varchar(200) not null,
        emp_max_count int(2) check(emp_max_count>0 and emp_max_count<51),
        parent_id int(8) foreign key parent_id REFERENCES 表二(id)
      )
      ALTER table 表一 add constraint `FK_DEPTNO` foreign key (`parent_id`) references `表一` (`id`)


索引
  自動索引:主鍵、惟一約束
  手動索引:
    給員工的名字字段創建索引:create index i_emp_ename on emp(ename)
  在一列或者多列上建立索引:
    create index 索引名 on 表名 (列名1,列名2,....);
  刪除索引:
    drop index 索引名;

視圖:
  定義
    視圖是從若干基本表和(或)其餘視圖構造出的虛表。
    在建立一個視圖時,只是存放的視圖的定義,也便是動態檢索數據的查詢語句,而並不存放視圖對應的數據
    在用戶使用視圖時纔去求相對應的數據,因此視圖被稱做「虛表」
  做用
    能夠限制對數據的訪問,能夠給用戶授予表的特定部分的訪問權限而不是整個表的訪問權限
    可使複雜的查詢變的簡單,在編寫查詢後,能夠方便的重用它而沒必要知道它的基本查詢細節
    提供了對相同數據的不一樣顯示

  建立視圖:
    ——create [or replace] view 視圖名
    ——[(alias[,alias]....)]
    ——AS subquery
    ——[with read only];
  查詢視圖:
    select * from 視圖名;
  刪除視圖:
    drop view 視圖名;

    P.S.3:
      ——建立視圖以後,隱藏基本表中某些字段,只對外功能部分字段
      create view v_emp as select empno, ename, job from emp;
      select * from v_emp limit 1;
      insert into v_emp values (3333,'ss','clerk')

      視圖能夠簡化查詢語句
      查詢員工表中工資最高的和最低員工信息
      create or replace view v_emp2 as select max(sal) as max_sal , min(sal) as min_sal from emp
      select * from emp where sal in (select max_sal from v_emp2) or sal in (select min_sal from v_emp2)

  總結:
    視圖是一個虛擬表,對應一條select語句,可將它的輸出看做一個表
    視圖不存儲數據
    改變基本表的數據,也會反應到基於該表的視圖上
    視圖能夠基於基本表的若干行,若干列
    視圖能夠基於一個表、多個表,甚至是基於其餘的視圖
    
    使用視圖能夠提供數據訪問的安全性,只顯示指定的行列數據
    使用視圖能夠下降查詢的難度,定製數據顯示

    能夠對視圖進行CRUD操做,其實是對基本表的CRUD操做
    若是視圖對應多個表,通常不容許添加操做,能夠經過觸發器解決
    使用with read only定義只讀視圖


事務(Transaction):是爲了保證數據庫的完整性
  事務是一個操做序列。這些操做要麼都作,要麼都不作,的一個不可分割的工做單位,是數據庫環境中的邏輯工做單位。
  當一個業務邏輯須要多個sql完成時,若是其中某條sql語句出錯,則但願整個操做都退回。
  使用事務能夠完成退回的功能,保證業務邏輯的正確性

事務語句:
  開始begin;
  提交commit;
  回滾rollback;

P.S.4create table t_account(
    id int primary key,
    money double
  )
  begin;
  update t_account set money=money-100 where id=1;
  update t_account set money=money+100 where id=2;
  commit|rollback;


表的關係:(PowerDesigner表設計軟件)
  一對一的關聯關係,只需想辦法讓外鍵字段同時有惟一約束。外鍵字段在任意的表中
  一對多的關聯關係,只須要在多的那張表中增長一個外鍵字段。
  多對多的關聯關係,須要找一箇中間表,轉化成兩個多對一的關係。
  # 第一種方式
  P.S.5:創建身份證表和人表
  create table t_person(
    id int primary key,
    name varchar(255),
    age int
  )

  ——身份證表
  create table t_idcard(
    card_number varchar(18) primary key,
    create_date date,
    p_id int unique,
    foreign key (p_id) references t_person (id)
  )
  # 第二種方式
  create table t_person(
    id int primary key,
    name varchar(200),
    age int
  )
  create table t_idcard(
    id int primary key,
    card_number varchar(18) unique,
    create_date date,
    foreign key (id) references t_person (id)
  )

 

內鏈接:返回兩表重疊內容
  語法規則1
    select table1.column,table2.column from table1,table2 where table1.column1 = table2.column2;
  語法規則2
    select table1.cloumn,table2.column from table1 inner join table2 on table1.column1 = table2.column2
  P.S.1:
  列出員工姓名,工資和工資頂級編號
    select ename, sal, grade from emp,salgrade where emp.SAL> salgrade.losal and emp.SAL < salgrade.HISAL
  查詢員工的編號,姓名,領導的編號和姓名
    select t1.empno,t1.ename,t2.empno,t2.ename from emp as t1 join emp as t2 on t1.MGR=t2.EMPNO
  查詢全部用戶的姓名,部門編號和部門名稱
    select t1.ename,t2.deptno,t2.dname from emp as t1 join dept as t2 on t1.deptno = t2.deptno
  查看10部門員工的姓名,薪水和薪水等級
    select t1.ename,t1.sal,t2.grade from emp as t1, salgrade as t2 where t1.deptno=10 and t1.sal between t2.losal and t2.HISAL

外鏈接
  左外鏈接
    兩個表在鏈接過程當中除返回知足鏈接條件的行之外,還返回左表中不知足條件的行,這種鏈接稱爲左外鏈接。
  右外鏈接
    兩個表在鏈接過程當中除返回知足鏈接條件的行之外,還返回右表中不知足條件的行,這種鏈接稱爲右外鏈接。
  全外鏈接
    兩個表在鏈接過程當中除返回知足鏈接條件的行之外,還返回兩個表中不知足條件的行,這種鏈接稱爲滿外鏈接。

  P.S.2:using(字段)鏈接的條件,而且兩個表之間的鏈接字段名字相同
  左外鏈接
    select t2.dname,t1.ename from dept as t2 left join emp as t1 on t1.deptno=t2.deptno
    select deptno,dname,empno,ename,job from dept left join emp using(deptno)
  右外鏈接
    select deptno,dname,empno,ename,job from dept right join emp using(deptno)  
  全外鏈接
    select deptno,dname,empno,ename,job from dept full join emp using(deptno)

  P.S.3:
  查詢全部員工的編號,姓名,有領導的顯示領導的編號和姓名,沒有領導的只顯示員工信息
    select t1.empno, t1.ename, t2.empno, t2.ename from emp as t1 left join emp as t2 on t1.mgr=t2.empno
  查詢全部部門的詳細信息及每一個部門的平均工資,包含沒有員工的部門
    select t2.*, avg(t1.sal) as 每一個部門的平均工資 from emp as t1 right join dept as t2 on t1.deptno=t2.deptno group by t2.deptno


  
子查詢
  語法:select 字段列表 from 表名 where 表達式 operator (select 字段列表 from 表名)

  P.S.4:
  子查詢能夠在select,fromwhere
  查詢工資高於平均工資的員工
    select ename, sal from emp where sal > (select avg(sal) from emp)
  查詢和scott同一部門且比他工資低的僱員名字和工資
    select t1.ename,t1.sal from emp as t1 join (select deptno,sal from emp where ename='scott') as t2 on t1.deptno = t2.deptno where t1.sal < t2.sal

  單行子查詢:對單行子查詢可以使用單行記錄比較運算符<>=>=<=<>!=
  多行子查詢:多行子查詢只能使用多行記錄比較運算符。(ALL和子查詢返回的全部值比較、ANY和子查詢返回的任意一個值比較、IN等於列表中的任何一個)

 

Pymysql
  安裝pymysql模塊:pip3 install PyMySQL

  Connection對象:
    1、用於創建與數據庫的鏈接
    二、建立對象:調用connect()方法    conn=connect(參數列表)
    3、參數host:鏈接的mysql主機,若是本機是localhost
    4、參數port:鏈接mysql主機的端口,默認是3306
    5、參數db:數據庫的名稱
    6、參數user:鏈接的用戶名
    7、參數password:鏈接的密碼
    8、參數charset:通訊採用的編碼方式,默認是‘gb2312’,要求與數據庫建立時指定的編碼一致,不然中午會亂碼
  對象的方法:
    close()關閉鏈接
    commit()事務,須要提交纔會生效
    rollback()事務,放棄以前的操做
    cursor()返回cursor對象,用於執行sql語句並得到結果
  
  Cursor對象
    1、執行sql語句
    2、建立對象:調用Connection對象的cursor()方法
    cursor1=conn.cursor()
  對象的方法
    close()關閉
    execute(operation[,parameters])執行語句,返回受影響的行數
    fetchone()執行查詢語句時,獲取查詢結果集的第一個行數據,返回一個元組
    next()執行查詢語句時,獲取當前行的下一行
    fetchall()執行查詢時,獲取結果集的全部行,一行構成一個元組,再將這些元組組裝入一個元組返回。

P.S.1#coding:utf-8
import pymysql

#建立數據庫鏈接
connection = pymysql.connect("數據庫地址","數據庫帳號","數據庫密碼","數據庫名")

#建立cursor對象
cursor = connection.cursor()

sql = "select * from emp"

#cursor執行sql
cursor.execute(sql)

#獲取cursor執行sql以後第一行結果
emp = cursor.fetchone()
print(type(emp))
print(emp)

#關閉遊標和鏈接
cursor.close()
connection.close()


P.S.2#coding:utf-8
import pymysql,datetime

connection = None
cursor = None
try:
  #建立數據庫鏈接
  connection = pymysql.connect("數據庫地址","數據庫帳號","數據庫密碼","數據庫名")

  #建立cursor對象
  cursor = connection.cursor()

  sql = "select * from emp"

  #cursor執行sql
  try:
    cursor.execute(sql)

    #獲取cursor執行sql以後第一行結果
    emp = cursor.fetchone()
    print(type(emp))
    print(type(emp[4]))
    print(datetime.datetime.strftime(emp[4],"%Y/%m/%d"))
    print(emp[4].strftime('%Y{y}%m{m}%d{d}').format(y='',m='',d=''))
    print(emp[4])
    print(emp)
  except Exception as ex:
    print(ex)
except expression as ex:
  print(ex)
finally:
  #關閉遊標和鏈接
  if cursor:
    cursor.close()
  if connection:
    connection.close()
  

P.S.3:
#coding:utf-8
import pymysql,datetime

connection = None
cursor = None
try:
  #建立數據庫鏈接,connection自動加入事務處理
  connection = pymysql.connect("數據庫地址","數據庫帳號","數據庫密碼","數據庫名")

  #建立cursor對象
  cursor = connection.cursor()

  sql1 = "insert into dept values(60,'leslie','上海')"
  sql2 = "insert into dept values(%s,'%s','%s')"%(60,'leslie','上海')
  sql3 = "insert into dept values(%s,%s,%s)"
  print(sql「1/2/3」)

  #cursor執行sql
  try:
    cursor.execute(sql「1/2」)
    cursor.execute(sql3,(70,'Jim','北京'))
    connection.commit()
  except Exception as ex:
    connection.rollback()
    print(ex)
except expression as ex:
  print(ex)
finally:
  #關閉遊標和鏈接
  if cursor:
    cursor.close()
  if connection:
    connection.close()


數據庫操做代碼封裝
#coding:utf-8
import pymysql

class MysqlHelper(object):
  config={"host":"192.168.0.4",
    "user":"root",
    "password":"root",
    "db":"test",
    "charset":"utf8"
  }
  def __init__(self):
    self.connection = None
    self.cursor = None
  
  #從數據庫表中查詢一行數據
  def getOne(self,sql,*args):
    try:
      self.connection = pymysql.connect(**MysqlHelper.config)
      self.cursor = self.connection.cursor()
      self.cursor.execute(sql,args)
      return self.cursor.fetchone()
    except Exception as ex:
      print(ex,ex)
    finally:
      self.close()

  #從數據庫表中查詢多行數據
  def getList(self,sql,*args):
    try:
      self.connection = pymysql.connect(**MysqlHelper.config)
      self.cursor = self.connection.cursor()
      self.cursor.execute(sql,args)
      return self.cursor.fetchall()
    except Exception as ex:
      print(ex,ex)
    finally:
      self.close()

  #對數據庫進行增,刪,改
  def executeDML(self,sql,*args):
    try:
      self.connection = pymysql.connect(**MysqlHelper.config)
      self.cursor = self.connection.cursor()
      num = self.cursor.execute(sql,args)  #sql語句執行以後影響的行數
      self.connection.commit()
      return num
    except Exception as ex:
      self.connection.rollback()
      print(ex,ex)
    finally:
      self.close()


  def close(self):
    if(self.cursor):
      self.cursor.close()
    if(self.connection):
      self.connection.close()


if __name__ == '__main__':
 # 測試 helper
= MysqlHelper() print(helper.executeDML("delete from dept where deptno=%s",80))

 

知識補缺:

 

字典建立:phone_book={'Harold':123, 'Jim':456}

字典清空:phone_book.clear()

字典追加:phone_book['Leslie'] =789

字典刪除:phone_book['Jim']

字典修改:phone_book['Harold']=444

 

打印輸出:

  age=3

  name="harold"

  print("{0} was {1} years old".format(name, age))

  print(name + "was" + str(age) + "years old")

 

讀寫文件:

some_sentences = '''\
I love learning python
because python is fun
and also easy to use
'''
f = open('sentences.txt', 'w')
f.write(some_sentences)
f.close()


f = open('sentences.txt')
while True:
  line = f.readline()
  if len(line) ==0:
    break
  print(line)
f.close()

 

裝飾器:

def add_candles(cake_func):
    def insert_candles():
        return cake_func() + "and candles"
    return insert_candles

def make_cake():
    return "cake"

gift_func = add_candles(make_cake)
print(make_cake())
print(gife_func())


'''等同於'''


def add_candles(cake_func):
    def insert_candles():
        return cake_func() + "and candles"
    return insert_candles

def make_cake():
    return "cake"

make_cake = add_candles(make_cake)
print(make_cake())



'''等同於'''




def add_candles(cake_func):
    def insert_candles():
        return cake_func() + "and candles"
    return insert_candles

@add_candles
def make_cake():
    return "cake"
print(make_cake())

 

圖形界面Tkinter:

# coding=utf-8
# Version:python3.6.1
__date__ = '2019/1/18 11:04'
__author__ = 'Lgsp_Harold'
from tkinter import *

import tkinter.simpledialog as dl
import tkinter.messagebox as mb

root = Tk()

w = Label(root,text = 'Guess Number Game')
w.pack()

mb.showinfo("Welcome","Welcome to Guess Number Game")

number = 44
while True:
    # guess = int(input("Enter an integer:"))
    guess = dl.askinteger("Number","Enter an integer:")
    if guess == number:
        output = "猜對了"
        mb.showinfo("Hint:", output)
        break
    if guess < number:
        # print("你輸入的數字小了。")
        output = "你輸入的數字小了。"
        mb.showinfo("Hint", output)
        continue
    else:
        # print("你輸入的數字大了。")
        output = "你輸入的數字大了。"
        mb.showinfo("Hint:", output)
        continue
print("Done")


if __name__ == '__main__':
    pass

 

建立簡單網站:

下載安裝python2.7

安裝lpthw.web:cmd>C:\ProgramFiles\Development\Python27\Scripts\easy_install lpthw.web

建立目錄:D:\ProgramFiles\Development\PycharmProjects\python2_7_Web\bin

建立app.py

import web
urls =(
    '/', 'index'
)
app = web.application(urls,globals())

class index:
    def GET(self):
        greeting = "Hello World"
        return greeting
if __name__ == "__main__":
    app.run()

cmd運行:

cd D:\ProgramFiles\Development\PycharmProjects\python2_7_Web\bin
D:\ProgramFiles\Development\Python27\python app.py
相關文章
相關標籤/搜索