🧑‍🏫
liualexiang
  • Introduction
  • Azure
    • AKS Basic
    • AKS Spark
    • AZ ACR SYNC
    • Azure CMI SDWAN
    • Azure LB DeepDive
      • Azure LB DeepDive
    • Azure Service Principal Basic
    • Azure Internal VM Network Connectivity
      • Azure Internal VM Network Connectivity
    • Azure Cli Build
    • Azure Vm Memory Monitor
  • Blockchain
    • BTC
  • CRISPR
    • 使用Parallel_Cluster提升CRISPA效率
  • OpenSource
    • ElasticSearch
      • ES Get Started
      • ES Search Query
      • Kibana 可视化
      • Logstash配置
    • Ansible 基础
    • Infra As Code
      • Pulumi Get Started
      • Terraform Basic
    • ZooKeeper 基础
    • RPC与REST
    • 使用Python申请大量内存测试
    • 使用TPC_DS产生压测数据
    • Superset
      • Superset部署手册
    • 代码扫描
    • Git
      • Git Basic
      • Github Action Basic
      • Gitlab与AzureAD集成
      • Gitbook 基础教程
    • K8S
      • enter_node
      • K8s X509 Client Cert
      • K8s Basic
      • K8s Oidc
      • Docker 基础
      • helm基础
      • K8S_Secrets管理
      • 深入了解K8S
      • 混沌工程
      • Istio
      • 生态
      • CRD开发
      • k8s网络
    • Cloud_Custodian
    • Jenkins Basic
    • Nginx
    • ETCD
    • 正则
    • VictoriaMetrics
    • Kafka
  • MySQL
    • MySQL 调优
  • Linux
    • SSH Tunnel 上网
    • 内存管理
    • 在Linux系统中通过LUKS加密磁盘
    • 量子计算 Basic
    • IO多路复用
    • Iptables
    • tmux和screen
    • Systemd
    • OS 基础
    • jq基础
    • yum
    • neovim
  • Web
    • Html Css
    • Web部署
    • 缓存
  • Programming
    • 算法
      • 返回list中最大生序子序列长度
    • Python技巧
      • Python的语法糖
      • Python常用装饰器
      • AsyncIO基础
      • 自动化测试pytest
      • python中的下划线
      • 面向对象
      • Python的坑
      • Python配置文件管理
      • HTTP Stream Response
      • Python项目管理
    • 设计模式
      • 设计模式
      • 面向对象的思想
      • 编程概念
    • Go
      • Go 基础
      • Go常用功能
      • 结构体入门
    • 前端
    • Vue
    • NodeJS
  • Math
    • 多项式插值法
  • Security
    • HTTP常见攻击
    • 加密与签名
    • RSA
    • ECDSA
  • Solidity
    • Solidity基础
    • Blockchain Testnet Faucet
  • Tools
    • 视频处理ffmpeg
    • IDE配置
    • iTerm2美化
    • 密码管理
    • FRP配置
    • 工具集
由 GitBook 提供支持
在本页
  • 实例方法,类方法,静态方法
  • 类实例方法
  • classmethod
  • staticmethod
  • abstractmethod
  • dataclass
  • property
  • dataclass 和 property 的关系与区别
  • 使用 functools 的 wraps 装饰器
  • typing 使用简介
  1. Programming
  2. Python技巧

Python常用装饰器

实例方法,类方法,静态方法

默认情况下创建的就是实例方法,这也就是在默认类方法里要有 self 的原因,这个self则代表了被实例化后的类object。因此可以调用实例化后类的一切属性和方法。比如__init__ 这个方法里的属性等。

类方法 @classmethod:则不需要进行实例化就能调用(也可以实例化调用),但是类方法不能调用实例化后的属性,比如 __init__ 方法里定义的属性就无法获取。类方法里的函数传的是 cls,而不是self

静态方法 @staticmethod:只是将一个普通方法放到类里而已,没办法获取类以及实例化后的任何属性和方法

总结:classmethod 的方法,不能访问 __init__ 方法里的任何属性和方法,可以在不初始化类的时候调用这个方法,也可以在初始化之后调用。而类的实例方法,必须在类实例化之后才能调用

类实例方法

和 classmethod 以及 staticmethod想对应,在默认情况下,不使用任何装饰器,类里的方法,就是类实例方法,顾名思义,一般是类实例化之后,使用的方法。但实际上,类实例方法,在类不实例化的情况下,也能调用。但是在没有实例化的时候,直接调用类实例化方法,在方法里使用了实例化之后的某些属性或方法,则会报错 (指的是引用了self.xxx)。

示例:在下面A的类中,并没有实例化,但直接引用了 sayhello的方法,并不会报错,但如果sayhello里,引用了类实例化的属性self.a,则就报错了

class A:
    def __init__(self):
        self.a = "self_a"
    def sayhello(self, something):
        print("I'm saying %s" % something)
        # print("I get get self.a, it's %s" % self.a)

A.sayhello("xx",something="ss")

在类实例化方法中,在 __init__方法里,定义的属性或方法,主要是用于下面多个类方法的相互传递,比如有 sayHello()方法,生成的某些属性或方法,想要传递给 run() 方法里,那么就可以在 sayHello()方法的返回值里,返回成 self.xxx,之后 run() 方法就能引用了

classmethod

classmethod 类方法, 可以实现在不实例化类的时候,就能实现类的方法。同时 cls 也能接收类本身的参数,但没法接收类实例化的 __init__ 方法的参数或属性。

在工厂方法里特别常用,比如用户可以通过不同方式创建类实例的替代构造函数,而无需创建额外的构造函数

Class method 的cls 代表了类本身,这就意味着,在执行 cls() 的时候,就相当于执行了类,也就是说执行了类里的 __init__方法,而cls()方法里的参数,则会传递给 __init__ 方法。

示例:当我们执行 hawaiian_pizza = Pizza.hawaiian() 的时候,先执行 Pizza类里的 hawaiian()方法,然后将 ['ham','pineapple'] 传递给init函数的toppings,所以我们能通过 hawaiian_pizza.toppings 获得 ['ham', 'pineapple']

class Pizza:
    def __init__(self, toppings):
        self.toppings = toppings

    @classmethod
    def hawaiian(cls):
        return cls(['ham', 'pineapple'])

还有一种用法是给类当作数据类使用,然后修改这个类的属性

class A:
    name = "aa"

setattr(A, "name", "bb")
print(A.name)

staticmethod

staticmethod 静态方法,也是可以在不实例化的时候,使用该方法。staticmethod没办法获得和调用类本身的属性和方法,也没法获得实例化的时候__init__ 方法里的属性。该装饰器有点像是把类外部方法放到了类里,但没法调用和访问类里的一切。只是组织管理代码的一种方式而已。

abstractmethod

python中并没有像java 的interface的这种概念。java 的interface可以定义一个接口,但不用具体实现接口的实际内容,由创建某一个class implement interface 的方式来override接口具体内容。python可以通过抽象类来实现,抽象类需要导入一个 abc 的库,在抽象类中定义的方法,在实现的类上必须将其实现,否则会报错。需要学习设计模式以了解更多

from abc import ABC, abstractmethod
class User(ABC):
    @abstractmethod
    def get_name(self, name: str) -> None:
        pass
class Boy(User):
    def get_name(self, name: str) -> None:
        print(f'用户名是:{name}')
u1 = Boy()
u1.get_name(name='alex')

dataclass

dataclass数据类:用于快速创建一个类似 C/C++/C# 等语言所支持的 结构体 struct的数据载体。主要关注数据的操作。

dataclass并非是python的内置方法,需要 from dataclass import dataclass 导入。在使用 @dataclass 装饰器对 class进行修饰的时候,实例化class的时候,必须同时进行赋值。

这个装饰器还有一个好处,就是能对类的 __repr__ 方法进行修改,使print 类的时候,不是直接返回类的地址,而是直接能看到类的属性以及值,显示结果更友好

在dataclass中,还可以根据属性进行对比(需要对dataclass引入 order=True的参数),默认情况下,是将属性都放到元组里,对元组进行对比,我们也可以选择对某一个字段对比,比如只对Age对比,那么可以将 Name的compare设置为 False

这种开发方式属于声明式开发,是属于现代开发的一个发展结果。类似 k8s的yaml定义,只需要定义好最终的执行结果,然后k8s会根据定义执行成我们想要的效果。

from dataclasses import dataclass, field
@dataclass(order=True)
class D:
    Name: str = field(compare=False)
    Age: int
d1 = D("alex",32)
d2 = D("jack", 31)
print(d1 > d2)

使用 dataclass 还可以轻松的将实例化的对象变成不可变对象,我们只需要加上 frozen=True就可以了

@dataclass(frozen=Ture)

property

使用 property 可以允许我们通过操作属性的方式,去操作类里面的方法,使用起来更简洁。使用property也体现了OOP里的封装的特性

class Square:
    def __init__(self):
        self._side = None
    @property
    def side(self):
        return self._side
    @side.setter
    def side(self, side: int):
        assert side > 0, '边长不能为负数'
        self._side = side
    @property
    def area(self) -> int:
        return self._side * self._side
        
square = Square()
square.side = 5
print(square.area)

dataclass 和 property 的关系与区别

我们发现,使用property可以将一个类的方法,变成属性的形式进行操作,比如设置name,age,上述示例的设置side等。那么感觉使用dataclass 也能做到?实际上确实如此。dataclass比较适合一些简单的场景,主要是修改了类的 __init__ 方法和 __repr__ 方法,能快速给类的一些属性复制。而property能够实现更细粒度的控制,比如可以控制属性里的 age,要求必须大于0,小于150,设置温度,必须大于 -273.15度等等 (虽然 class里可以通过 __post_init__ 方法对实例化类的时候起一些约束作用,但是在实例化之后,直接对实例化过的对象的属性或方法做修改的时候,这个约束就不再生效了)

使用 functools 的 wraps 装饰器

在默认情况下,如果我们创建了一个装饰器,那么当我们去打印执行函数的名字,文档等,返回的是 wrapper 函数的相关信息,而并非原函数的相关内容。当然我们可以通过覆盖的方式,将 wrapper 函数的 __name__ 被原函数覆盖

def printline(func):
    def wrapper():
        print("====")
        func()
        print("====")
    # wrapper.__name__ = func.__name__
    return wrapper

@printline
def printa():
    print("aa")

print(printa.__name__)

不过显然上述方法有些麻烦,此时我们就可以借助于 functools.wrapper()函数实现

from functools import wraps

def printline(func):
    @wraps(func)
    def wrapper():
        print("====")
        func()
        print("====")
    return wrapper

@printline
def printa():
    print("aa")

print(printa.__name__)

typing 使用简介

python是一门动态类型语言,为了在开发的时候,更好的写注解,让程序员能更清晰的描述和理解代码,我们可以使用 typing导入对应的数据类型,这样在写程序的时候,IDE也能更友好的给出提示。注意:这个只是一个注解而已,并不强制要求数据类型和注解的一致。比如下面的示例,即使我们把Dict里定义成 int类型,也不会报错

from typing import Dict
def func1(urls: Dict[str, str]) -> None:
    for key, value in urls.items():
        print(key, value)
a = {"baidu":"www.baidu.com", "google": "www.google.com"}
func1(a)
上一页Python的语法糖下一页AsyncIO基础

最后更新于1年前