"""
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(四声)。
感觉之前敲的代码都只是为了解决某个问题,根本没有考虑到一件事:如果变变参数这程序还能用吗?
之后,我便把程序的可用性和扩展性放在了第一位,而不再只觉得只要程序跑的快就完事了
"""
谈谈Python中的《面向对象》
最新推荐文章于 2024-07-27 12:20:46 发布