「python中一切皆对象」
类与对象
self参数
self参数用于对当前类中实例的引用,必须作为该类中任何函数的第一个参数,但可以不必命名为 self
class A:
def add(self, x, y):
self.x = x 1
self.y = y 1
class B:
def add(abc, x, y):
abc.x = x 1
abc.y = y 1
__new__ 与 __init__ 关系
- https://xxhs-blog.readthedocs.io/zh_CN/latest/how_to_be_a_rich_man.html
- https://www.cnblogs.com/wdliu/p/6757511.html
- https://blog.csdn.net/fjswcjswzy/article/details/105637086
在使用类名创建对象时,Python 解释器会首先调用 __new__
方法为对象分配空间,并返回对象的引用,Python 解释器在获得对象的引用后,将引用作为第一个参数,传递给 __init__
__new__
通常用于控制生成一个类实例的过程,它是类级别的方法__init__
通常用于初始化一个新实例,控制这个初始化的过程,比如添加一些属性, 做一些额外的操作,发生在类实例被创建完以后,它是实例级别的方法
继承关系
子类继承于父类,子类拥有其自身及父类的方法和属性,同名的子类方法和属性将会覆盖父类的方法和属性
代码语言:javascript复制class Parent:
def a(self):
self.title = "In parent"
print(self.title)
class Son(Parent):
def b(self):
print(self.title)
c = Son()
c.a()
# In parent
c.b()
# In parent
c.title
# In parent
可以通过 __bases__
方法查看一个类的(所有)父类
Son.__bases__
# (<class '__main__.Parent'>,)
实例化关系
实例化关系是一个从抽象到具体的关系,实例是类的具体表现形式
代码语言:javascript复制class A:
pass
a = A() # a 就是类 A 的实例化对象
如果想要查看一个对象是由哪个类实例化而来,可以通过 type()
命令或者 __class__
方法查看
type(a)
# <class '__main__.A'>
a.__class__
# <class '__main__.A'>
type、object、class 之间关系
- https://zhuanlan.zhihu.com/p/100885824
- object 类是所有类(class)的父类,包括 type 类,object 类的父类为空
- type 类是所有类的类型,即所有类都由 type 类的实例化而来,包括 type 类本身
下图中红色箭头指向其父类,蓝色箭头指向其类型(由哪个类实例化而来)
代码语言:javascript复制class A:
pass
a = A()
A.__bases__ # (<class 'object'>,)
object.__bases__ # ()
type.__bases__ # (<class 'object'>,)
type(a) # <class '__main__.A'>
type(A) # <class 'type'>
type(type) # <class 'type'>
type(object) # <class 'type'>
类属性与方法
- https://www.runoob.com/python/python-object.html
- https://www.cnblogs.com/chenhuabin/p/10055316.html
私有属性
以两个下划线开头,声明为私有属性,则类外部无法对其进行调用
代码语言:javascript复制class A:
__secret = 0
def B(self):
self.__secret = 1
a = A()
a.__secret
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute '__secret'
虽然无法直接调用私有属性数据,但是可以通过 object._className__attrName
(对象名._类名__私有属性名)进行访问
class A:
__secret = 123
a = A()
a._A__secret
# 123
私有方法
同样是以两个下划线开头,声明为私有方法,类外部无法对其进行调用
代码语言:javascript复制class A:
secret = 0
def __B(self):
self.secret = 1
print(self.secret)
a = A()
a.B()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'B'
静态方法
在定义时,使用 @staticmethod
装饰器来进行修饰,无须传入 self 等参数即可创建方法。在调用过程中,无需将类实例化,可以直接通过 类名.方法名 进行调用,也可以在实例化后通过 实例名.方法名 进行调用,在静态方法内部,只能通过 类名.类变量名 方式访问变量
class A:
a = 1
@staticmethod
def add():
print(A.a 1)
aa = A()
aa.a
# 1
aa.add()
# 2
A.a
# 1
类方法
在定义时,使用 @classmethod
装饰器进行修饰,同时需要指定传入第一个参数为 cls
(命名可以自定义),在调用过程中,可以直接通过 类名.方法名 进行调用,也可以在实例化后通过 实例名.方法名 进行调用,在方法内部,可以通过 类名.类变量名 方式访问变量,也可以通过 cls.类变量名 方式访问
class A:
a = 1
@classmethod
def add(cls):
print(A.a 1)
print(cls.a 2)
aa = A()
aa.a
# 1
aa.add()
# 2
# 3
A.a
# 1
实例方法
实例方法不需要修饰器进行修饰,但是要求指定传入第一个参数为 self
(命名可以自定义)。实例方法可以访问实例变量,类方法与静态方法则不能。实例方法内部只能通过 类名.类变量名 方式访问变量,在调用时可以通过 实例名.实例方法名 方式调用,如果想要通过 类名.实例方法名 方式调用,必须显式传入实例名
class A:
a = 1
def __init__(self, name, age):
self.name = name
self.age = age
def test(self):
print(A.a)
print(self.name, self.age) # 访问实例变量
aa = A("abc", 18)
aa.test()
# 1
# abc 18
A.test(aa) # 显式传入实例名作为参数
# 1
# abc 18
函数与魔法方法
super()
用来调用父类(超类)的方法,若父类和超类中有同名方法,优先调用父类
Python2 用法:super(父类/超类名, self).函数名
Python3 用法:super().函数名
父类、子类、超类的关系:
- Son直接继承Parent,二者之间叫做子类和父类
- Parent直接继承Grandparent,二者之间叫做子类和父类
- Son间接继承Grandparent,Grandparent是Son的超类
class Grandparent:
def xor(self, x, y):
res = x ^ y
print(res)
print("In Grandparent")
class Parent(Grandparent):
def add(self, x, y):
sum = x y
print(sum)
print("In Parent")
class Son(Parent):
def add(self, x, y):
super().add(x, y)
def xor(self, x, y):
super().xor(x, y)
a = Son()
a.add(1, 2)
# 3
# In Parent
a.xor(3, 3)
# 0
# In Grandparent
dir() 与 __dict__
- https://cloud.tencent.com/developer/article/1581164
- http://c.biancheng.net/view/2374.html
dir() 函数返回一个列表,列表的内容是该对象的所有属性,包括从父类继承的属性
代码语言:javascript复制class A:
name = 'abc'
def aa(self):
pass
class B(A):
def bb(self):
print(self.name)
dir(A)
# ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'aa', 'name']
dir(B)
# ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'aa', 'bb', 'name']
_dict_ 返回一个字典,字典内容是当前对象的属性(不包括父类),属性名作为键,属性值作为键对应的值
代码语言:javascript复制A.__dict__
# mappingproxy({'__module__': '__main__', 'name': 'abc', 'aa': <function A.aa at 0x7f2aed150a60>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None})
B.__dict__
# mappingproxy({'__module__': '__main__', 'bb': <function B.bb at 0x7f2aed150af0>, '__doc__': None})
实例的 __dict__ 属性只包含当前实例的实例属性,并不是所有有效属性,
代码语言:javascript复制class A:
def __init__(self):
self.name = 'abc'
self.age = 18
class B(A):
def __init__(self):
self.name = 'def'
self.age = 20
a = A()
b = B()
a.__dict__
# {'name': 'abc', 'age': 18}
b.__dict__
# {'name': 'def', 'age': 20}
从这两个方法的对比,我们也可以看出来,__dict__
得到的内容只是 dir()
的子集,dir()
中包含 __dict__
中的属性
__getattr__ 与 __getattribute__
- https://www.cnblogs.com/huchong/p/9306459.html
- https://juejin.cn/events/all
二者都是访问属性的方法,不同的是所有通过实例访问属性都会触发 __getattribute__
方法,而当访问的属性不存在时,会继续触发 __getattr__
,也就是说 __getattribute__
一定会在 __getattr__
之前触发,当 __getattribute__
有返回值时就不会再触发 __getattr__
__getattr__(self, name)
- self:函数中固定第一个参数
- name:参数名
- 该方法可以自定义返回值,若不定义,则在方法执行结束后触发 AttributeError
__getattribute__(self, name)
- self:函数中固定第一个参数
- name:参数名
class A:
test = 123
def __getattr__(self, name):
print("__getattr__ is called")
return name " not found"
def __getattribute__(self, name):
print("__getattribute__ is called")
return object.__getattribute__(self, name)
a = A()
a.test
# __getattribute__ is called
# 123
a.test2
# __getattribute__ is called
# __getattr__ is called
# 'test2 not found'
getattr(object, name[ ,default])
- object:对象
- name:参数名
- dufault:默认返回值,如果不提供该参数,在没有对应属性时,将触发 AttributeError
object.__getattribute__(name)
- object:对象
- name:参数名
class A:
test = 1
a = A()
getattr(a, 'test')
# 1
a.__getattribute__('test')
# 1
getattr(a, 'test2')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'test2'
这两个方法也可以用来命令执行
getattr(__import__('os'), 'system')('ls')
__import__('os').__getattribute__('system')('ls')
type() 与 __class__
两种方法都可以用来查看该实例是由哪个类实例化而来,也可以称为其所属类型
代码语言:javascript复制class A:
pass
a = A() # a 就是类 A 的实例化对象
type(a)
# <class '__main__.A'>
a.__class__
# <class '__main__.A'>
().__class__
# <class 'tuple'>
[].__class__
# <class 'list'>
type(1)
# <class 'int'>
__base__ 与 __bases__
__base__
可用于查看一个类的一个父类,符合菱形继承机制
class A:
pass
class B:
pass
class C(B, A):
pass
C.__base__
# <class '__main__.B'>
__bases__
可用于查看一个类的全部父类, 但只能向上寻找一层
class A:
pass
class B(A):
pass
class C(B, A):
pass
C.__bases__
# (<class '__main__.B'>, <class '__main__.A'>)
__mro__
有关具体继承机制可参考:
- https://hanjianwei.com/2013/07/25/python-mro/
简单来讲就是菱形继承机制,左侧优先,重复类保留最后一个
该方法用于查看类的调用顺序(继承关系)
代码语言:javascript复制class A:
pass
class B(A):
pass
class C(B, A):
pass
C.__mro__
# (<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
__subclasses__()
获取一个类的所有子类,返回一个由所有子类构成的列表
这个方法只适用于新式类,新式类继承自 object,Python3版本中只支持新式类,Python2版本中可能不支持
代码语言:javascript复制class A:
pass
class B(A):
pass
class C(B, A):
pass
A.__subclasses__()
# [<class '__main__.B'>, <class '__main__.C'>]
type 类也具有此方法,但不同的是,type 类作为所有类别的实例化来源,它的 __subclasses__()
方法需要一个类别作为参数,而其他类则不需要
A.__mro__[-1].__class__
# <class 'type'>
A.__mro__[-1].__class__.__subclasses__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: descriptor '__subclasses__' of 'type' object needs an argument
A.__mro__[-1].__class__.__subclasses__(A.__mro__[-1]) # 以 object 类作为参数为例
[<class 'type'>, <class 'weakref'>, <class 'weakcallableproxy'>, <class 'weakproxy'>, <class 'int'>, <class 'bytearray'>, <class 'bytes'>, <class 'list'>, <class 'NoneType'>, <class 'NotImplementedType'>, <class 'traceback'>, <class 'super'>, <class 'range'>, <class 'dict'>, <class 'dict_keys'>, <class 'dict_values'>, <class 'dict_items'>, <class 'dict_reversekeyiterator'>, <class 'dict_reversevalueiterator'>, <class 'dict_reverseitemiterator'>, <class 'odict_iterator'>, <class 'set'>, <class 'str'>, <class 'slice'>, <class 'staticmethod'>,......]
__globals__ 与 func_globals
__globals__
可用于python2/3,以字典的形式返回函数所在的全局命名空间所定义的全局变量,即找到该函数所有能够调用内容
class A:
def test(self):
pass
A.test.__globals__
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'A': <class '__main__.A'>}
func_globals
只用于python2,用途与 __globals__
相同
A.test.func_globals
{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', 'A': <class __main__.A at 0x0000000003101768>, '__doc__': None, '__package__': None}
内建模块
在 python 中有许多不需要引用就能直接使用的函数,例如 open
、str
、chr
等等,这些函数都包含在内建模块中,在 python2/3 中对于内建模块,有不同的表示方法
- python2
在 python2 中,内建模块用 __builtin__
表示,需要先引入才能查看
import __builtin__
__builtin__
<module '__builtin__' (built-in)>
可以用 dir()
或者 __dict__
方法来查看其中包含的各种函数
dir(__builtin__)
__builtin__.__dict__
调用方法也很简单
代码语言:javascript复制__builtin__.str(1)
- python3
在 python3 中,内建模块用 builtins
表示,同样也要先引入才能查看,各种查看方法与调用方法与 python2 相同,不再赘述
- 通用
在 python2/3 中,都有一个 __builtins__
,它是 __builtin__
和 builtins
的引用,它的好处是直接就可以使用,不需要事先 import
dir(__builtins__)
__builtins__.str(1)
__getitem__
处理对象为序列,可以通过下标或键值方式返回序列中的值
代码语言:javascript复制# 字符串
'abc'.__getitem__(0)
'a'
# 元组
(1, 2).__getitem__(0)
# 列表
[1, 2, 3].__getitem__(0)
1
# 字典
{'1':'a', '2':'b'}.__getitem__('1')
'a'
*未完待续...
可能也许大概应该好像似乎不一定会持续更新(