谈谈Python中的《面向对象》

"""
Python支持面向对象,但我个人还是将其作为一门脚本语言使用,充分
发挥其特性。Python中的面向对象操作手感和其他编译型语言(如C++, Java)
差别还是较大的,我总结整理了一部分使用心得,供各位参考
"""
import json
import sys
from threading import Thread


class Test:

    """
    直接声明在类中的变量为"类变量",可以直接通过类名调用
    注意,刚初始化的对象中的类变量xx统一指向类中的xx
    例如:t0, t1 = Test(),Test()
    此时有条件表达式 id(t0.a) == id(t1.a) and id(t0.a) == id(Test.a) 值为True
    且通过Test.a = xx 的方式来修改此变量是直接修改内存中的值,会影响所有对象
    但通过对象修改则只是变更了对象中该变量的指针指向
    这在设计上是合理的: 类变量不应该全部是静态的。
    Python摒弃了很多修饰符,如private, public, static等,所以语法上相对自由,但这不应该
    成为开发者滥用其特性的理由。

    :type 这只是声明此变量的逻辑类型,像强类型语言中声明一个变量要先声明数据类型那样
    例如Java中 String s = "", 这时变量s的值就只能为字符串
    但Python中并不会在语法层面强制限制变量只能接受与声明类型相符(即同
    一类型或是其子类)的数据
    """
    a: int = 50
    b: list = [x for x in range(a)]
    c: str = str(b[10])

    """
    在变量前以下划线开头, 等同于private修饰符,即它是一个私有变量
    不能在类的外部使用,但这也只是逻辑层面的私有化, 需要开发者自觉遵守
    具体的体现也就是在编辑器其中不会出现待选提示
    值得一提的是,Python中所有的标识符均不能出现 $ (可能因为作者是荷兰人吧)
    """
    _a = 20

    """
    开头两条下划线的变量也是私有变量,在类外部不可以直接
    通过Test.__a的方式调用,因为类中所有成员都以 name: value的方式存放在一个
    属性字典中,这个字典的名称为 __dict__ 在object类中声明,可以直接通过名称调用,
    也可以通过内置函数vars(Test)的方式获取。解释器在将其放入字典时会做一些加工
    即加一个前缀: _类名。所以此变量在类外部直接调用的格式为:Test._Test__a
    """
    __a = 30

    """
    类的初始化方法
    其中参数列表中的self代表对象本身,所有非类方法或静态方法都应该显示声明它
    可以自定义参数列表。
    很可惜,Python并不支持方法重载。我们不能定义多个初始化方法,
    好在参数列表设计的足够灵活。
    有意思的是, 当重写此方法后,类变量只能在类内部通过self对象调用
    在类外部通过对象调用会出现异常
    例如:t = Test(); print(t.a) => AttributeError: 'NoneType' object has no attribute 'a'
    这是因为Python是动态语言,它可以在运行时创建实例变量,而通过对象调用某个成员时会首先从实例成员字典
    中以名称为键来索引值,若无果则会直接抛出异常而不是转头再去类成员字典查找
    """
    def __init__(self, id_: int = 0, name: str = ''):
        # 通过self.xx创建的变量称为“实例变量”
        # 只能通过实例化后产生的对象来调用它
        self.id = id_
        self.name = name

    """
    构造方法,在__init__方法执行前,__new__会负责构造一个对象
    以供__init__使用
    其中cls是当前正在实例化的类
    """
    def __new__(cls, *args, **kwargs):
        print("Test: I'm going to start")
        # 可以在此处直接返回一个其他对象来当做实例化后返回的结果
        # 但这种就属于滥用行为,如果没有什么特殊需要,不要这么做
        # return 111

        # 正常情况下,会通过super()来构建一个父类对象当做返回结果
        # 在此处,__new__方法只需传递需要实例化的类即可
        # 注意不要调用本类的__new__方法或者试图return Test()
        # 这样是无限递归,当栈满时会抛出递归错误
        # RecursionError: maximum recursion depth exceeded
        return super().__new__(cls)

    """
    析构函数,当对象被回收时,解释器调用的方法
    """
    def __del__(self):
        # 如果实例变量中有closable对象
        # 可在此处关闭
        pass

    """
    字符序列化方法(类似于Java中toString方法)
    当对象需要以字符串的格式出现时只需要通过str(对象)获取即可
    但__str__默认的实现是返回此对象的所在类类名和地址值
    所以,可以重写此方法来让其可以适用与各种开发场景
    注意,此方法的返回值只能是一个字符串 str
    """
    def __str__(self):
        # 实例1:作为响应给浏览器的结果
        # return json.dumps(vars(self))

        # 实例2: 以字典格式出现
        return str(vars(self))

    """
    与__str__功能类似,但__repr__是作为此对象在一个容器中(列表,元组等)转为
    字符串时调用的方法
    """
    def __repr__(self):
        # 最常用的还是直接调用__str__
        return self.__str__()

    # 或者直接将其指向__str__
    __repr__ = __str__

    """
    类方法,需要添加装饰器@classmethod
    """
    @classmethod
    def get_dict(cls):
        return vars(cls)


    """
    Python保留了重载运算符的操作
    这也是被很多人诟病的,使用得当,会让程序更简洁,可读性更高
    使用不当会导致程序一团糟,在程序中不要为了在代码层面省事
    而重载不必要的运算符。还好Python对其做了一些限制,让它的灵活性,安全性等方面
    更加均衡
    
    有些事情让我不安,比如运算符重载。我决定不支持运算符重载,
    这完全是个人选择,因为我见过太多 C++ 程序员滥用它。
    
                           ——詹姆斯 高斯林


    由于我在程序中很少使用重载运算符,所以在此处不做过多介绍
    所以在最后只发表一些个人经验吧
    Python我更多的还是当做一门脚本语言去用,就像JavaScript(JS)那样,在JS中创建的对象
    就像Python中的字典结构(dict)。真正去用class的时候不多,只是简单的封装一组常量参数而已
    谈不上面向对象。更像是面向模块编程。但还是鼓励大家多去面向对象编程。这比起编程更像是
    一种设计,如何把现实事物抽象化,模型化。在程序中又该怎么去用这些模型,怎么去处理他们之间
    的关系,怎么找到公共的属性并把他们抽取出来作为向后的扩展,封装层次怎样控制才能
    让API使用手感最佳,留给上层的接口怎样设计才能有高通用性
    这些东西不是可不是算法题刷的多就能掌握的。这更像是一种哲学,站在高处控制全局那种感觉...
    第一次用Java中Spring框架时真的被震撼到了,设计框架的都是些什么神仙。
    但其中的功能代码还不算太难理解,自己也能做出模拟,但将每个功能怼在一块,呵,玩个dan(四声)。
    感觉之前敲的代码都只是为了解决某个问题,根本没有考虑到一件事:如果变变参数这程序还能用吗?
    之后,我便把程序的可用性和扩展性放在了第一位,而不再只觉得只要程序跑的快就完事了
    """


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值