美文网首页python
Python | Python笔记(进阶)

Python | Python笔记(进阶)

作者: 琼脂糖 | 来源:发表于2019-09-25 14:45 被阅读0次

    Python学习笔记。包括exception,模块,标准库,pypi等。

    6. 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)

    7. 类

    7.1. 基础

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

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

    isinstance(obj,class)返回布尔值

    7.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()
    

    7.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。

    7.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
    

    7.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可以访问私有属性

    7.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.6. 继承

    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") 
    

    7.7. 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必须要有,否则会报错。用法相当于一个约定,或模版。


    image

    7.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)
    

    8. 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中的内容。

    9. 标准库

    9.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")
    

    9.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")]
    

    9.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)
    

    9.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)
    

    9.6. 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)
    

    9.7. 打开浏览器

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

    9.8. 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()
    

    9.9. command line

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

    9.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)
    

    10. pypi

    10.1. pypi

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

    10.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)
    

    10.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

    11. popular python packages

    11.1. Yelp API

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

    image

    buisiness endpoint中的buisiniess search找到GET url。

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

    pip3.7 install pipenv
    cd PyYelp
    pipenv install requests
    

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

    image

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

    image image

    正确返回,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)
    
    image

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

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

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

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

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

    可中括号读取属性值
    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())
    

    11.3. pdf

    1. 包 pypdf2

    11.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)
    
    image
    cells = sheet["a:c"]
    print(cells)
    
    image

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

    image

    print(sheet[1:3])

    image

    save

    sheet.append([1, 2, 3])
    wb.save("transcations2.xlsx")
    

    相关文章

      网友评论

        本文标题:Python | Python笔记(进阶)

        本文链接:https://www.haomeiwen.com/subject/tnaiuctx.html