Python3 面向对象及标准库

本文深入解析Python的面向对象编程概念,包括类、方法、属性、继承与抽象基类,同时全面概览标准库,涵盖操作系统接口、字符串正则匹配、数学运算、互联网访问、日期时间处理、数据压缩及性能度量等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Python3 面向对象及标准库

面向对象

术语介绍

类(Class): 
    用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
方法:
    类中定义的函数。
类变量:
    类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
数据成员:
    类变量或者实例变量用于处理类及其实例对象的相关的数据。
方法重写:
    如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
局部变量:
    定义在方法中的变量,只作用于当前实例的类。
实例变量:
    在类的声明中,属性是用变量来表示的。这种变量就称为实例变量,是在类声明的内部但是在类的其他成员方法之外声明的。
继承:
    即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。
实例化:
    创建一个类的实例,类的具体对象。
对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

注意:python是多继承

类定义:

class ClassName:
    <statement-1>
    ...
    <statement-N>
类实例化后可以使用其属性,实际上创建一个类之后,可以通过类名访问其属性
ClassName.name等同于下面两句
className = ClassName()
className.name

类对象:

类对象支持两种操作:属性引用(obj.name)和实例化
class ClassName:
    name = 'g'
    def getName(self):
        return self.name
实例化:
className = ClassName()
访问属性和方法
className.name
className.getName()

构造方法init:

python类对象的构造器是__init__(self),该方法在类实例化时自动调用
其中self代表类的实例,相当于java的this,不同于this,self位置必须处于类方法的第一个参数
注意!
python类继承构造方法__init__()的执行顺序:
    若子类定义了自己的init,则子类只会执行自己的init(此时需要super关键字调用父类的构造方法
        super(Son, self).__init__(),或使用类名.__init__(self)调用父类的构造方法)
    若子类未定义自己的init,则子类会沿着向上的链路找到父类的init方法并执行
    多继承init的执行,按照多继承从左向右的优先级查找
    即
    class E(C, D):
    class C(A):
    class D(B):
    查找顺序为E->C->A->D->B
    class E(C, D):
    class C(A):
    class D(A):
    查找顺序为E->C->D->A

类的方法:

使用def定义方法,不同于函数,类的方法必须包含参数self且为第一个参数

静态方法和类方法:

静态方法和类方法是这样创建的:将它们分别包装在staticmethod和classmethod类的对象中。静态方法的定义中没有参数self,可直接通过类来调用。类方法的定义中包含类似于self的参数,通常被命名为cls。

实例:

class MyClass:
    
    def smeth():
        print('This is a static method')
    smeth = staticmethod(smeth)
    
    def cmeth(cls):
        print('This is a class method of', cls)
    cmeth = classmethod(cmeth)

可以用装饰器替代以上手工包装替换的步骤:

class MyClass:
    
    @staticmethod
    def smeth():
        print('This is a static method')
   
    @classmethod
    def cmeth(cls):
        print('This is a class method of', cls)

定义之后使用方法如下:
MyClass.smeth()
MyClass.cmeth()

继承:

python支持多继承,若基类中有相同的方法名,而在子类未指定则python按从左向右的顺序搜索
class DerivedClass(A, [B, [C, ...]]):
    <statement-1>
    ...
    <statement-N>

方法重写:

子类可以重写父类的方法
super()函数用于调用父类的一个方法
super(子类类型,子类实例).method() #用子类对象调用父类已被覆盖的method方法

类属性与方法

类的私有属性:

两个下划线开头,声明属性为私有,不能在类的外部被使用或直接访问。在类内部的方法中使用时self.__private_attrs

类的私有方法:

实例不能直接访问私有属性和私有方法
__private_method:两个下划线声明该方法为私有方法,只能在类的内部调用,self.__private_method

强制访问私有属性和方法:

class A:
    __name
    def __get():
        pass
    pass
A._A__name
A._A__get()
通过实例/类名_类型.__私有属性/方法 可以访问私有

若不希望名称被修改,又想发出不要从外部修改属性或方法的信号,可用一个下划线打头
_attr,_method()
这是一种约定,外部可以访问但是 导模块会无视 如from module import * 不会导入以一个下划线打头的名称

类的专有方法:可以重写

__setitem__ : 按照索引赋值
__getitem__: 按照索引获取值
__len__: 获得长度
__cmp__: 比较运算
__call__: 函数调用
__add__: 加运算
__sub__: 减运算
__mul__: 乘运算
__truediv__: 除运算
__mod__: 求余运算
__pow__: 乘方

重写__add__和__str__方法可以对自定义对象进行+ 运算符并能打印
常用专有属性说明触发场景
init构造初始化函数创建实例后,赋值时使用,在__new__后
new生成实例所需属性创建实例时
class实例所在的类实例.class
str实例字符串表示,可读性print(类实例),如没实现,使用repr结果
repr实例字符串表示,准确性类实例 回车 或者 print(repr(类实例))
del析构函数,释放对象时使用del删除实例
dict实例自定义属性vars(实例.dict)
doc类文档,子类不继承help(类或实例)
getattribute属性访问拦截器访问实例属性时
bases类的所有父类构成元素类名.bases

__getattr__ , __setattr__等方法:

可以拦截对对象属性的所有访问企图,用途之一是在旧式类中实现特性。要在属性被访问时执行一段代码,需要使用下面4个魔法方法:

  • __getattribute__(self, name):在属性被访问时自动调用(只适用于新式类)
  • __getattr__(self, name):在属性被访问而对象没有这样的属性时自动调用
  • __setattr__(self, name, value):试图给属性赋值时自动调用
  • __delattr__(self, name):试图删除属性时自动调用
class Rectangle:
    def __init__(self):
        self.width = 0
        self.height = 0
    def __setattr__(self, name, value):
        if name == 'size':
            self.width, self.height = value
        else:
            self.__dict__[name] = value
    def __getattr__(self, name):
        if name == 'size':
            return self.width, self.height
        else:
            raise AttributeError()

__getattribute__的坑:

    class Person(object):
        def __getattribute__(self,obj):
            print("---test---")
            if obj.startswith("a"):
                return "hahha"
            else:
                return self.test

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

    t.Person()
    t.a #返回hahha
    t.b #会让程序死掉
        #原因是:当t.b执行时,会调用Person类中定义的__getattribute__方法,但是在这个方法的执行过程中
        #if条件不满足,所以 程序执行else里面的代码,即return self.test  问题就在这,因为return 需要把
        #self.test的值返回,那么首先要获取self.test的值,因为self此时就是t这个对象,所以self.test就是
        #t.test 此时要获取t这个对象的test属性,那么就会跳转到__getattribute__方法去执行,即此时产
        #生了递归调用,由于这个递归过程中 没有判断什么时候推出,所以这个程序会永无休止的运行下去,又因为
        #每次调用函数,就需要保存一些数据,那么随着调用的次数越来越多,最终内存吃光,所以程序 崩溃
        #
        # 注意:以后不要在__getattribute__方法中调用self.xxxx

尽量使用property函数替代以上魔法方法

self和cls:

self指向对象本身
cls表示这个类本身

特性property

通过property函数将存取方法作为参数(获取方法在前,设置方法在后)创建一个特性,然后将属性名称关联到这个特性
calss Rectangle:
    def __init__(self):
        self.width = 0
        self.height = 0
    def set_size(self,size):
        self.width, self.height = size
    def get_size(self):
        return self.width, self.height
    size = property(get_size, set_size)

    r = Rectangle()
    r.width = 10
    r.height = 5
    r.size 
    =>(10,5)
    r.size = 150, 100
    r.width
    =>150
调用函数property时,可以不指定参数,指定一个参数,指定三个参数或指定四个参数。
若没有指定参数则创建的特性将既不可读也不可写。
若指定了一个参数(获取方法),创建的特性将是只读的
第四个参数也是可选的,指定一个文档字符串
这些参数分别为fget,fset,fdel,doc

解析:
property其实并不是函数,而是一个类。它的实例包含一些魔法方法
这些魔法方法为__get__,__set__,__delete__,它们一道定义了所谓的描述符协议。只要对象实现了这些方法中的任何一个,它就是一个描述符
描述符的独特之处在于其访问方式,如,读取属性(具体说,是在实例中访问类中定义的属性)时,若它关联的是一个实现了__get__的对象,将不会返回这个对象,而是调用方法__get__并将结果返回。

@property成为属性函数,可以对属性赋值时做必要的检查,并保证代码的清晰短小,主要有2个作用

  • 将方法转换为只读
  • 重新实现一个属性的设置和读取方法,可做边界判定
class Money(object):
    def __init__(self):
        self.__money = 0

    @property
    def money(self):
        return self.__money

    @money.setter
    def money(self, value):
        if isinstance(value, int):
            self.__money = value
        else:
            print("error:不是整型数字")

探讨继承

确定一个类是否是另一个类的子类
    内置方法issubclass
        issubclass(Student, People)
        =>True
若有一个类,想知道其基类,可访问特殊属性__bases__
    Student.__bases__
    =>class __main__.People at 0x324e43
确定类属于哪个类
    isinstance(s,str)
    s.__class__

抽象基类 abc模块

from abc import ABC, abstractmethod

class Talker(ABC):
    @abstractmethod
    def talk(self):
        pass
@为装饰器
抽象类的特征是不能实例化

常用函数:

callable(object)    判断对象是否是可调用的(如是否是函数或方法)
getattr(object, name[, default]) 获取属性的值,还可提供默认值
hasattr(object, name)  确定对象时候有指定的属性
setattr(object, name, value)  将对象的指定属性设置为指定的值

元类

类也是对象,只要使用关键字class,Python解释器在执行的时候就会创建一个对象。

class Obj():
    pass

将在内存中创建一个对象,名字是Obj。这个类对象拥有创建实例对象的能力,可以做以下操作:

  • 可以将它赋值给一个变量
  • 可以拷贝它
  • 可以为它增加属性
  • 可以将它作为函数参数传递

动态创建类

通过内建函数type可以动态的创建类

type(Obj())  # <class '__main__.Obj'>
type(Obj)  # <type 'type'>

type对Obj查看类型时,答案是type 即元类

type可以接受一个类的描述作为参数,然后返回一个类

type(类名, 由父类名称组成的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))

class Test: #定义了一个Test类
    pass
Test() #创建了一个Test类的实例对象
等同于下面

Test = type("Test",(),{}) #定了一个Test类
    Test() #创建了一个Test类的实例对象
    
help(Test) # help查看Test类结构

可以使用type创建带有属性或继承关系的类:

Animal = type("Animal", (), {"name" : "Animal"})
等效于
class Animal():
    name = "Animal"
    
Dog = type("Dog", (Animal,), {})
class Dog(Animal):
    pass

使用type创建带有方法的类:

先定义方法,再将方法赋值给属性
实例方法:
def getName(self):
    print(self.name)
Dog = type("Dog", (Animal,), {"getName" : getName})

hasattr(Dog, "getName") # 判断Dog类中是否有getName这个属性 返回True

静态方法:
@staticmethod
def staticTest():
    print("static method")

Dog = type("Dog", (Animal,), {"getName" : getName, "staticT" : staticTest})
dog = Dog()
dog.getName()
dog.staticT() # staticT 映射 staticTest

类方法:
@classmethod
def classTest(cls):
    print(cls)

Dog = type("Dog", (Animal,), {"classTest" : classTest})
dog = Dog()
dog.classTest()

以上通过type() 动态创建类 实际通过元类实现

class Foo(object):
    pass
实际上,解释器将其解释为:Foo = type('Foo', (object,), {})

所谓元类

元类是类的类对象,即类是元类的实例,Python中默认的元类为type,动态自定义元类的方式实现对类的创建

元类就是用来创建类的
MyCls = MetaClass() # 元类创建一个对象,即类对象
MyObj = MyCls() # 类创建实例对象
Python中所有的东西都是对象;包括整数、字符串、函数以及类。且它们都是从一个类创建而来,这个类就是type

以下展示各个对象的__class__属性
字符串:type 'str'
整数:type 'int'
函数:type 'function'
实例对象:class '__main__类名'  连续调用两次__class__ 返回type类型
类:type 'type'
python 3 中,定义 metaclass 的语法:
class Foo(metaclass=Singleton ): 
    pass

__metaclass__属性

可以在定义一个类的时候为其添加__metaclass__属性

class Foo(object): # py3默认加载object
    __metaclass__ = ... # Python2用法,Python3的用法为i.e. the __metaclass__ attribute is no longer used, in favor of a keyword argument in the list of base classes
    ...

若定义类时指定了__metaclass__属性,则python会用元类创建类Foo;顺序为: class Foo(object)类定义完,不过还没在内存中创建,python会在类的定义中寻找__metaclass__属性,若有则用它创建类Foo,没有就使用内建的type来创建该类。

实际上python做了以下操作:

  1. Foo中有__metaclass__属性吗?有就通过该属性创建名为Foo的类(对象)
  2. 若没有__metaclass__,python会继续在父类中寻找,并尝试做第一步同样的操作
  3. 若python在父类中找不到__metaclass__,则会在模块层次中寻找该属性,并尝试做第一步同样的操作
  4. 若完全找不到该属性,则通过内置的type创建这个类对象。

__metaclass__中可赋值type或使用到type或子类化type的代码

自定义元类

元类的主要目的是当创建类时能够自动改变类。如,模块里所有类的属性都为大写,则通过模块层次设定__metaclass__,这个模块中的所有类都会通过这个元类来创建

实例:

def upper_attr(future_class_name, future_class_parents, future_class_attr):

    #遍历属性字典,把不是__开头的属性名字变为大写
    newAttr = {}
    for name,value in future_class_attr.items():
        if not name.startswith("__"):
            newAttr[name.upper()] = value

    #调用type来创建一个类
    return type(future_class_name, future_class_parents, newAttr)

class Foo(object, metaclass=upper_attr):
    bar = 'bip'

print(hasattr(Foo, 'bar'))
print(hasattr(Foo, 'BAR'))

f = Foo()
print(f.BAR)

用class当做元类来使用:

class UpperAttrMetaClass(type):
    # __new__ 是在__init__之前被调用的特殊方法
    # __new__是用来创建对象并返回之的方法
    # 而__init__只是用来将传入的参数初始化给对象
    # 你很少用到__new__,除非你希望能够控制对象的创建
    # 这里,创建的对象是类,我们希望能够自定义它,所以我们这里改写__new__
    # 如果你希望的话,你也可以在__init__中做些事情
    # 还有一些高级的用法会涉及到改写__call__特殊方法,但是我们这里不用
    def __new__(cls, future_class_name, future_class_parents, future_class_attr):
        #遍历属性字典,把不是__开头的属性名字变为大写
        newAttr = {}
        for name,value in future_class_attr.items():
            if not name.startswith("__"):
                newAttr[name.upper()] = value

        # 方法1:通过'type'来做类对象的创建
        # return type(future_class_name, future_class_parents, newAttr)

        # 方法2:复用type.__new__方法
        # 这就是基本的OOP编程,没什么魔法
        # return type.__new__(cls, future_class_name, future_class_parents, newAttr)

        # 方法3:使用super方法
        return super(UpperAttrMetaClass, cls).__new__(cls, future_class_name, future_class_parents, newAttr)
        
# python3的用法
class Foo(object, metaclass = UpperAttrMetaClass):
    bar = 'bip'

print(hasattr(Foo, 'bar'))
# 输出: False
print(hasattr(Foo, 'BAR'))
# 输出:True

元类本身:

  1. 拦截类的创建
  2. 修改类
  3. 返回修改之后的类

标准库概览

操作系统接口

os模块提供了与操作系统相关联的函数

import os   # 建议使用import os 而非from os import 如此可以保证os.open()不会覆盖内置函数open()
os.getcwd()   # 返回当前工作目录
os.chdir('/server/accesslogs') # 修改当前的工作目录
os.system('mkdir today') # 执行系统命令mkdir

针对日常的文件和目录管理任务,:mod:shutil模块提供了一个易于使用的高级接口

import shutil
shutil.copyfile('data.db', 'archive.db')
shutil.move('/build/executables', 'installdir')

字符串正则匹配

re模块为高级字符串处理提供了正则表达式工具:

import re
re.findall(r'\bf[a-z]*', str)  # 从str中匹配正则表达式,返回匹配的列表
re.sub(r'(\b[a-z]+)', str)  # 
str.replace('too', 'two')  # 字符串str替换too为two

数学模块为浮点运算提供了对底层C函数库的访问:

import math
math.cos()
math.log()

random提供了生成随机数的工具

import random
random.choice(seq)
random.randrange(n) # random integer chosen from range(n
random.random() # random float [0,1)

访问互联网

有几个模块用于访问互联网以及处理网络通信协议。最简单的是两个用于处理urls接收的数据的urlib.request以及用于发送电子邮件的smtplib

from urlib.request import urlopen
for line in urlopen('www.baidu.com'):
    line = line.decode('utf-8') # Decoding the binary data to text
    if 'EST' in line or 'EDT' in line: # look for Eastern Time
        print(line)

import smtplib
server = smtplib.SMTP('host')
server.sendmail(tomail, frommail, 'To:', 'From:')
server.quit()

日期和时间

datetime模块为日期和时间处理提供了方法,并支持格式化输出,该模块还支持时区处理

from datetime import date

计算程序运行时间:

1.程序开始到程序结束的运行时间
import datetime
start = datetime.datetime.now()
end = datetime.datetime.now()
print ((end - start).seconds)

2.
start = time.time()
end = time.time()
print (end-start)

3.程序cpu时间
start = time.clock()
end = time.clock()
print (end-start)

数据压缩

以下模块直接支持通用的数据打包和压缩格式:zlib,gzip,zipfile,tarfile

import zlib

性能度量

timeit

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值