类和对象+正则表达式笔记

类和对象

面向对象

封装对外部隐藏对象的工作细节
继承子类自动共享父类之间数据和方法的机制
多态可以对不同类的对象调用相同的方法,产生不同的结果

类对象

“Python无处不对象”:当类定义完之后,自然就是类对象。在这个时候,你可以对类的属性(变量)进行直接访问

基本特征

封装

对象=属性(变量)+方法(函数)如果对象的属性跟方法名相同,属性会覆盖方法

类的属性名和方法名绝对不能相同

需要先创造类(class)(类名约定以大写字母开头,函数用小写字母开头),然后调用使用点操作符

class Turtle#只是名字
color="green"    #属性
def climb(self):  #方法
    print("正在努力爬")
def bite(self):
    print("咬你哦咬你哦")
    
#运行以上代码
t1=Turtle()
tt.bite()
输出:咬你哦咬你哦

t2=Turtle()
t2.legs=3
t2.legs
输出3#但是不影响t1.legs等于4

self代表上面的t1,t2

继承

子类(B),基类(A)

class A:
    x=520
    def hello(self):
        print("你好呀")
class B(A):
    pass
b.x
>>>520
b.hello()
>>>你好呀

如果B 里面有和类A 一样的属性和方法名,会覆盖掉

判断继承关系:

  1. isinsatance(b,B),返回True判断对象 a 是否为 类 A 的实例对象

​ isinsatance(b,A)也返回True

  • 如果 objec t是 classinfo 的子类的一个实例,也符合条件
  • 如果第一个参数不是对象,则永远返回False
  • classinfo 可以是类对象组成的元祖,只要class与其中任何一个候选类的子类,则返回 True
  • 如果第二个参数不是类或者由类对象组成的元祖,会抛出一个 TypeError 异常
  1. inssbuclass(B,A)返回True判断一个类是否为另一个类的子类
    • 一个类被认为是其自身的子类
    • classinfo 可以是类对象组成的元祖,只要 class 与其中任何一个候选类的子类,则返回 True
    • 在其他情况下,会抛出一个 TypeError 异常

多重继承,调用时返回左边的父类,找不到继续往下找

组合,绑定
class Garden:
    t=Turtle()
    c=Cat()
    def say(self):
        self.t.say()#self用来绑定对象
        self.c.say()
g=Garden()
g.say()

#判断Self
c=C()
c.get_self()

#查找对象的属性
c.__dict__
#往对象里面加属性(两种方法)
c.set_x(250)
c.__dict__['键名']=#如果不加self,类和属性x的值都不变,是会新建一个局部变量x
calss C:
    x=100
    def set_x(self,v):
        x=v
c=C()
c.set_x(250)
c.x
>>>100
C.x()
>>>100
#如果对象c没有某个属性,会跟着类走
C.x=250                     #不建议做
c.x
>>>250
#最小的类,可以当作字典,列表使用
class C:
    pass
c=C()
c.x=5
c.y=6
print(c.x)
>>>5
重写(子类对父类重写函数)

调用未绑定的父类方法

class D(C)
class D:
    def __init__(self,x,y,z):
        C.__init__(self,x,y)
        self.z= z
       
    def add(self):
        return self.add(self)+self.z

但是可能会出现钻石继承的问题

B1,B2继承A,C同时继承B1,B2,调用出来A 会出现两次

解决方法:调用super()函数,直接把B1,B2,C里面调用函数的地方变成super().函数名

#看函数,方法解析顺序(MRO)
b.mro()

super函数论坛有备用知识,依赖mro

Mix-in()

如果给mixin起名是C,D同时继承C和B,那么遇到Super的时候如果自己没有函数,会调用到B里面

class Displayer:
    def dispaly(self,message):
        print(message)
        
class LoggerMixin:
    def log(self,message,filename="logfile.txt"):
        with open(filename,"a") as f:
            f.wirite.lof(message)         
    def dispaly(self,message):
        super().display(message)
        self.log(message)
        
class Mysubclass(LoggerMixin,Displayer):
    def log(self,message):
      super()log(message,filename="subclasslog.txt")
        
subclass=Mysubclass()
subclass.display("this is a test")

#思路:先在Mysubclasss里面找display,然后第一句super跳到Loggermixin(message),然后又是一个super跳到Displayer打印,然后回到Loggermixin第二局self.log(message),跳到自己的log写入文件,名称是subclasslog

type()

用来创造类 type(“类名”,(父类名,),dict(x=250)(属性),value=520)

__init_subclass(cls,value)__

可以覆盖子类属性

多态
  1. len函数也支持多态

  2. 类继承多态:重写(基类函数用pass,后面子类重新定义函数内容)

  3. 自定义函数,参数写成子类名字可以直接调用类里面的所有内容

    def animal(x):
        x.intro()
        x.say()
    animal(c)
    
鸭子类型

鸭子类型(duck typing)是动态类型的一种风格。

在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由当前方法和属性的集合决定

“私有变量”

(通过某种方法,使得对象里面的属性和变量不被外界访问)

name mangling(名字修饰):前面加两个下划线,e.g.__x

执意访问x:对象名加下划线加类名加函数或者属性名:c._D__x

如果想要单独添加一个私有变量,就不会被改名隐藏

_单个下划线开头变量:仅供内部使用

单个下划线结尾变量: 为了保留字后面加"_"

__slots__,锁属性,省空间

class C:
    __solts__=["x","y"]
    def init__(self,x):
        self.x=x

继承自父类的__slots__属性不会在子类中生效

魔法方法:类实例化时被自动调用

创建和注销

1.__init__(self[,....])自动创建实例

init 特殊方法不应当返回除了 None 以外的任何对象

当我们的实例对象需要有明确的初始化步骤的时候,你可以在 init 方法中部署初始化的代码

构建对象:__new__(cls[,..])然后传递给init

用到new:

class Capstr(str):#会继承字符串的所有操作
    def __new__(cls,string):
        string=string.upper()
        return super().__new__(cls,string)#交给new的爸爸去做
cs=Capstr(Fish)
cs.lower
>>>'fish'
class C2F(float):
        "摄氏度转换为华氏度"
        def __new__(cls, arg=0.0):
                return float.__new__(cls, arg * 1.8 + 32)

继承不可变类型时,重写new比较方便,比如return str.__new__(cls,string)

2.__del__销毁函数

class Capstr(str):
    def __init__(self):
        print("我来了")
    def __del__(self):
        print("我走了")
c=C()
>>>我来了
del c #只在不被引用的时候发生
>>>我走了

重生

#方法1:用全局变量
class D:
    def __init__(self):
        print("我来了")
    def __del__(self):
        global x
        x=self
d=D()
#方法2,闭包函数:参数传递:self保存在外部函数x变量
class D:
    def __init__(self,name,func):
        self.name=name
        self.func=func
    def __del__(self):
        self.func(self)        
def outter():#闭包
    x=0
    def inner(y=None):
        nonlocal x 
        if y:
            x=y
        else:
            return x
    return inner
f=outter()
e=D("我",f)
del e
g=f()
g.name
>>>

运算相关

  1. 工厂函数:工厂函数,其实就是一个类对象。当你调用他们的时候,事实上就是创建一个相应的实例对象
class S(str):
    def __add__(self,other):
        return len(self)+len(other)
s1=S("Fish")
s2="Silly"
s1+s2
>>>9
#中文也能变整数
class ZW:
    def __init__(self,num):
        self.num=num
   
    def __int__(self):
        try:
            return int(self.num)
        except ValueError:
            zw={"零":0,"一":1}
            result=0
            for each in self.num:
                if each in zw:
                    result+=zw[each]
                else:
                    result+=int(each)
                result *= 10
            
            return result // 10     

反算数运算

调用前提:当运算时,如果左侧的对象和右侧对象是不同类,并且左侧对象没有对应的算数运算方法或者这个方法返回NotImplemented,那么寻找右侧对象是否有反算术运算并执行

增强赋值运算

s1+=s2

重新定义一个相同名字的类会覆盖

位运算

与& 只有两个数二进制相同位置都一样结果对应的位才是1,否则是0,

或| 只要其中某个位是1,结果对应位就是1

非~ 按位取反 补码

异或^ 某个位不一样的话就是1

左移 运算对象<<移动位数比如1000左移两位是100000,结界在最右边,左移加进来两个0

右移 运算对象>>移动位数

移动位数必须是正数

优先级:或,异或,与优先级依次递增,非和正负号是一个优先级

math和index

ulp()表达math的最低有效位

index:对象作为索引值被访问

class C:
    def __index__(self):
        print("被拦截了")
        return 3
c=C()
s="Fish"
s[C]
>>>被拦截了
bin(c)     #返回二进制形式
被拦截了
'0b11'

比较

__lt__拦截小于号<

__gt__拦截大于号>

__eq__拦截等于号=

字符串比较初始是比较编码大小

如果想要拦截不能实现,可以定义函数以后在下面写`le=None```

属性访问

函数和对应的魔法方法:

  1. hasattr(对象,“属性名”),判断对象是否有某个属性,返回True或者False,注意属性名要用字符串格式

  2. getattr(对象,“属性名”[, default]),得到属性的内容,否则返回Default内容

    __getattibute__(self,attrname)

    class C:
        def __init__(self,name,age):
            self.name=name
            self.__age=age
        def __getattribute__(self,attrname):
            print("拿来吧你")
            return super().__getattribute__(attrname)
    c=C("我"18)
    getattr(c,"name")
    >>>拿来吧你
    我
    
    c._C__age
    >>>拿来吧你
    18
    

__getattr__只在用户获取一个不存在的属性的时候才被触发,会拦截然后执行下面语句

class C:
    def __init__(self,name,age):
        self.name=name
        self.__age=age
    def __getattribute__(self,attrname):
        print("拿来吧你")
        return super().__getattribute__(attrname)
    def __getattr__(self,attrname):
        if attrname==Fish:
            print("I love fish")
        else:
            raise AttruibuteError(attrname)
c=C("我"18)
c.Fish
>>>
拿来吧你
I love fish
#献给getattribute然后return到getattr
  1. setattr(对象,“属性名”,属性值)

    __setattr()__

    #死亡螺旋:
    class D:
        def __setattr__(self,name,value):
            self.name=value
    d.D()
    d.name="我"
    >>>报错#因为赋值了两次
    
    #解决方法,可以给super也可以用下面的
    class D:
        def __setattr__(self,name,value):
            self.__dict__[name]=value
    d.D()
    d.name="我"
    d.name
    
  2. delattr(对象,“属性名”)删除

__delattr__和上面同理,要小心死亡螺旋

property函数

property() 函数允许编程人员轻松、有效地管理属性访问

class C:
    def __init__(self):
        self._x=250
    def getx(self):
        return self._x
    def setx(self,value):
        self._x=value
    def delx(self):
        del self._x
    x=property(getx,setx,delx)
c=C()
c.x
>>>250

可以作为装饰器,使得创建只读函数变得很简单

class D:
    def __init__(self):
        self._x=250
    @property
    def x (self):
        return self._x
#只读的话不带下面的
    @x.setter
    def x (self,value):
        self._x=value
    @x.deleter
    def x(self):
        del self._x
d=D()
d.x

索引,切片

对象对索引时,python会调用__getitem__(self,index)拦截索引,切片和获取操作

slice函数用法:和字符串一样只不过空的地方要写None

s[slice(7,None)]

迭代器

__iter__(self)

一个容器如果是迭代器,那必须实现iter魔法方法,这个方法实际上就是返回迭代器本身

列表里没有next(),不是一个迭代器,是个可迭代对象

__next__(self)

真正用来迭代

自己的迭代器:
class Double:
    def __init(self,start,stop):
        self.value=start-1
        self.stop=stop
    def __inter__(self):
        return self
    def __next__(self):
        if self.value==self.stop:
            raise StopIteration
        self.value+=1
        return self.value*2
d.Double(1,5)
for i in d:
    print(i,end=" ")
>>>2 4 6 8 10
#让对象干嘛,对象就干嘛,这个例子里面是让对象一直翻倍,直到Stop值  
    pos = turtle.move()
    # 在迭代器中删除列表元素是非常危险的,经常会出现意想不到的问题,因为迭代器是直接引用列表的数据进行引用
    # 这里我们把列表拷贝给迭代器,然后对原列表进行删除操作就不会有问题了^_^
    for each_fish in fish[:]:
        if each_fish.move() == pos:
            # 鱼儿被吃掉了
            turtle.eat()
            fish.remove(each_fish)
            print("有一条鱼儿被吃掉了...")

代偿

1.__contain__

a in b 优先找contain,然后找iter,next,最后找getitem,非零返回True

2.__bool__

优先bool,不行了换__len__,结果是非零的话返回True

```__call(self[,位置参数,关键字参数])`可以像调用函数一样调用对象

class C:
    def __call__(self):
        print("hai")
c=C()
c()
>>>hai

字符串相关

__str__(self)(str():参数转化成字符串,给人看)和__repr__(self)(repr():对象转化为字符串,给程序看,是eval函数的反函数

__repr__(self)可以代偿__str__(self),而且使用场景更多

class C:
    def __repr__(self):
        return "I love you"
c=C()
repr(c)
>>>"I love you"
str()
>>>"I love you"

类方法

在def上一行加上@classmethod

静态

静态属性

在类中直接被定义的属性

class C:
    count = 0  # 静态属性
    def __init__(self):
        C.count = C.count + 1  # 类名.属性名的形式引用

def getCount(self):
    return C.count

静态方法

@staticmethod放在def前一行

使得可以用类名访问

静态方法不需要绑定对象

不涉及类属性和继承的时候用比较好

最大的优点是:不会绑定到实例对象上,换而言之就是节省开销

描述符

  1. 定义:实现了__get__(self,instance,owner=None),__set__(self,instance,value),__delete__(self,instance)三个方法的功能
    • get(self, instance, owner)
      - 用于访问属性,它返回属性的值
    • set(self, instance, value)
      - 将在属性分配操作中调用,不返回任何内容
    • delete(self, instance)
      - 控制删除操作,不返回任何内容
  2. 应用:需要你设计一些更为复杂的操作来响应(例如每当属性被访问时,你也许想创建一个日志记录)。最好的解决方案就是编写一个用于执行这些“更复杂的操作”的特殊函数,然后指定它在属性被访问时运行。那么一个具有这种函数的对象被称之为描述符。
  3. 应用方法 :描述符被编写成独立的类,然后将描述符的实例对象赋值给类属性,从而可以实现对该属性读取,写入和删除的全方位拦截
  4. 举例

__get__(self,instance,owner=None)

把想要被管理类的属性作为对象,如类C种属性x,x=D()

self:x属性的值

instance:被拦截的属性所在类的对象

owner:被拦截属性所在的类

#不太好,不如property的方法
class D:
    def __get__(self,instance,owner):
        return instance._x
    def __set__(self,intance,value):
        intance._x=value
    def __delete__(self,intance):
        del instance._x
class C:
    def __init__(self,x=250):
        self._x=x
        x=D()
        
c=C()
c.x
>>>250
        
#创建自己的proeperty方法
clss Myproperty():
    def __init__(self,fget=None,fset=None,fdel=None):
        self.fget=fget
        self.fset=fset
        self.fdel=fdel
    def __get__(self,instance,owner):
        return self.fget(instance)#instance:被拦截的属性所在类的对象
    def __set__(self,intance,value):
        self.fset(instance,value)
    def __delete__(self,intance):
        self.fdel(instance)
class C:
    def __init__(self):
        self._x=250
    def getx(self):
        return self._x
    def setx(self,value):
        self._x=value
    def delx(self):
        del self._x
    x=Myproperty(getx,setx,delx)
c=C()
c.x        
  1. 描述符只能应用于类属性,不能应用于对象属性

  2. 分类:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A5qGlD5O-1677032350663)(Python面向对象+正则表达式.assets/image-20221124170037440.png)]

访问优先级(赋值会覆盖拦截):

__getattribute__>数据描述符>实例对象属性>非数据描述符>类属性

6.除了三个方法之外的新方法:__set_name__(self,name,owner)

#原来的
class D:
    def __init__(self,name):
        self.name=name
    def __get__(self,instance,owber):
        print("get~")
        return instance.__dict__.get(self,name)#instance:被拦截的属性所在类的对象
    def __set__(self,instance,value):
        print("set~")
        instance.__dict__[self.name]=value
class C:
    x=D("x")
    
c=C()
c.x=250
>>>set~
c.x
>>>get~
250

#优雅的
class D:
    def __set_name__(self,owner,name):
        self.name=name
    def __get__(self,instance,owber):
        print("get~")
        return instance.__dict__.get(self,name)#instance:被拦截的属性所在类的对象
    def __set__(self,instance,value):
        print("set~")
        instance.__dict__[self.name]=value
class C:
    x=D()

c=C()
c.x=250
>>>set~
c.x
>>>get~
250

类描述器

类的装饰器

在类被实例化之前进行拦截来干预

类作为装饰器去装饰函数

生成器

功能:函数结束后还保留内容,让函数可以

做法:yield 代替 return语句,每次调用提供一个数据

特点:1.不走回头路 2.支持next语句

不可以用顺序索引

生成器表达式

列表推导式

生成器表达式:用普通小括号括起来(i for i in range (10))

  • 可以作为函数的参数使用,外面可以不加小括号

定制容器

  1. 协议:
    • 如果希望定制容器不可变,则只需要定义__len__()__getitem__()方法
    • 如果希望可变,还需要定义__setitem__()__deletitem__()

正则表达式

  1. 用途:查找符合某些复杂规则的字符串

  2. re模块

    import re
    re.search(r'fish(可变)',"I love fish")
    #这里前面的fish也可以换成通配符'.',可以匹配除了换行符之外的任何字符
    #如果就是想匹配点号,在前面加\
    
    • 如果想匹配字符类中任何字符用[]包起来,中间还可以用-表示范围
    • 重复匹配的话可以在需要匹配的字符后加{个数}
    • \d表示0-9
  3. 特殊符号:

    元字符: .^$+?{}[]|()

    • 点号:通配符
    • ^在开头才算
    • $在结尾才算
    • 反斜杠后面加上的是数字,那它还有两种用法:

    • 如果跟着的数字是1~99,那么它表示引用序号对应的子组所匹

    配的字符串。

    • 如果跟着的数字是以0开头或者是三位数字,那么它是一个八进

    制数,表示的是这个八进制数对应的ASCII字符

    • 小括号(( ))本身是一对元字符,被它们括起来的正则表达

      式称为一个子组。后面可以用来引用

      >>> re.search(r"(FishC)\1", "FishC.com") 
      #这里的\1表示引用前面序号为1的子组(也就是第一个子组),所 以r"(FishC)\1"相当于r"FishCFishC"
      
    • []生成字符类,除了:

      • (1)小横杆(-),用它来表示范围:

        >>> re.findall(r"[a-z]", “FishC.com”)

        [‘i’, ‘s’, ‘h’, ‘c’, ‘o’, ‘m’]

        >>> # findall()表示找出所有匹配的内容,并将结果返回为一个列表

        (2)反斜杠(/),这里用于字符串转义,例如\n表示匹配换行符

        号:

        >>> re.search(r"[\n]", “FishC.com\n”)

        <_sre.SRE_Match object; span=(9, 10), match=‘\n’>

        (3)脱字符(^),用于表示取反的意思:

        >>> re.findall(r"[^a-z]", “FishC.com”)

        [‘F’, ‘C’, ‘.’]

        • {}表示重复次数

        • 同样表示重复的:

          • 星号(*)相当于{0,}

          • 加号(+)相当于{1,}

          • 问号(?)相当于{0,1}

          非贪婪模式

          在表示重复的元字符后面再加上一个问号(?)即可:

          >>> s = “I love FishC.com

          >>>re.search(‘<.+?>’, s)

          <_sre.SRE_Match object; span=(0, 6), match=‘’>

反斜杠**+普通字母=**特殊含义

实用函数

  1. 需要重复使用某个正则表达式,那么可以先将该正则表达式编

    译成模式对象。 使用re.compile()方法来进行编译:

    \>>> p = re.compile("[A-Z]") 
    
    \>>> p.search("I love FishC.com!") 
    
    <_sre.SRE_Match object; span=(0, 1), match='I'> 
    
    \>>> p.findall("I love FishC.com!") 
    
    ['I', 'F', 'C'] 
    
  2. re.search(pattern, string, flags=0)

    flag不用写

    • 要获得具体字符串:结果赋值给result,然后再result.group

      • 如果结果中有元组,还可以按序号拿到
    • start()、end()和span()分别返回匹配的开始位置、结束位置和匹配的

      范围

    • 在findall()方法 中,如果给出的正则表达式包含了一个或者多个子组,就会返回子组中

      匹配的内容。如果存在多个子组,那么它还会将匹配的内容组合成元组

      的形式再返回。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值