继魔术方法及运算符重载(其实也就是特殊的魔术方法)之后,我又学(瞎)习(碰)到了一些有意思的特殊方法名。这里也对Python类的特殊方法做一个小总结。
受保护的方法
形如_attr
的方法名,以单个下划线开头。其在Python中被视为受保护的方法,原则上它不应该被外部调用,IDE也会对外部调用的行为予以警告。然而,与类型注解类似,它只是一种提示,而非强制。
例如:
class Test():
def _protected(self):
print("Protected method")
test = Test()
test._protected() # Protected method
评价为君子协定
私有方法
形如__attr
的方法名,以两个下划线开头,是一种仅允许内部调用的私有方法。
例如:
class Test():
def __private(self):
print("Private method")
test = Test()
test.__private() # AttributeError
内部调用是允许的
class Test():
def __init__(self):
self.__private()
def __private(self):
print("Private method")
test = Test()
事实上,这也是个君子协定。Python对这类方法的处理是对方法名进行重写,可以通过重写__getattribute__
魔术方法进行验证:
class Test():
def __init__(self):
self.__private() # 内部访问
def __private(self):
print("Private method")
def __getattribute__(self, item):
print(f"Get attribute: {item}") # print大法进行调试,item是实际传递给class的方法名
if item.startswith('_'):
return super().__getattribute__(item)
return self.__get(item)
test = Test() # Get attribute: _Test__private
我们可以看到,这个方法在内部访问时被重写为了_Test__private
。
于是我们其实也可以在外部直接访问该private方法:
class Test():
def __private(self):
print("Private method")
test = Test()
test._Test__private() # Private method
评价为私有了,但没完全私有。
一些装饰器
虽然不属于方法名导致的特殊行为,但也算是特殊的类方法
静态方法
最常见的特殊方法,如果这个方法没有使用或修改self的其他方法,那么可以使用@staticmethod
装饰器装饰该方法,该方法不再接受首个默认参数self,并可以在未实例化的Class对象直接调用,
例如
class MathUtils:
@staticmethod
def add(a, b):
return a + b
# 没有实例化,直接调用静态方法
result = MathUtils.add(3, 5)
print(result) # 8
评价为好像有用又好像没用(除了能跳过实例化的步骤直接调用外,对于逻辑的实现并没有任何改变)
抽象方法
它存在的意义就是让这个class不能实例化作为基类存在,强制要求创建子类后再进行实例化。
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def make_sound(self):
pass
class Cat(Animal):
def make_sound(self):
return "Nya~"
# animal = Animal() # TypeError
cat = Cat()
print(cat.make_sound()) # Nya~
一般用来定义模板基类,用于给其他类继承。@abstractmethod
装饰的类方法通常没有具体行为,需要子类重写;然而也可以为其定义一些行为,作为该方法的默认行为。
评价为法如其名,非常抽象的方法。
属性方法
使用@property
装饰器定义。属性方法允许将方法作为属性访问,一般用于封装类的属性访问逻辑。然后你可以使用@property.setter
和@property.deleter
定义属性的设置和删除行为。
“Talk is cheap. Show me the code.”
class MyClass:
def __init__(self, value):
self._value = value
@property
def value(self):
return self._value
@value.setter
def value(self, new_value):
if new_value < 0:
raise ValueError("Value cannot be negative")
self._value = new_value
obj = MyClass(10)
print(obj.value) # 10
obj.value = 20
print(obj.value) # 20
# obj.value = -1 # 违反了检查器的规则,将会抛出 ValueError
评价为基本没用过的玩意儿(当然可能是暂时没有这方面的需求)