Python面向对象编程(二)类方法、静态方法、属性方法、__name__、反射、双下划线方法、动态创建类、创建自定义错误类等

目录

类方法@classmethod

静态方法@staticmethod

属性方法@property

__name__

反射

hasattr

getattr

setattr

delattr

动态加载模块

类的双下划线方法

__getitem__

 __setitem__

 __delitem__    __delattr__ 

__len__

str & repr

new方法

call方法

动态创建类

创建错误类


类方法@classmethod

类方法通过@classmethod装饰器实现,其只能访问类变量,不能访问实例变量

class dog:
    name=1
    def __init__(self,name):
        self.name=name
    def func1(self):
        print(self)
    @classmethod
    def func2(self):
        print(self)
        print(self.name)

p1=dog(2)
p1.func1()
p1.func2()
# <__main__.dog object at 0x00000241F0A03400>
# <class '__main__.dog'>
# 1

可以看出类方法的self这个参数接受的不是实例本身,而是类本身,所以不能访问实例变量

这里举例一个使用场景,每次实例化一次就计数一次(这个地方不能把__num+=1放在初始化函数中,因为那样相当于创建了一个新的实例变量)

class person:
    __num=0
    def __init__(self):
        self.__add()
    @classmethod
    def __add(cls):
        cls.__num+=1
        print(cls.__num)


p1=person()
p2=person()

静态方法@staticmethod

静态方法通过@staticmethod装饰器实现,其不能访问类变量,不能访问实例变量

静态方法隔断了其跟类和实例的任何关系

class person:
    __num=0
    def __init__(self,name):
        self.name=name
    @staticmethod
    def test(obj):
        print(obj.name)

p1=person('lee')
p1.test(p1)

在调用时,他无法获取self参数,只能自己手动传入

属性方法@property

把一个方法变成一个静态的属性

调用时不要加()

class person:
    def __init__(self,name):
        self.name=name
    @property
    def test(obj):
        print(obj.name)

p1=person('lee')
p1.test
# lee

这里的应用场景是,根据对象内部的属性进行某些操作,而不需要传入参数的过程

Python @property属性详解 - 知乎

__name__

在当前模块主动执行的情况下(不是被导入执行),等于__main__

在被其它模块导入执行的情况下,等于模块名

反射

反射主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。

 说白了就是可以通过字符串的形式来操作对象的属性

hasattr

查询类或对象是否含有方法或者属性

class person:
    num=1
    def __init__(self,name,age):
        self.name=name
        self.age=age

    def walk(self):
        print(111)


p=person('lee',21)
print(hasattr(person,'num'),hasattr(person,'walk'))
# True True
print(hasattr(p,'name'),hasattr(p,'age'))
# True True

getattr

获取类或对象的方法或者属性的值

class person:
    num=1
    def __init__(self,name,age):
        self.name=name
        self.age=age

    def walk(self):
        print(111)


p=person('lee',21)
print(getattr(p,'name'))
# lee
print(getattr(person,'num'))
# 1

setattr

给类或对象的方法或者属性赋值

class person:
    num=1
    def __init__(self,name,age):
        self.name=name
        self.age=age

    def walk(self):
        print(111)

def talk(self):
    print(22222)
p=person('lee',21)
setattr(p,'name','liu')
print(p.name)
setattr(person,'talk',talk)
p.talk()
# liu
# 22222

delattr

删除类或对象的方法或属性

delattr(person,'num')

动态加载模块

可以在后期使用字符串动态的导入新的模块

方法一

__import__('model_name')

方法二

import importlib
importlib.import_module('model_name')

类的双下划线方法

全部内容可以看这个

python魔法方法长文详解 - 个人文章 - SegmentFault 思否

这里挑几个重要的写一下

__getitem__

__getitem__ :以字典的形式获取值,当使用 obj['key']的时候就会使用这个方法

class person:
    num=1
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def __getitem__(self, item):
        return self.__dict__[item]

p=person('lee',12)

print(p['name'])
# lee

在输入是列表时,可以使得类具有数组的特性

class person():
    def __init__(self,student_list):
        self.student_list = student_list
    def __getitem__(self, item):
        return self.student_list[item]

a = person([1,2,3,4])
print(a[1])#2

for i in a:
    print(i)
# 1
# 2
# 3
# 4

 __setitem__

__setitem__:以字典的形式设置值,当使用 obj['key']=value时就会调用这个方法

class person:
    num=1
    def __init__(self,name,age):
        self.name=name
        self.age=age

    def __delitem__(self, key):
        self.__dict__.pop(key)
        print(1111)
    def __delattr__(self, item):
        self.__dict__.pop(item)
        print(2222)

p=person('lee',12)

del p['name']
del p.age

 __delitem__    __delattr__ 

 __delitem__,__delattr__:都是删除,只是调用形式不一样

class person:
    num=1
    def __init__(self,name,age):
        self.name=name
        self.age=age

    def __delitem__(self, key):
        self.__dict__.pop(key)
        print(1111)


p=person('lee',12)
del p['name']

__len__

 能使用len函数调用类里面的值

class person():
    def __init__(self,name,student_list):
        self.student_list = student_list
    def __len__(self):
        return len(self.student_list)

a = person('lee',[1,2,3,4])
print(len(a))
# 4

str & repr

当什么都不设置时

class person:
    num=1
    def __init__(self,name,age):
        self.name=name
        self.age=age
p=person('lee',12)

print(p)
print(str(p))
print(repr(p))
# <__main__.person object at 0x0000022CBB838668>
# <__main__.person object at 0x0000022CBB838668>
# <__main__.person object at 0x0000022CBB838668>

 如果定义了__str__() 函数:

class person:
    num=1
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def __str__(self):
        return '11111'

p=person('lee',12)

print(p)
print(str(p))
print(repr(p))
# 11111
# 11111
# <__main__.person object at 0x0000019AF5038828>
  • str函数或者print函数调用时--->obj.__str_()
  • repr或者交互式解释器中调用时--->obj._repr__()
  • 如果_str__没有被定义,那么就会使用_repr___来代替输出
  • 注意:这俩方法的返回值必须是字符串,否则抛出异常
     

new方法

new方法负责执行__init__,是执行在__init__方法前的

class person(object):
    num=1
    def __init__(self,name,age):
        self.name=name
        self.age=age
        print(1111)
    def __new__(cls, *args, **kwargs):
        print(cls,*args, **kwargs)


p=person('lee',12)
# <class '__main__.person'> lee 12

上面这种写法重写了 new方法,所以__init__就没有被调用了

正确一般是:

class person(object):
    num=1
    def __init__(self,name,age):
        self.name=name
        self.age=age
        print(1111)
    def __new__(cls, *args, **kwargs):
        print(cls,*args, **kwargs)
        return object.__new__(cls)


p=person('lee',12)
# <class '__main__.person'> lee 12
# 1111

这里举一个实例,即单例模式,其实就是当创造了实例时,后面再尝试创造实例将会失败并直接返回第一次创造的实例

class person(object):
    num=0
    objfirst=None
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def __new__(cls, *args, **kwargs):
        if cls.num==0:
            cls.objfirst=object.__new__(cls)
            cls.num+=1
            return cls.objfirst
        else:
            return cls.objfirst


p1=person('lee',11)
p2=person('liu',33)

print(p1)
print(p2)
# <__main__.person object at 0x00000127C5FCC128>
# <__main__.person object at 0x00000127C5FCC128>

call方法

实例名()就执行这个方法

class person(object):
    num=0
    objfirst=None
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def __call__(self, *args, **kwargs):
        print(1111)


p1=person('lee',12)
p1()
# 1111

动态创建类

python中的可以使用type()函数动态的创建一个类

type('类名',(继承的类,),{属性名:值,方法名:方法})
def __init__(self,name,age):
    self.name=name
    self.age=age

def talk(self):
    print(1111)
person = type('person',(object,),{'num':1,'__init__':__init__,'talk':talk})

p1=person('lee',21)
print(p1.name)
p1.talk()
# lee
# 1111

创建错误类

python可以自己定义错误类,继承baseException的基类

class MyError(BaseException):
    def __init__(self,msg):
        self.msg=msg
    def __str__(self):
        return self.msg


try:
    raise MyError('my error')
except MyError as e:
    print(22222,e)

# 22222 my error

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值