Fork me on GitHub

Python进阶

Python一切皆对象

对象介绍

  Python的对象是一种数据抽象或者数据结构抽象,对象应该同时具备:本征值(Indentity)、型式(Type)、值(Value)三个参数。

a = 45
print(id(a)) # 表示在python中的唯一内存地址,具备唯一性
print(type(a))
print(a)

/*-----output-------*/
2063144480432
<class 'int'>
45

  对象具体指变量Variable、类Class、函数Function,具备四种用途:

  • 作为返回值
  • 赋值给另一个对象
  • 作为函数参数传递
  • 添加到另一个集合对象

Object、Class、Type关系

  type可以用于查看对象,创建对象

a = 45
print(type(a))
print(type(type(a)))
print(type.__bases__)
print(type(type))

/*-----output-------*/
<class 'int'>  # a由int创建
<class 'type'> # int由type创建
(<class 'object'>,)  # type继承object
<class 'type'> # type自己创建自己

  class声明一个类

class STU:
    pass

stu = STU()
print(type(stu))
print(type(STU))

/*-----output-------*/
<class '__main__.STU'> # stu的实例化由STU完成
<class 'type'> # STU类由type创建

   object是所有class的基类

class STU:
    pass

print(STU.__bases__)

/*-----output-------*/
(<class 'object'>,)  # STU继承自object类

 1、所有的class都继承自object,所有的class都由type创建

  2、type本身也是class,因此type自身创建了自身

  3、python中一切皆对象,因为所有对象都由type创建,包括type类本身

Python的内置类型

  None:本身也是一个对象,全局只有一个

  数值:int,float,complex(复数),bool

  迭代类型:迭代器和生成器

  序列类型:list、bytes、bytearray、memoryview(二进制)、tuple、str、array

  映射:dict

  集合:set、frozenset(不可变)

  上下文管理:with(文件管理)

  其他:模块类型(import)、class、函数类型、方法类型、代码类型、type类型、object类型、ellipsis类型、notimplemented类型

  所有的对象都有类型

类变量与实例变量

  类变量是所有相关类实例共用的变量,只能通过类去修改类变量。通过类实例修改类变量时将会新建一个实例变量,无法修改类变量。

class A:
    # 类变量
    character = 0

    def __init__(self,x):
        self.x = x  # 实例变量


a = A(2)

# 可以通过类实例访问类变量忽然实例变量
print(a.x,a.character)

# 可以通过类访问类变量,但不能访问实例变量
print(A.character)

# 实例对象修改类变量时会重新创建一个对应的实例变量!
a.character = 5
print(a.character)
A.character = 3
print(a.character)  # a.character = 5

私有变量

  私有属性是类的一种私密变量,通过变量前加双下划线__私有属性不能被继承,私有属性不可以作为返回值。

class Date:
    def __init__(self, year, month, day):
        # 实例属性
        self.year = year
        self.month = month
        self.day = day

class User:
    def __init__(self,birthday):

        # 私有属性:具体日期是涉密的
        self.__birthday = birthday  # 私有属性只能在类方法中直接使用,无法通过结成,无法作为返回值

    def age_get(self):
        year = self.__birthday.year  # 只能间接返回,不建议将私有属性开放给外部访问
        return 2024 - year 

if __name__ == '__main__':
    user = User(Date(1990,4,24))
    print(user.age_get())

类方法

  类方法:传入cls,装饰器为classmethod。

  静态方法:传入self类实例,装饰器为staticmethod。硬编码。

  实例方法:传入self类实例。

class Date:
    def __init__(self, year, month, day):
        # 实例属性
        self.year = year
        self.month = month
        self.day = day

    # 实例方法:带有self参数,self是当前类的实例对象
    def __str__(self):
        return F"{self.year}/{self.month}/{self.day}"

    # 静态方法:不需要添加self实例对象,实例都可以调用
    @staticmethod
    def DataTransfer(DataStr):
        y,m,d = tuple(DataStr.split('-'))
        return Date(y,m,d) # 硬编码,如果类名更改,方法就会出错

    # 类方法:添加cls,指向类
    @classmethod
    def DataTransferCls(cls,DataStr):
        y,m,d = tuple(DataStr.split('-'))
        return cls(y,m,d)


if __name__ == "__main__":
    newday = Date(2024,1,8)
    print(newday)
    newday1 = Date.DataTransfer("2024-01-25")
    print(newday1)
    newday2 = Date.DataTransferCls("2024-08-03")
    print(newday2)

魔术方法

  魔术方法是类中固有功能的拓展。以__双下划线开头。

from abc import abstractmethod, ABCMeta

class Student:
    def __init__(self, StuList):
        self.StudentList = StuList

    # 魔法函数:枚举
    def __getitem__(self, item):
        return self.StudentList[item]

    # 魔法函数:成员长度
    def __len__(self):
        return len(self.StudentList)


stu = Student(['jim', 'tom', 'eason'])
# 常规遍历
for item in stu.StudentList:
    print(item)

# 魔术方法遍历
for item in stu:
    print(item)

# 魔法方法求指定成员长度
print(len(stu))

__len__方法

  len()方法会调用__len__,当统计的是Python的内部方法时,会直接调用C语言库,速度很快。

方法重写

  子类重写父类的方法

class Animal:
    def say(self):
        print("i'm animal")


class Dog(Animal):
    def say(self):  # 重写
        print("i'm a dog")


class Duck(Animal):
    def say(self):  # 重写
        print("i'm a duck")

鸭子类型

  多个类的方法名一致,将其存入列表进行迭代调用就可以实现类似多态的功能。这些类可以统称为鸭子类型。

class Dog():
    def say(self):  
        print("i'm a dog")


class Duck():
    def say(self):  
        print("i'm a duck")

dog = Dog()
duck = Duck()
animal = [dog,duck]
for an in animal:
    an.say()

抽象基类

  抽象基类的设计非常考验框架开发的功力,常规开发中仅使用多继承。

from abc import ABCMeta,abstractmethod

class AbstractClass(metaclass=ABCMeta):
    @abstractmethod
    def kind(self):
        pass
    @abstractmethod
    def name(self):
        pass

class HistoryBook(AbstractClass):
    def __init__(self):
        pass

    def kind(self):
        pass
    def name(self):
        pass


hb = HistoryBook()

类型判断isinstance

  类型读取是type(),类型判断使用isinstance()

    pass

class B(A):
    pass
a = A()
b = B()

print(isinstance(a,B))  # 父类实例是不是和子类一致  false
print(isinstance(b,A))  # 子类实例是不是和父类一致  true
print(type(a) is B) # 父类实例是不是和子类一致  flase
print(type(b) is A) # 子类实例是不是和父类一致  true

a = 12
print(isinstance(a,int))  # 判断常量是否为int true
print(type(a) is int)  

Super()

  super函数并不是调用父类的函数,而是继承的父类中优先级最高的类。

class A:
    def __init__(self):
        print('A')

class B(A):
    def __init__(self):
        print('B')
        super().__init__()  # 调用__init__,调用顺序是按类的继承顺序来调用的

class C(A):
    def __init__(self):
        print('C')
        super().__init__()  # 调用__init__,调用顺序是按类的继承顺序来调用的


class D(C,B):
    def __init__(self):
        print('D')
        super().__init__()  # 调用__init__,调用顺序是按类的继承顺序来调用的

d = D()
print(D.__mro__)  # 打印类的继承优先顺序

Python的自省机制

  编程语言中的自省机制是指知道一个变量叫什么?有什么用途。例如__dict_、dir()、_isinstance()、type()等。高级的自省则是反射hasattr()、getattr()、setattr()、delattr()。可以使用字符串去指向整个对象,达到怎么用?。

class Person:
    name = 'user'

class Student(Person):
    def __init__(self,fullname):
        self.fullname = fullname

user = Student("lucy")
# 通过__dict__查询属性:实例中所有的变量与值组成的字典
print(user.__dict__)
# dir会列出对象的所有可用属性
print(dir(user))

With与上下文管理器

  with上下文管理器中可以使用满足上下文协议的语句

__enter__\__exit__

# with上下文管理器语句就是为了简化 try finally的写法
class Sample:
    def __enter__(self):
        # enter里面去获取资源
        print("enter")
        return self # 必须存在返回值

    def __exit__(self, exc_type, exc_val, exc_tb):
        # exit中去释放资源
        print("exit")

    def do_something(self):
        # 操作资源
        print("donging something!")


with Sample() as sam:
    sam.do_something()  # 离开with语句的时候会自动调用__exit__

contextlib

import contextlib

@contextlib.contextmanager
def Fileopen(filename):
    # yield之前进行前置处理
    print("File Open.") # 做一些操作
    yield {} # 生成一个空字典,contextmanager必须包含生成器
    # yield之后进行后续处理
    print("File End")

with Fileopen("boby.txt") as f:
    print("file processing.")

is与==

  ==用于检查对象值

  is用于检查对象值和内存地址是否相同,是更严格的==

a = [1,2,3]
b = [1,2,3]
print(id(a),id(b)) # 3046412739008  3046412738688
print(a == b) # true 仅检查值
print(a is b) # false 检查值与内存位置

c = 1
d = 1
print(id(c),id(d)) # 3046407498032 3046407498032
print(c == d) # true
print(c is d) # true  python中将一定范围内得小整数会自动进行整合

推导式

  推导式就是一行代码生成对应的数据类型。

列表推导式

  也称列表生成式,列表生成式高于列表操作

# 生成20以内的奇数
odd_list = [i for i in range(21) if i % 2 ==1]
print(odd_list)

# 复杂情况:引入函数
def handle(i):
    return i*i
odds_list = [handle(i) for i in range(21) if i % 2 ==1]
print(odds_list)

  

 生成器表达式

  将列表推导式的[]换为(),生成器表达式可以通过转换及迭代来访问。

list1 = (i for i in range(21) if i % 2 ==1) # []变成()会变成生成器
print(list1)

print(list(list1))

   

字典推导式

# 字典推导式
dict1 = {"tom1":22,"tom2":33,"tom3":44}
print(dict1)
reverse_dict = {value:key for key,value in dict1.items()} # 颠倒键值
print(reverse_dict)

  

集合推导式

# 集合推导式
dict1 = {"tom1":22,"tom2":33,"tom3":44}
set1 = {key for key,value in dict1.items()}
print(set1)

  

Bisect序列查找

  Bisect用于维护已经排序好的序列,主要有insort_right\bisect_right\insort_left\bisect_left四种方法

import bisect

li = [1,2,3,4,5,7]
index4 = bisect.bisect_left(li,4)  # 返回一个新列表
print('{} 左插 {}'.format(li,index4))
index5 = bisect.bisect_right(li,4)
print('{} 右插 {}'.format(li,index5))

   

Dict字典

userdict、dict、defaultdict的区别

  userdict是python开放给用户用于重新定义字典数据操作的类,可以进行方法覆盖等各种定义行为

  dict是python默认的dict类,任何dict的定义都是dict进行实例化

  defaudict是dict的子类,只是新增了missing方法和一个default_factory

  重新定义dict行为时继承userdict,不可以继承dict,因为继承dict只适用添加新方法,如果对dict原有的魔法函数进行覆盖将无效

垃圾回收机制

  python中的垃圾回收采用 引用计数为主,隔代回收为辅的策略

  引用计数:类似于C++的智能指针shared_fur

a = 1 # 计数器=1
b = a # 计数器=2
del a # 计数器 = 2-1 python中delete并不是回收,此时仍然有值,只有引用计数器 = 0时才会回收b

  隔代回收:当交叉引用时,会先回收引用的对象

class A:
    def __init__(self):
        self.pro = None

    def __del__(self): # 垃圾回收
        print("回收A")


class B:
    def __init__(self):
        self.pro = None

    def __del__(self):  # 垃圾回收
        print("回收B")

classA = A()
classB = B()
classA.pro = classB
classB.pro = classA
del classA # 先回收B

  

元类编程

Setter与Getter

class User:
    def __init__(self, name):
        self.name = name
        self._name = None

    def getname(self):
        return self.name

    # 直接作为一种属性
    @property # 在python中的getter方法使用@property修饰
    def gname(self):
        return self.name

    @gname.setter
    def sname(self,value):
        self.name = value


if __name__ == "__main__":
    user = User('zhang075') 
    print(user.gname,user.name)
    user.sname = "zhang" # setter
    print(user.gname,user.name)

__getattr__与__getattribute__

class User:
    def __init__(self,info = {}):
        self.info = info

    # 查找不到时会进入此函数
    def __getattr__(self, item):
        return '属性不存在'

    # 属性拦截器
    def __getattribute__(self, item):
        print('开始属性拦截')
        return super().__getattribute__(item) # 返回属性值,如果不存在会调用__getattr__


us = User(info = {'name':'zhangwei','age':'15'})

print(us.info['name'])

属性描述符

  描述符的作用是用来代理另外一个类的属性(必须把描述符定义成这个类的类属性,不能定义到构造函数中),属性描述符可以对类对象进行检查

import numbers

class IntField:
    def __get__(self, instance, owner): # 属性描述符,本质就是魔法函数
        return self.value

    def __set__(self, instance, value):
        if isinstance(value,numbers.Integral):
            print('%d 类型检查通过' % value)
        else:
            raise ValueError("类型检查不通过")
        self.value = value # 存放值

    def __delete__(self, instance):
        del self.value


class NonDataIntField:
    def __get__(self, instance, owner): # 非数据描述符
        return  self.value

class User:
    age = IntField() #age是属性描述符得对象,类对象

  描述符具备优先级:

  1>类属性
  2>数据描述符
  3>实例属性
  4>非数据描述符
  5>找不到的属性触发__getattr__()

posted @ 2024-03-04 21:35  张一默  阅读(22)  评论(0编辑  收藏  举报