[Python]自学习打卡第三周(225~335p)

包括exception,模块,标准库,pypi等。

Exception

Exception的作用是:prevent program from crashing

try except else结构:else- 当try的代码没有throw exception的时候执行

try:
    age = int(input("Age: "))
except ValueError:
    print("You didn't enter a valid age.")
else:
    print("No exceptions were thrown.")
print("Execution continues.")

except ValuesError as ex:ex为error message

except (ValueError, ZeroDivisionError):多个exception

finaly:无论有没有exception都可以执行

try:
    file = open("app.py")
    age = int(input("Age:"))
    xfactor = 10 / age
except (ValueError, ZeroDivisionError):
    print("You didn't enter a valid age.")
else:
    print("No exceptions were thrown.")
finally:
    file.close()

with
当一个对象有enter和exit magic method,那么这个obj支持context management protocol。就可以用with。Python会自动call exit method,然后释放内存

with open("app.py") as file:
    print("File opened.")

可以定义自己的exception:
首先python built-in exception已经很充足了,但也可以定义自己的

def calculate_xfactor(age):
    if age <= 0:
        raise ValueError("Age cannot be 0 or less.")
    return 10 / age
    
try:
    calculate_xfactor(-1)
except ValueError as error:
    print(error)

raise exception很耗资源
可以return none:

if age <= 0:
    return None

运行时间
from timeit import timeit
code1=""" """
timeit(code1, number=100000)

 类

1. 基础

Class: blueprint for creating new objects
Object: instance of a class

比如
Class: Human
Objects: John, Mary, Jack

isinstance(obj,class)返回布尔值

2. init 魔法方法

是新的实类创建的时候自动调用的方法,也称为constructor。一般用来将参数初始化

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def draw(self):
        print(f"({self.x}, {self.y})")


point = Point(1, 2)
point.draw()

3. 实类和类属性&方法(instance & class attribute & method)

instance attribute不是一定要在init中声明的。在class外面也可以声明。只需要把在class内用到的属性在init中声明。

point = Point(1, 2)

point.z = 4
point.draw()
print(point.x, point.y, point.z)

instance att属于每一个instance,不同的instance可以有不同的att。
class att可以通过class或者instance来访问。
claas att被所有instance共享。如果改变其值,所有instance都同时生效。

class Point:
    default_color = "red"

class method:可用来批量建instances。也称为factory方法。
比如创建一个x和y都是0的点。

point = Point(0, 0)  # constructor
another_point = Point.zero()  # factory(class method)
@classmethod
def zero(cls):
    return cls(0, 0)

需要decorator。

4. 魔法方法

根据我们使用obj的方式来自动的调用某个方法。

str方法:当我们想把obj转换成string的时候调用。默认返回名称和内存位置。

def __str__(self):
    return f"({self.x}, {self.y})"

比较 eq gt

def __eq__(self, other):
    return self.x == other.x and self.y == other.y
    
def __gt__(self, other):
    return self.x > other.x and self.y > other.y

5. 自定义容器

容器:dict list set

自定义意义:可以大小写不敏感

class TagCloud:
    def __init__(self):
        self.__tags = {}
    # 1.add 添加item到字典
    def add(self, tag):
        self.__tags[tag.lower()] = self.__tags.get(tag.lower(), 0) + 1
    #cloud["python"]来得到其count
    def __getitem__(self, tag):
        return self.__tags[tag.lower()]
    #cloud["python"] = 10
    def __setitem__(self, tag, count):
        self.__tags[tag.lower()] = count
    #for tag in cloud(iterable)
    def __iter__(self):
        return iter(self.__tags)


cloud = TagCloud()
cloud.add("Python")
cloud.add("Python")
cloud.add("python")
cloud.add("PYTHON")
print(cloud.__tags["python"])

私有属性:cloud["python"]相当于cloud.tags["python"]
但后者是大小写敏感的。需要将tags作为私有属性,不能从外面访问
选中tags,按F2,用来集中修改属性名字,需要装个包。加两个下划线

通过dict可以访问私有属性

6. property

考虑:product(-50) 这样不能赋值给price,而应该返回错误。
在set_price函数中来赋值。另外不希望price从外面访问,因此作为私有属性。点+price的是属性,改为下划线price。
price是从外传入的变量,不一样哈。

class Product:
    def __init__(self, price):
        self.set_price(price)

    def get_price(self):
        return self.__price
 
    def set_price(self, price):
        if price < 0:
            raise ValueError
        self.__price = price


product = Product(-50)

property:an obj sits in front of an attri, and allow us to get or set the value of an attr.
在get和set之后,定义一个class attri。
property(fget,fset,fdel,doc) :获得属性值的函数,设定属性值的函数
property从外面看就像一个regular attribute。内部是两个method:getter和setter

隐藏getter和setter:
方法一:名字前面加下划线 (但不推荐,extra noise)

推荐方法decorator
@property: 自动创建一个property obj
@price.setter

class Product:
    def __init__(self, price):
        self.price = price

    @property
    def price(self):
        return self.__price

    @price.setter
    def price(self, price):
        if price < 0:
            raise ValueError("price cannot be less than 0")
        self.__price = price


product = Product(-5)
print(product.price)

如果没有setter,那么property是read-only的,初始化给了参数后,后面不能修改

property作用:1)属性实际是通过getter访问的,setter设定的(可以有一定限制条件)。但写法仍然是点访问。2)setter不写的话就是只读的

7. 继承

  1. class Mammal(Animal)
  2. isinstance issubclass
  3. method overriding: super().__init__()
    如果没有super语句,那么子类的init就彻底覆盖父类的init噢
class Mammal(Animal):
    def __init__(self):
        print("Mammal Constructor")
        self.weight = 2
        super().__init__()
  1. 多层继承:最好一层到两层。太多会造成代码混乱

multiple继承:
class Manager(Person,Employee)
谨慎使用:当几个类都是小类而且没有没有共同点可以使用。

class Flyer:
    def fly(self):
        pass
class Swimmer:
    def swim(self):
        pass
        
class FlyingFish(Flyer, Swimmer):
    pass

一个好的例子

class InvalidOperationError(Exception):
    pass

class Stream:
    def __init__(self):
        self.opened = False

    def open(self):
        if self.opened:
            raise InvalidOperationError("alreay open")
        self.opened = True

    def close(self):
        if not self.opened:
            raise InvalidOperationError("already closed")
        self.opened = False

class FileStream(Stream):
    def read(self):
        print("read from a file")


class NetworkStream(Stream):
    def read(self):
        print("read from a network") 

8. abstract base class

code

from abc import ABC, abstractmethod
 
class AbstractClassExample(ABC):
    
    @abstractmethod
    def do_something(self):
        print("Some implementation!")
        
class AnotherSubclass(AbstractClassExample):
    def do_something(self):
        super().do_something()
        print("The enrichment from AnotherSubclass")
        
x = AnotherSubclass()
x.do_something()
        

在子类中,do_something必须要有,否则会报错。用法相当于一个约定,或模版。

9. namedtuple

如果类里面只有属性,没有method。也就是 data class,可以用namedtuple来代替。

如果要修改属性,只能重新建立一个新的point

from collections import namedtuple

Point = namedtuple("Point", ["x", "y"])
p1 = Point(x=1, y=2)
# p1 = Point(x=10, y=2)
p2 = Point(x=1, y=2)
print(p1 == p2)

Module

创建module
将功能相近的属性和method放在一个app.py文件中。

调用:from app import ... 按ctrl+space来选择
from app import * : 不好,可能同名覆盖
import app : 然后app.func来用函数和属性

path

print(sys.path)

导入子文件夹ecommerce的module:在文件夹下新建 init.py,这样python会将这个文件夹作为package

from ecommercy.app import func1
##or
import ecommery.app

dir(app) 返回app module里面的属性和method

模块的内置属性__name__,__file__,__package__:

ecommerce.shopping.sales
ecommer.shopping
/Users/mosh/Courses/Python/Demo/HelloWorld/ecommerce/shopping/sales.py

The name of the module that starts the program is main.
比如从a脚本调用b模块,那么b中的__name__属性就是b的名字。
直接运行b脚本,那么b中的name属性就是__main__

if __name__ == "__main__":
    print("Sales started")
    calc_tax()

如果直接运行脚本,就执行if中的内容;如果脚本作为模块导入其他脚本,就不执行if中的内容。

标准库

1. path

from pathlib import Path

Path(r"C:\Program Files\Microsoft")
Path("/usr/local/bin")
Path()
Path("ecommerce/__init__.py")
Path() / Path("ecommerce")
Path() / "ecommerce" / "__init__.py"
Path.home()

path = Path("ecommerce/__init__.py")
path.exists()
path.is_file()
path.is_dir()
print(path.name) #__init__.py
print(path.stem) #__init__
print(path.suffix) #.py
print(path.parent) #ecommerce

path = path.with_name("file.txt") #ecommerce/file.txt
path.absolute() #绝对路径

path = path.with_suffix(".txt") #ecommerce/__init__.txt

path.exists()
path.mkdir()
path.rmdir()
path.rename("ecommerce2")

2. directory

  1. iterdir
# 返回path下面的所有目录 生成paths列表
from pathlib import Path
paths = [p for p in path.iterdir() if p.is_dir()]
  • iterdir()返回的是一个生成器
  • 缺点:不能search pattern ;不能search recursively
  1. glob :search pattern
    py_files = [p for p in path.glob("*.py")]
  2. rglob:search recursively
py_files = [p for p in path.glob("**/*.py")]
py_files = [p for p in path.rglob("*.py")]

3. file

path.rename("init.txt")
path.unlink() #delete
path.stat() #统计信息
from time import ctime
ctime(path.stat().st_ctime) #ctime转换成尅看懂的时间信息 创建时间

读取和写入 (可以自行close)

path = Path() / "app.py"
print(path.read_text())
#same
with open(file,"r") as file: ..

path还有read_bytes方法,针对非文本文件。

复制file(shutils)

source = Path("ecommerce/__init__.py")
target = Path() / "__init__.py"
#方法一:冗杂代码
target.write_text(source.read_text())
#方法二:推荐
import shutil
shutil.copy(source, target)

4. zip

from pathlib import Path
from zipfile import ZipFile
#将文件夹打包
with ZipFile("files.zip", "w") as zip:
    for path in Path("ecommerce").rglob("*.*"):
        zip.write(path)
#read zipfile
with ZipFile("files.zip") as zip:
    print(zip.namelist())  # 打印zip中的所有文件
    info = zip.getinfo("ecommerce/__init__.py")
    print(info.file_size)
    print(info.compress_size)
    zip.extractall("extract")  # 解压到extract文件夹
    ```
## 9.5. csv
 ```python
import csv
with open("data.csv", "w") as file:
    writer = csv.writer(file)
    writer.writerow(["name", "age", "price"])
    writer.writerow([1000, 1, 5])
    writer.writerow([1001, 2, 15])
with open("data.csv") as file:
    reader = csv.reader(file)
    for row in reader:
        print(row)

5.random

import string
import random

print(random.random())
print(random.randint(1, 10))
print(random.choice([1, 2, 3, 4]))  # 从列表中随机选一个
print(random.choices([1, 2, 3, 4], k=2))  # 随机选k个

#password
print("".join(
    random.choices(
        string.ascii_letters + string.digits, k=4)
))

#打乱
numbers = [1, 2, 3, 4]
random.shuffle(numbers)
print(numbers)

6. 打开浏览器

import webbrowser

print("Completed.")
webbrowser.open("http://google.com")

7. mail

完整code(网上)

import smtplib
from email.header import Header
from email.mime.text import MIMEText
#第三方 SMTP 服务
mail_host = "smtp.163.com"      # SMTP服务器
mail_user = "chashuguzi"        # 用户名
mail_pass = "snowwhite1723"     # 授权密码,非登录密码

sender = 'chashuguzi@163.com'    # 发件人邮箱(最好写全, 不然会失败)
receivers = ['freyasnow@163.com']  # 接收邮件,可设置为你的QQ邮箱或者其他邮箱

content = '我用Python'
title = '人生苦短'  # 邮件主题

def sendEmail():

    message = MIMEText(content, 'plain', 'utf-8')  # 内容, 格式, 编码
    message['From'] = "{}".format(sender)
    message['To'] = ",".join(receivers)
    message['Subject'] = title

    try:
        smtpObj = smtplib.SMTP_SSL(mail_host, 465)  # 启用SSL发信, 端口一般是465
        smtpObj.login(mail_user, mail_pass)  # 登录验证
        smtpObj.sendmail(sender, receivers, message.as_string())  # 发送
        print("mail has been send successfully.")
    except smtplib.SMTPException as e:
        print(e)

if __name__ == '__main__':
    sendEmail()

8. command line

import sys
if len(sys.argv) == 1:
    print("USAGE: python3 app.py <password>")
else:
    password = sys.argv[1]
    print("Password", password)

9. External programs

import subprocess

completed = subprocess.run(["ls", "-l"])
print("args", completed.args)
print("returncode", completed.returncode)
print("stderr", completed.stderr)
print("stdout", completed.stdout)

args ['ls', '-l']
returncode 0
stderr None
stdout None

returncode 0 表示成功。
stdout 如果没有capture是没有的。如果需要capture,可以参数capture_output = TRUE,text设为true将binary转换为text
completed = subprocess.run(["ls", "-l"],capture_output=True,text=True)

run child process

completed = subprocess.run(["python3", "other.py"],
                            capture_output=True,
                            text=True)

从一个python脚本中调用另一个python脚本

check 设为true,如果有错误,会raise exception

import subprocess

try:
    completed = subprocess.run(
        ["false"],
        capture_output=True,
        text=True,
        check=True)

except subprocess.CalledProcessError as ex:
    print(ex)

pypi

1. pypi

python package index:大家建立的第三方库
https://pypi.org

2. pip

我们通过pip来安装pypi

python3 相对应用pip3
python3.7 对应pip3.7

pip3 install requests #安装requests包
pip3 install --upgrade pip #更新pip
pip3 list #当前安装pypi
pip3 install requests==2.9.0
pip3 install requests==2.9.* #该版本下的最新版
pip3 uninstall requests #卸载
pip3 install requests ~=2.9.0 #latest compatible version

在pypi.org网站requests包里查看release history.

包和python自带module一样使用 import requests

import requests
response = requests.get("http://www.baidu.com")
print(response)

3. 虚拟环境

一般做法: 在需要的文件夹,建立一个叫env的虚拟环境

python3.7 -m venv env

会创建env文件夹,里面有python 解译器及包。在lib/python3.7/site-packages下面就是我们需要安装不同版本包的地方。
启动虚拟环境:source env/bin/activate.bat
退出虚拟环境:deactivate

(env)HelloWorld $
在该环境下安装需要的包。

推荐做法:pipenv

pip3 install pipenv
pipenv install requests #自动建立虚拟环境并安装requests

创建了pipfile和pipfile.lock
虚拟环境地址 pipenv --venv
进入虚拟环境pipenv shell
退出exit

包安装位置:全局或者虚拟环境
vscode的code runner python interpreter是全局python,而不是虚拟环境中的python intepreter
如何让code runner用虚拟环境中python interpreter:
pipenv --venv找到python位置,open可以打开文件夹查看
将文件夹/bin/python3路径 设置到vscode的设置中,方法同最初设置python3
如何让vscode用虚拟环境中的python interpreter:
左下角的python版本改为虚拟环境中的python,如果找不到,在设置中加上下面,引号内写python的路径

"python.pythonPath": "",

一个项目有虚拟环境的话,其文件夹中就有pipfile和pipfilelock。但相关的所有包不是装在该文件夹下,位置在--env可以查到
如果需要在另一台电脑上运行,可以根据pipfile或者lock文件重建虚拟环境所有的包
pipfile

  • 包的版本是根据安装的一样。如果没有指定,那么这里也不会指定,写为星号
  • 根据pipfile安装所有包 pipenv install
    pipfile.lock:
  • 严格记录所有包及依赖包目前的版本
  • 忽略pipfile,根据lock中的版本来安装 pipenv install --ignore-pipfile

popular python packages

1. Yelp API

Yelp是一个点评网站,api即application program interface。可以获取app的数据。
yelp fusion界面创建app,得到ID和KEY。

新建项目:文件夹PyYelp,新建虚拟环境并安装requests。将左下角python编辑器改为虚拟环境的python,并在termial而不是coderunner中运行程序。

pip3.7 install pipenv
cd PyYelp
pipenv install requests

错误401:authentication erro。需要api key。

错误400:bad requests
print respnse.text 查看server返回的信息。有必须提供的参数。

 

 

正确返回,response.text返回一个json obj
response.json()将结果转换成dictionary

code

import requests
url = "https://api.yelp.com/v3/businesses/search"
api_key = "Ud6gzFpKeMrn7V7w8kWdVpetiZEUAj7X1lOfb3CmhQK9I_5WeMw5dsT5twYy9Z6poL3H8Jeo-WIcAnr2eOYhw2EtapoWrizhl-cb304Gnx-tbuDObmqSbJYF-husXHYx"
headers = {
    "Authorization": "Bearer " + api_key
}
params = {
    "location": "NYC",
    "term": "barber"
}
response = requests.get(url, headers=headers, params=params)
businesses = response.json()["businesses"]
#for business in businesses:
#print(business["name"])
#get name of rate > 4.5
names = [business["name"]
         for business in businesses if business["rating"] ≥ 4.5]
print(names)

 

git中如何隐藏api key
将api key 存在独立的文件config.py中,然后在app.py中import config,调用使用config.api_key
新建一个文件.gitignore,在这个文件中写config.py。 git就不会包含这个文件。

2. 网络爬虫(web crawler/spider)

  1. 不是所有app或网站都有api可以获取数据。这时候就要用爬虫来parse HTTP网页,获取所需要的数据。
  2. 安装包beautifulsoup4

response.text 返回网页的html代码
soup.select参数css选择器, .question 为类选择器
比如得到的div obj,其属性存在obj.attr的dictionary中

questions = soup.select(".question-summary")
print(questions[0].attrs)

可中括号读取属性值
print(questions[0]["id"])
用get 可以防止属性值为空。
print(questions[0].get("id", 0))
select_one 针对单一元素,只选择一个。比如每个summary中只有一个标题。否则会搜索整个div,并返回一个列表。

import requests
from bs4 import BeautifulSoup
response = requests.get("https://www.stackoverflow.com/questions/")
soup = BeautifulSoup(response.text, "html.parser")
questions = soup.select(".question-summary")
for question in questions:
    print(question.select_one(".question-hyperlink").getText())
    print(question.select_one(".vote-count-post").getText())

3. pdf

  1. 包 pypdf2

4. excel

  1. 包openpyxl
  2. workbook
    wb = openpyxl.Workbook:create a new workbook
    wb = openpyxl.load_workbook("transactions.xlsx"):打开workbook
    wb.sheetnames:属性sheetnames 返回sheet名字

sheet
sheet = wb['Sheet1']
wb.create_sheet("Sheet2", 0) : 创建sheet并放在最前面
wb.remove_sheet(sheet)

cell
cell = sheet["a1"]
cell = sheet.cell(row=1, column=1)
print(cell.value) : transaction_id
print(cell.row) : 1
print(cell.column): 1
print(cell.coordinate): A1
得到所有的值

for row in range(1, sheet.max_row + 1):
    for column in range(1, sheet.max_column + 1):
        cell = sheet.cell(row, column)
        print(cell.value)

获取值

column = sheet["a"]
print(column)

cells = sheet["a:c"]
print(cells)

 inner tuple :每column
print(sheet["a1:c3"])

print(sheet[1:3]) 

 save

sheet.append([1, 2, 3])
wb.save("transcations2.xlsx")
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值