本文汇总一些python常见的内置函数以及python类的内置函数
1.breakpoint()
该函数可以在不适用IDE的情况下debug python代码,十分方便在服务器上调试代码(但是需要python 3.7+)
x = 1
print(x)
breakpoint()
x = 2
print(x)
上述代码在运行到breakpoint()时会进入pdb模式(python debug的缩写),可以支持查看/修改变量的值。
当运行到breakpoint()时程序会停止:
1
> /Users/sniper/PycharmProjects/MyE2E/test.py(27)<module>()
-> x = 2
(Pdb)
进入pdb模式,在这里我们可以输入变量名查看变量的值,或者输入表达式:
1
> /Users/sniper/PycharmProjects/MyE2E/test.py(27)<module>()
-> x = 2
(Pdb) x
1
(Pdb) x=3
(Pdb) x
3
(Pdb)
按c执行到下一个断点,按n执行下一步。
1
> /Users/sniper/PycharmProjects/MyE2E/test.py(27)<module>()
-> x = 2
(Pdb) x
1
(Pdb) x=3
(Pdb) x
3
(Pdb) c
2
2.dir()
查看属性、方法列表等。
class fun():
def __init__(self):
self.x = 1
def test(self):
pass
print(dir())
print(dir(fun))
print(dir(fun()))
当dir携带参数时,输出的是当前调用路径可以访问的变量、方法。而当参数为一个尚未实例化的类时,可以看到方法,而传入实例化后的类时,可以看到方法和属性。(只有最后一个有‘x’)
['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'fun']
['__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__', 'test']
['__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__', 'test', 'x']
3.__init__
类的初始化方法,主要是初始化类中的一些参数。
class A(): print('a') def __init__(self): print('init') a = A() # output: # a # init
但是它的调用顺序晚于类中声明的变量。
4.__new__
python类分配空间的方法。当创建对象时,python会首先调用__new__来为对象分配空间。
class A():
print('a')
def __init__(self):
print('init')
@staticmethod
def __new__(cls, *args, **kwargs):
print('new')
return super().__new__(cls)
def fun(self):
print('fun')
a = A()
# output:
# a
# new
# init
当解析器调用__new__时,__new__负责在内存中为该对象分配空间,同时返回对象的引用(self),随后将self传给__init__ 。 重写__new__的方法十分固定,就是 $ return\ super().\_\_new\_\_(cls) $。由于该方法负责申请内存空间,因此在该方法中可以很方便的实现单例模式。
class A():
A = None
def __init__(self):
print('init')
@staticmethod
def __new__(cls, *args, **kwargs):
print('new')
if cls.A is None:
cls.A = super().__new__(cls)
return A
else:
return A
def fun(self):
print('fun')
a = A()
print(id(a)) # 4402021120
b = A()
print(id(b)) # 4402021120
虽然创建了很多”实例“,但是他们的地址都是同一个。
5.super()
一个用来调用父类的一个方法
class A():
def __init__(self):
print('A')
class B(A):
def __init__(self):
print('B')
super(B, self).__init__()
A.__init__(B)
B()
# output:
# B
# A
# A
可以看到,使用super()调用了父类的__init__函数,当然也可以显式的进行调用,这里结果是一样的,但是有一点点不一样,在稍后会提到。
6.__mro__
该方法的值是一个元组,它会按照方法解析顺序存放各个超类的名称。
在一些复杂的继承场景时,我们可能没办法立刻判断这些父类的初始化逻辑
class A():
def __init__(self):
print('A')
class B(A):
def __init__(self):
print('B')
super(B, self).__init__()
class C(A):
def __init__(self):
print('C')
super(C, self).__init__()
class D(B, C):
def __init__(self):
print('D')
super(D, self).__init__()
print(D.__mro__)
D()
# output:
# (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
# D
# B
# C
# A
而通过__mro__我们就可以看出父类的初始化逻辑,与实际的调用顺序一致。
同时还可以发现,__mro__的输出并不重复(B和C的父类都是A,但是却只出现了一次),因此也就避免了重复初始化的问题。而super()也正是沿着__mro__进行初始化的,因此相比显式的直接调用__init__,使用super()调用__init__则没有重复调用的问题。
7.__str__
类似于java的toString(),可以显示的指定当前类的打印结果。
class A():
def fun(self):
pass
def __str__(self):
return 'is class A'
print(A) # <class '__main__.A'>
print(A()) # is class A
8.__call__
允许对象的实例直接调用的方法。如下,可以用过实例名()调用。当然也可以通过.调用其他方法。
class A():
def __call__(self, *args, **kwargs):
print(kwargs)
def fun(self):
print('fun')
a = A()
a(a=1, b=2) # {'a': 1, 'b': 2}
a.fun() # fun
9.@property
@property是python的一种装饰器,用来修饰方法的。
我们使用@property装饰器来创建只读属性,它会将方法转换为同名的只读属性,这样可以防止属性被篡改。
class A(): def __init__(self): self._name = 'A' @property def fun(self): return 'fun in ' + str(self._name) a = A() print(A().fun) # fun in A print(a._name) # A a._name = 'B' print(a._name) # B
使用@property修饰后的方法,可以当做属性一样调用(也只能当做属性调用),同时由于可以隐藏属性名,因此也可以防止属性被篡改(当然了,python并没有真实的私有变量,依然可以通过实例.name进行调用与修改)。
10.@方法名.setter
@property解释器提供了隐藏属性的方法,那如何更改这些属性呢?既然尽量隐藏某些属性名,总不能通过实例名.name进行更改吧,可以通过方法名.setter的方式进行更改,同时由于定义的是方法,还可以对数据进行检查。
class A():
def __init__(self):
self._name = 'A'
@property
def name(self):
return self._name
@name.setter
def name(self, name):
if len(name) <= 1:
raise Exception('name must be at least 1')
self._name = name
a = A()
print(a.name) # A
a.name = 'BB'
print(a.name) # BB
a.name = 'B'
print(a.name) # Exception: name must be at least 1
需要注意的是,这两个方法名必须一致,重载关系。
11.@方法名
@方法名 可以让被注释的方法拥有额外的功能,或者说改变这个函数的执行结果。
def login_check(func):
def wrapper(self, username, password):
if username == password == 'root':
return func(self, username, password)
raise Exception('wrong password')
return wrapper
class A():
def __init__(self):
self._name = 'A'
@login_check
def login(self, username, password):
print('login success')
a = A()
a.login(username='root', password='root')
上面这段代码就执行了登录前的用户名密码检查,通过装饰器,可以快速直观的切换不同的登录检查方式等。
后续再有再回来补充。
0 条评论