生活中总会出现这样一种特征,一类事物共有的共同的特征,Python语法中提供了类型属性(简称类属性)描述表现这样的特征。
定义给类型的属性,直接描述一类事物的特征,而不是具体某个对象的特征。
类属性,声明在类型的内部,方法的外部。
class Person:
"""人的类型"""
# 类属性
max_age = 150
def __init__(self, name, age):
self.name = name
self.age = age
类属性描述了一类事物的特征,所以可以被这个类型创建的所有对象去访问(不能修改)
class Person:
max_age = 150
def __init__(self, name, age):
self.name = name
self.age = age
# 类属性的访问
# 1. 通过 类名.类属性 访问
>>> print(Person.max_age)
150
# 2. 通过 对象.类属性 访问
>>> man = Person("tom", 35)
>>> man.max_age
150
# 类属性的修改
# 通过 类名.类属性 修改
>>> Person.max_age = 130
>>> print(Person.max_age)
130
类属性的出现,主要是用来描述一类事物共同的特征,如果在项目开发中,出现了类似的特征,要求所有对象都能遵循满足同一个特征数据,考虑适用类属性声明这个特征!
class 类型名称:
...
@classmethed
def 类方法名称(cls, [形参]):
pass
@classmethed
装饰器声明,表示这是一个类方法cls
表示的是当前类cls
直接访问和修改类方法和类属性一样,推荐直接通过 类名.方法名调用执行
类方法属于一类事物的共同行为,所以通过对象也可以调用
项目中的某个类型出现了一种行为,和具体的对象无关,此时这样的行为方法,就可以被声明为类方法。
类属性的封装,属性的 set/get 方法必须通过类方法来实现
class 类名:
...
@staticmethod
def get_current_time():
return datatime.now()
项目开发过程中,出现了一些功能性的方法,如获取当前系统时间,如此简单之行为,抽取对象声明类型,反倒有过度设计的嫌疑!
注意:面向对象的开发中,不要为了面向对象去专门强行设计类型,很容易造成过度设计!
1. 声明函数实现
面向对象的项目中,如果出现了一些实现独立的小功能行为,可以将这样的功能声明成函数在项目中调用执行(面向过程 面向对象 混合开发)
2. 静态方法实现
类似获取时间这样的功能性函数,如果抽取对象声明类型比较繁琐,Python语法中针对这样的函数提供了一个特殊的方法:静态方法。包含在任意一个类型中,通过类型统一管理,可以通过类型名称直接调用,但是静态方法不能访问实例属性,也不能访问类型属性,只起到了函数的作用!
@staticmethod
声明实例方法 | 类方法 | 静态方法 | |
---|---|---|---|
访问实例属性 | Y | N | N |
访问类属性 | Y | Y | N |
魔法方法如同它的名字一样神奇,是指哪些Python内部已经包含的,被双下划线所包围的方法,这些方法在进行特定的操作时会被自动调用。
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
"""当对象被打印时调用"""
return f"name is {self.name}, age is {self.age}"
tom = Person("tom", 18)
print(tom)
# name is tom, age is 18
魔法方法名 | 描述 |
---|---|
new(cls) | 构造方法 |
init(self) | 初始化方法 |
call(self[,…]) | 允许一个对象像函数一样被调用:x(a,b) 调用x.__call__(a,b) |
len(self) | 定义当被len() 调用时的行为 |
repr(self) | 定义当被repr() 调用时的行为 |
str(self) | 定义当被str() 调用时的行为 |
hash(self) | 定义当被hash() 调用时的行为 |
魔法方法名 | 描述 |
---|---|
getattr(self,name) | 定义一个当用户试图获取一个不存在的属性时的行为 |
getattribute(self, name) | 定义当该类的属性被访问时的行为 |
setattr(self, name, value) | 定义当一个属性被设置时的行为 |
delattr(self, name) | 定义当一个属性被删除时的行为 |
dir(self) | 定义当 dir() 被调用时的行为 |
魔法方法名 | 描述 |
---|---|
lt(self, other) | 定义小于号的行为:x < y 调用 x.__lt__(y) |
eq(self, other) | 定义等于号的行为:x == y 调用 x.__eq__(y) |
ne(self, other) | 定义不等号的行为:x != y 调用 x.__ne__(y) |
gt(self, other) | 定义大于号的行为:x > y 调用 x.__gt__(y) |
魔法方法名 | 描述 |
---|---|
add(self, other) | 定义加法的行为:+ |
sub(self, other) | 定义减法的行为:- |
mul(self, other) | 定义乘法的行为:* |
truediv(self, other) | 定义真除法的行为:/ |
魔法方法名 | 描述 |
---|---|
iadd(self, other) | 定义赋值加法的行为:+= |
isub(self, other) | 定义赋值减法的行为:-= |
imul(self, other) | 定义赋值乘法的行为:*= |
itruediv(self, other) | 定义赋值真除法的行为:/= |
魔法方法名 | 描述 |
---|---|
int(self) | 让当前对象支持 int() 类型转换操作 |
float(self) | 让当前对象支持 float() 类型转换操作 |
bool(self) | 让当前对象支持 bool() 类型转换操作 |
str(self) | 让当前对象支持 str() 类型转换操作 |
… more and more
反射方法,就是不通过方法名称调用方法,而是通过一个字符串反向解析得到方法对象执行方法的过程。
# 常规
Object.study() # 执行了 study() 方法
# 反射
method = getattr(Object, "study")
method()
魔法方法名 | 描述 |
---|---|
hasattr(obj, attr) | 判断目标对象中是否包含指定的属性或者方法 |
getattr(obj, attr) | 从目标对象中获取执行名称的属性或者方法 |
setattr(obj, attr, value) | 获取并执行目标对象中的属性或者方法 |
delattr(obj, attr) | 从目标对象中删除对应的属性或者方法 |