Python 面向对象编程技术(四)
??属性是对现实世界中实体特征的抽象,提供了对类或对象性质的访问。举一个例子,长方形是一个对象,则长和宽就是长方形的两个属性。
注意:属性反映了面向对象的编程思想,即不能直接操作类的字段。属性隔离了字段,而且能对要赋值的字段进行监测,合乎要求的才会被允许。属性是这样的成员:它提供了灵活的机制来读取、编写或计算某个私有字段的值。可以像使用公共数据成员一样使用属性,但实际上它们是称作“访问器”的特殊方法。这使得可以轻松访问数据,此外还有助于提高方法的安全性和灵活性。
一、认识属性
??在Python程序中,属性是对类进行建模必不可少的内容,上一篇文章介绍的方法是用来操作数据的,而和操作相关的大部分内容都和下面将要讲解的属性有关。我们既可以在构造方法中定义属性,也可以在类中的其他方法中使用定义的属性。在本篇文章之前的内容中,已经多次用到了属性,例如在上一篇的实例中, “name”和“age”都是属性,具体实现代码如下所示:
class Dog:
"小狗的类"
def __init__(self,name,age):
"初始化属性name和agw"
self.name = name
self.age = age
def wang(self):
"模拟狗狗汪汪叫"
print(self.name.title() + "汪汪")
def shen(self):
"模拟狗狗伸舌头"
print(self.name.title() + "伸舌头")
my_dog = Dog("大狗",6)
your_dog = Dog("小狗",3)
print("霍老二爱犬的名字是" + my_dog.name.title() + ".")
print("霍老二的爱犬已经" + str(my_dog.age) + "岁了!")
my_dog.wang()
print("\n你爱犬的名字是" + your_dog.name.title() + ".")
print("你的爱犬已经" + str(your_dog.age) + "岁了!")
your_dog.wang()
??在上述代码中,在构造方法__init__()中创建一个表示特定小狗的实例,并使用我们提供的值来设置属性name和 age。在my_dog.name.title()和str(my_dog.age)中点运算符“.访问了实例属性,运算符表示法在 Python中很常用,这种语法演示了Python如何获取属性的值。在上述代码中,Python先找到实例my_dog,再查找与这个实例相关联的属性name。在类Dog中引用这个属性时,使用的是self.name。同样道理,可以使用同样的方法来获取 ??属性age的值。在代码“my dog.name.title()”中,将my_dog的属性name的值改为首字母是大写的,当然我们代码中用的是汉字,读者可以将其设置为字母试一试。在代码行“str(my_dog.age)”中,将my_dog的属性age的值“6”转换为字符串。
二、类属性和实例属性
??在Python程序中,通常将属性分为实例属性和类属性两种,具体说明如下所示。 ?? (1)实例属性:是同一个类的不同实例,其值是不相关联的,也不会互相影响的,定义时使用“self.属性名”的格式定义,调用时也使用这个格式调用。 ??(2)类属性:是同一个类的所有实例所共有的,直接在类体中独立定义,引用时要使用“类名.类变量名”的格式来引用,只要是某个实例对其进行修改,就会影响其他所有这个类的实例。演示实例:
class X_Property: #定义类X_Property
class_name = "X_Property" #设置类的属性
def __init__(self,x=0): #构造方法
self.x = x #设置实例属性
def class_info(self): #定义方法输出信息
print("类变量值:",X_Property.class_name)
print('实例变量名',self.x)
def chng(self,x): #定义方法修改实例属性
self.x = x #引用实例属性
def chng_cn(self,name): #定义方法修改类属性
X_Property.class_name = name
aaa = X_Property() #定义类X_Property的实例化对象aaa
bbb = X_Property() #定义类X_Property的实例化对象bbb
print("初始化两个实例")
aaa.class_info()
bbb.class_info()
print("修改实例变量")
print("修改aaa实例变量")
aaa.chng(3)
aaa.class_info()
bbb.class_info()
print("修改bbb实例变量")
bbb.chng(10)
aaa.class_info()
bbb.class_info()
print("修改类变量")
print("修改aaa类变量")
aaa.chng_cn("aaa")
aaa.class_info()
bbb.class_info()
print("修改bbb类变量")
bbb.chng_cn("bbb")
aaa.class_info()
bbb.class_info()
??在上述实例代码中,首先定义了类X_Property, 在类中有一个类属性class_name 和一个实例属性x,两个分别修改实例属性和类属性的方法。然后分别实例化这个类,并调用这两个类实例来修改类属性和实例属性。对于实例属性来说,两个实例相互之间并不联系,可以各自独立地被修改为不同的值。而对于类属性来说,无论哪个实例修改了它,都会导致所有实例的类属性值发生变化。执行后会输出:
三、设置属性的默认值
??在Python程序中,类中的每个属性都必须有初始值,并且有时可以在方法__init__()中指定某个属性的初始值是0或空字符串。如果设置了某个属性的初始值,就无须在__init__()中提供为属性设置初始值的形参。假设有这么一个场景,年底将至,想换辆新车,初步中意车型是奔驰E级。例如在下面的实例中,定义了一个表示汽车的类,在类中包含了和汽车有关的属性信息:
class Car():
"奔驰!"
def __init__(self,manufacturer,model,year):
"初始化操作,创建描述汽车的属性"
self.manufacturer = manufacturer
self.model = model
self.year = year
self.odometer_reading = 0
def get_descriptive_name(self):
"返回描述信息"
long_name = str(self.year) + ' ' + self.manufacturer + ' ' + self.model
return long_name.title()
def read_odometer(self):
"行驶里程"
print("新车的仪表显示行驶里程是" +str (self.odometer_reading) + "公里!")
my_new_car = Car("Benz","E300L",2009)
print(my_new_car.get_descriptive_name())
my_new_car.read_odometer()
??对上述实例代码的具体说明如下所示。 ??(1)首先定义了方法__init__(),这个方法的第一个形参为self, 三个形参: manufacturer、model和year。运行后方法__init__()接受这些形参的值,并将它们存储在根据这个类创建的实例的属性中。创建新的Car实例时,我们需要指定其品牌、型号和生产日期。 ??(2)在第8行代码中添加了一个名odometer_reading 的属性,并设置其初始值总是为0。 ??(3)在第9行代码定义了一个名为get_descriptive_name(的方法,在里面使用属性year、manufacturer 和model创建了一个对汽车进行描述的字符串,在程序中我们无须分别打印输出每个属性的值。为了在这个方法中访问属性的值,分别使用了self.manufacturer、self.model和self.year格式进行访问。 ??(4)在第13行代码中定义了方法readodometer(),功能是获取当前奔驰汽车的行驶里程。 ??(5)在倒数第3行代码中,为了使用类Car,根据类Car创建了一个实例,并将其存储到变量my_new_car中。然后调用方法get_descriptive_name(),打印输出我当前想购买的是哪一款汽车。 ??(6)在最后1行代码中,打印输出当前奔驰汽车的行驶里程。因为设置的默认值是0,所以会显示行驶里程为0。执行后会输出:
四、修改属性的值
??在Python程序中,可以使用如下两种不同的方式修改属性的值。 ??●直接通过实例进行修改; ??●通过自定义方法修改。 ??在下面的内容中,将详细讲解.上述两种修改属性值方法的知识。 ??1. 直接通过实例进行修改 ??在Python程序中,可以直接通过实例的方式修改一个属性的值。例如在下面的实例代码中,将新车奔驰E300L的行驶里程修改为12公里。
my_new_car = Car("Benz","E300L",2009)
print(my_new_car.get_descriptive_name())
my_new_car.odometer_reading = 12 #修改里程数
my_new_car.read_odometer()
??在上述代码中,使用点运算“.”来直接访问并设置汽车的属性odometer_reading,并将属性odometer_reading值设置为12,执行结果如下: ??2.自定义方法修改 ??在Python程序中,可以自定义编写一个专有方法来修改某个属性的值。这是可以无须直接访问属性,而只是将值传递给自定义编写的方法,并在这个方法内部进行修改即可。例如在下面的实例代码中,通过自定义方法update_odometer()将行驶里程修改为15公里:
def update_odometer(self,mileage):
"修改行驶里程"
if mileage>= self.odometer_reading:
self.odometer_reading = mileage
else:
("这是一个不合理的数据")
my_new_car = Car("Benz","E300L",2019)
print(my_new_car.get_descriptive_name())
my_new_car.update_odometer(15)
my_new_car.read_odometer()
??在上述实例代码中定义了一个自定义方法update_odomer(),此方法可以接受一个行驶里程值,并将其存储到self.odometer_reading 中。并且设置在修改属性前检查指定的里程数据是否合理。如果新指定的里程大于或等于原来的里程“self.odometer_reading” ,则将里程数据改为新设置的里程数据。否则就发出提醒,输出“这是一个不合理的数据!”的提示。在倒数第2行代码中,调用自定义方法update_odometer() 将行驶里程修改为15。执行后会输出:
五、使用私有属性
??在前面一篇文章的内容中已经讲解了私有方法的知识,已经了解到只要在属性名或方法名前加上两个下画线“__”,那么这个属性或方法就会为私有的了。在Python程序中,私有属性不能在类的外部被使用或直接访问。当在类的内部使用私有属性时,需要通过“self. __属性名”的格式使用。例如在下面的实例中演示了在类内使用私有属性过程。实例如下:
class Person:
def __init__(self):
self.__name="haha"
self.age = 22
def get_name(self):
return self.__name
def get_age(self):
return self.age
person = Person()
print (person.get_name())
print (person.get_age())
??在上述代码中,“__name”是私有属性。如果直接访问私有属性和私有方法,系统会提示找不到相关的属性或者方法。执行后输出:
|