面向对象(进阶)

目录:

面向对象高级语法部分: 

  • 静态方法、类方法、属性方法
  • 类的特殊方法
  • 反射

异常处理:

一、类成员(字段、方法和属性)

1、字段

字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同,

  • 普通字段属于对象
  • 静态字段属于

 

复制代码
class Province:

    # 静态字段
    country = '中国'

    def __init__(self, name):

        # 普通字段
        self.name = name

# 直接访问普通字段
obj = Province('河北省')
print(obj.name)

# 直接访问静态字段
Province.country


*****************************************************************************

class foo:

name = 'Python2' #静态字段

def __init__(self,age):
#普通字段
self.age =age
self.gender ='男'
def fun(self):
print(self.name,self.age,self.gender)
#通过对象p直接调用普通字段
p = foo(12)
p.fun()
p.age
#类直接调用静态字段
foo.name
复制代码

【普通字段需要通过对象来访问】【静态字段通过类访问】,在使用上可以看出普通字段和静态字段的归属是不同的。其在内容的存储方式类似如下图:

  • 静态字段在内存中只保存一份
  • 普通字段在每个对象中都要保存一份

应用场景: 通过类创建对象时,如果每个对象都具有相同的字段,那么就使用静态字段

二、方法

方法包括:普通方法、静态方法和类方法,三种方法在内存中都归属于类,区别在于调用方式不同。

  • 普通方法:对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self
  • 类方法:由调用; 至少一个cls参数;执行类方法时,自动将调用该方法的复制给cls
  • 静态方法:由调用;无默认参数;
复制代码
class  foo:
    def __init__(self,name):
        self.name = name

    def A(self):       #普通方法。至少一个参数self
        print(self.name,'普通方法')

    @staticmethod   # 静态方法无参数
    def B():
        print('无参数,  静态方法')

    @classmethod     
    def C(cls,name):       #类方法,至少一个参数cls
        cls.name=name
        print(name,'类方法')

#调用普通方法
p = foo('self参数')
p.A()       #self参数 普通方法

#调用静态方法
foo.B()     #无参数,  静态方法

#调用类方法
foo.C('cls参数 ')    #cls参数  类方法
复制代码

相同点:对于所有的方法而言,均属于类(非对象)中,所以,在内存中也只保存一份。

不同点:方法调用者不同、调用方法时自动传入的参数不同。

三、属性(属性是普通方法的变种)

1、属性的基本使用

复制代码
class foo:
    def __init__(self,name):
        self.n = name

    def fun1(self):
        print(self.n)
    #定义属性
    @property
    def fun2(self):
        print(self.n)

#方法调用
p = foo('Python2')
p.fun1()

"""******************************"""
#属性调用
foo('Python3').fun2
复制代码

 

由属性的定义和调用要注意一下几点:

    • 定义时,在普通方法的基础上添加 @property 装饰器;
    • 定义时,属性仅有一个self参数
    • 调用时,无需括号
                 方法:foo().fun1()
                 属性:foo().fun2

注意:属性存在意义:访问属性时可以制造出和访问字段完全相同的假象

           属性由方法变种而来,如果Python中没有属性,方法完全可以代替其功能。

实例:

 

2、属性的两种定义方式:

  • 装饰器 即:在方法上应用装饰器
  • 静态字段 即:在类中定义值为property对象的静态字段
复制代码
class foo:
    @property    #装饰器调用
    def fun1(self):
        return '装饰器方式添加属性'

    def fun2(self):
        return '静态字段方式'
    BAR = property(fun2)    #静态字段调用  调用时改变了函数名为BAR
    
#装饰器方式添加属性调用    
p = foo()
ret = p.fun1
print(ret)
#静态字段方式调用
pf = foo()
ret = pf.BAR
print(ret)
复制代码

 property的构造方法中有个四个参数

  • 第一个参数是方法名,调用 对象.属性 时自动触发执行方法
  • 第二个参数是方法名,调用 对象.属性 = XXX 时自动触发执行方法
  • 第三个参数是方法名,调用 del 对象.属性 时自动触发执行方法
  • 第四个参数是字符串,调用 对象.属性.__doc__ ,此参数是该属性的描述信息
复制代码
class Foo:

    def get_fun(self):
        return 123

    def set_fun(self,v):
        print('获取',v)

    def del_fun(self):
        print('del')

    per = property(fget=get_fun,fset=set_fun,fdel=del_fun,doc='adfasdfasdfasdf')

    # @property
    # def per(self):
    #     return 123

obj = Foo()
# ret = obj.per   #获取
# print(ret)    
obj.per = 123456     #修改
# del obj.per     #del删除
复制代码

 实例:

复制代码
class Goods(object):

    def __init__(self):
        # 原价
        self.original_price = 100
        # 折扣
        self.discount = 0.8

    def get_price(self):
        # 实际价格 = 原价 * 折扣
        new_price = self.original_price * self.discount
        return new_price

    def set_price(self, value):
        self.original_price = value

    def del_price(self, value):
        del self.original_price

    PRICE = property(get_price, set_price, del_price, '价格属性描述...')

obj = Goods()
obj.PRICE         # 获取商品价格
obj.PRICE = 200   # 修改商品原价
del obj.PRICE     # 删除商品原价
复制代码
View Code
复制代码

 

四、类成员修饰符

类成员的两种形式:

  • 公有成员,在任何地方都能访问
  • 私有成员,只有在类的内部才能方法

私有成员定义:私有成员命名时,前两个字符是下划线。(特殊成员除外,例如:__init__、__call__、__dict__等)

复制代码
# class foo:
#     def __init__(self,name,__age):
#         self.name = name  # name 公有字段
#         self.__age = __age   # __age  私有字段
#     def func(self):
#         print('name:%s'%self.name)
#         print('__age:%s'%self.__age)
#
# obj = foo('yang',18)
# obj.func()   # name:yang   __age:18
复制代码

静态字段

  • 公有静态字段:类可以访问;类内部可以访问;派生类(子类)中可以访问
  • 私有静态字段:仅类内部可以访问;
复制代码
# class foo1(foo):
#     def fun(self):
#         print('name:%s' % self.name)
#         # print('__age:%s'%self.__age)  #'foo1' object has no attribute '_foo1__age'
#
# obj = foo1('yang',90)
# #foo.__age
# obj.fun()


# class foo:
#     name = '公有静态字段'
#
#     def fun(self):
#         print(foo.name)
#
# class  foo1(foo):
#     def  dun(self):
#         print('name:%s'%foo.name)
#
# print(foo().name)
View Code
复制代码

普通字段

  • 公有普通字段:对象可以访问;类内部可以访问;派生类(子类)中可以访问
  • 私有普通字段:仅类内部可以访问;

ps:如果想要强制访问私有字段,可以通过 【对象._类名__私有字段明 】访问(如:obj._C__foo),不建议强制访问私有成员。

 

复制代码
# class foo:
#     __name = '私有静态字段'
#
#     def fun(self):
#         print(foo.__name)  # 类内调用私有字段
#
# class foo1(foo):
#     def dun(self):
#         print('name:%s' % foo.__name)  # 调用foo中的私有字段__name
#
# print(foo().fun())    # 私有静态字段
#
# obj = foo1()
# print(obj.dun())  # type object 'foo' has no attribute '_foo1__name'
View Code
复制代码

 

五、类的特殊成员方法

1、__doc__

复制代码
# __doc__ 表示类的注释信息
# class  foo:
#     """  这是foo的注释信息,用__doc__显示出来"""
#     def fun(self):
#         pass
#
# print(foo.__doc__)  #  这是foo的注释信息,用__doc__显示出来

# __module__表示当前操作对象在哪个模块
# from 模块.py import foo
# # obj = foo()
# # print(obj.__module__)  # 输出模块.py 打印初模块
# # print(obj.__class__)   # 输出 模块.py.foo  打印初类
__doc__输出注释信息
复制代码

2、__module__和__class__

复制代码
# __module__表示当前操作对象在哪个模块__class__输出对象调用的类
# from 模块.py import foo
# # obj = foo()
# # print(obj.__module__)  # 输出模块.py 打印初模块
# # print(obj.__class__)   # 输出 模块.py.foo  打印初类动执行foo中__init__方法
__module__表示当前操作对象在哪个模块__class__输出对象调用的类
复制代码

3、__init__构造方法

复制代码
# __init__ 构造方法   构造方法,通过类创建对象时,自动触发执行。
# class foo:
#     def __init__(self,name):
#         self.name = name
#
# obj = foo('yang')   #自动执行foo中__init__方法
__init__ 构造方法 构造方法,通过类创建对象时,自动触发执行。
复制代码

4、__call__

对象后面加括号,触发执行。

注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

复制代码
# __call__
# class foo:
#     def __init__(self,name):
#         self.name = name
#     def __call__(self, *args, **kwargs):
#         print('name:%s'%self.name)
#
# obj = foo('yang')
# obj()  # 对象后面加() 直接执行
# foo('yang')()  # 对象后面加() 直接执行
__csll__对象后面加() 直接执行
复制代码

5、__dict__

复制代码
# __dict__
# class foo:
#     def __init__(self,name,age):
#         self.name = name
#         self.age = age
#     def fun(self):
#         print('name:%s'%self.name)

# print(foo.__dict__)
# {'__module__': '__main__', '__init__': <function foo.__init__
# at 0x0000016F7C48BA60>, 'fun': <function foo.fun at 0x0000016F7C48B840>,
# '__dict__': <attribute '__dict__' of 'foo' objects>, '__weakref__': <attribute '_
# _weakref__' of 'foo' objects>, '__doc__': None}

# obj = foo('yang',22)
# print(obj.__dict__)  #{'name': 'yang', 'age': 22}
__dict__获取类或者对象中所有成员
复制代码

6、__str__

复制代码
# __str__ 函数调用时,会自动执行__str__并输出返回值
# class  foo:
#     def __str__(self):
#         return  '自动返回__str__'
#
# obj = foo()
# print(obj)  #自动返回__str__
__str__ 函数调用时,会自动执行__str__并输出返回值
复制代码

7、 __getitem__,__setitem__,__delitem__用于索引操作,如字典。分别表示,获取,设置,删除

复制代码
#  __getitem__,__setitem__,__delitem__用于索引操作,如字典。分别表示,获取,设置,删除
# class foo(object):
#     def __getitem__(self, value):
#         print('获取:',value)
#     def __setitem__(self, key, value):
#         print('设置:',key,value)
#     def __delitem__(self, key):
#         print('删除:',key)
#
# obj = foo()
# lis = [1,24,45,98]
# result = obj[lis[0]]   #获取: 1
# obj[lis[1]] = 200   #设置: 24 200
# del obj[lis[2]]  #删除: 45
__getitem__,__setitem__,__delitem__
复制代码

8、__getslice__,__setslice__,delslice__  分片操作

复制代码
# __getslice__,__setslice__,delslice__  分片操作

# class foo(object):
#     def __getslice__(self,i,j):
#         print('getslice:',i,j)
#     def __setslice__(self,i,j):
#         print('setslice:',i,j)
#     def __delslice__(self, i, j):
#         print('__delslice__', i, j)
# obj = foo()
# obj[-1:1]      # 自动触发执行 __getslice__
# obj[0:1] = [11, 22, 33, 44]   # 自动触发执行 __setslice__
# del obj[0:2]    # 自动触发执行 __delslice__
__getslice__,__setslice__,delslice__ 分片操作
复制代码

9、__del__析构方法

析构方法,当对象在内存中被释放时,自动触发执行。

注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

10. __iter__ 

用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了 __iter__ 

11. __new__ 和 __metaclass__

12.super

super在子类中调用父类方法时用

复制代码
class FooParent(object):
    def __init__(self):
        self.parent = 'I\'m the parent.'
        print('Parent')

    def bar(self, message):
        print(message, 'from Parent')

class FooChild(FooParent):
    def __init__(self):
        super(FooChild, self).__init__()  # 调用父类初始化方法
        print('Child')

    def bar(self, message):
        super(FooChild, self).bar(message)  # 调用父类bar方法
        print('Child bar fuction')
        print(self.parent)


if __name__ == '__main__':
    fooChild = FooChild()
    fooChild.bar('HelloWorld')
super的使用
复制代码

 

posted @   Delta.Farce  阅读(199)  评论(0编辑  收藏  举报
编辑推荐:
· [杂谈]如何选择:Session 还是 JWT?
· 硬盘空间消失之谜:Linux 服务器存储排查与优化全过程
· JavaScript是按顺序执行的吗?聊聊JavaScript中的变量提升
· [杂谈]后台日志该怎么打印
· Pascal 架构 GPU 在 vllm下的模型推理优化
阅读排行:
· WinForm 通用权限框架,简单实用支持二次开发
· 如何为在线客服系统的 Web Api 后台主程序添加 Bootstrap 启动页面
· 硬盘空间消失之谜:Linux 服务器存储排查与优化全过程
· 面试官:DNS解析都整不明白,敢说你懂网络?我:嘤嘤嘤!
· 双语对照的 PDF 翻译工具「GitHub 热点速览」
点击右上角即可分享
微信分享提示