前言
这篇文章将系统带大家了解python类中一些进阶的用法,不敢保证能把理论介绍清晰,但也尽量把用法表达的生动明了。
类的继承
简单的继承
class Person: # 定义一个父类
def talk(self): # 父类中的方法
print("person is talking....")
class Cooker(Person):
def walk(self):
print("make malatang")
cooker = Cooker()
cooker.talk()
cooker.walk()
person is talking....
make malatan
类方法的重写
class Person: # 定义一个父类
def talk(self): # 父类中的方法
print("person is talking....")
class Cooker(Person):
def talk(self):
print("Cooker is talking....")
cooker = Cooker()
cooker.talk()
Cooker is talking....
构造函数的继承
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
self.weight = 'weight'
def talk(self):
print("person is talking....")
class Chinese(Person):
def __init__(self, name, age, language): # 先继承,在重构
super(Chinese, self).__init__(name, age) #继承父类的构造方法,也可以写成Person.__init__(self, name, age) 这种继承在单继承中没有问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题
self.language = language # 定义类的本身属性
def walk(self):
print('say {}'.format(self.language))
c = Chinese("嘎子", 22, "卧槽")
c.walk()
c.talk()
say 卧槽
person is talking....
类中的特殊方法
classmethod
我们先来看下classmethod函数的用法
class Test_Staic:
def __init__(self):
print("实例化测试类")
@classmethod
def say_hello(cls, name):
print("hello: ", name)
Test_Staic().say_hello("小强")
实例化测试类
hello: 小强
我们可以看到类被实例化,然后调用了类方法。这是很正常的使用。
Test_Staic.say_hello("小强")
hello: 小强
我们发现类有没有被实例化都可以调用被classmethod装饰的函数。但是如果只是这样的话,好像跟staticmethod并没有什么区别。
其实我们也称呼classmethod为构造方法。
class Data_test:
def __init__(self,year=0,month=0, day=0):
self.day = day
self.month = month
self.year = year
def out_date(self):
print("day", self.day)
print("month", self.month)
print("year", self.year)
data_test = Data_test(2021, 5, 8)
data_test.out_date()
day 8
month 5
year 2021
这是一个表现时间的对象,我们实例化输入的是具体年月日。但如果我们输出的不是这种标准的格式呢,比如是这种"2021-5-8", 这样我们怎么办呢。我们可以在实例化时加入一个其他参数,来处理。但这样无疑使我们的对象变得臃肿。
这样无疑是变得无意义的。
class Data_test2:
def __init__(self, year=0, month=0, day=0):
self.day = day
self.month = month
self.year = year
def out_date(self):
print("day", self.day)
print("month", self.month)
print("year", self.year)
@classmethod
def separate(cls, data_string):
year, month, day = data_string.split("-")
return cls(year, month, day)
data_test = Data_test2.separate("2021-5-8")
data_test.out_date()
day 8
month 5
year 2021
这样就相当于给我们的类加了一个新的实例方法。
还有一点需要注意的是我们的classmethod方法无法使用实例属性,甚至在使用方法也比较繁琐。但是却可以调用静态方法。
staticmethod
class Test_Staic:
def __init__(self):
print("实例化测试类")
@staticmethod
def say_hello(name):
print("staticmethod: ", name)
Test_Staic().say_hello("hello")
Test_Staic.say_hello("hello")
实例化测试类
staticmethod: hello
staticmethod: hello
staticmethod与classmethod的相同点是都是既是类方法也是实例方法,不同点是staticmethod装饰的就是一个类方法而已,和外部函数没有任何区别。
甚至我觉得如无必要,在类中加入过多的staticmethod本身就是不好的。一个类中如果有过多的静态方法,这个类本身写的也算不上高明。
property
class Student:
def __init__(self):
self._birth = 1997
@property
def birth(self):
return self._birth
@birth.setter
def birth(self, value):
self._birth = value
@property
def age(self):
return 2021 - self._birth
stu = Student()
stu.birth
1997
stu.age
24
我们可以看到,我们使用property装饰一个名为age的函数,他返回的是这个实例的年龄。这样该函数就能如属性一样调用。
在实际开发中,动态属性函数的内部实现可能会更加复杂。
之所以我们称呼动态属性,是因为我们可以进行动态的取值以及赋值。
stu.birth = 2008
stu.birth
2008
stu.age
13
是不是感觉这一套操作行云流水
类中的私有属性及方法
私有属性
class Person(object):
def __init__(self,name,age):
self.name = name
self.__age = age #使用__下划线表示私有属性,对象不能直接调用,要通过方法调调用
def getAge(self):
return self.__age
def setAge(self,age):
if age >100 or age <0:
print("age is not true")
else :
self.__age = age
def __str__(self):
info = "name :"+self.name +",age:"+ str(self.__age)
return info
per = Person("kangkang", 22)
print(per)
name :kangkang,age:22
per._age
AttributeError: 'Person' object has no attribute '_age'
直接调用则会报错,我们尝试赋值
per._age = 88
print(per)
name :kangkang,age:22
其实私有属性的值并没有被改变
per.setAge(88)
print(per)
name :kangkang,age:88
只有通过内部的函数才能调用该属性。但是其实我们在团队开发中应避免使用__方法名这种方式,而采用 _方法名,这种虽然不是强制性的,但一种建议性的命名,往往在开发中更能被接受。
私有方法
class Person2:
def __f1(self):
print("这是私有方法")
def f2(self):
print("这是f2不是私有方法")
def f3(self):
print("这是f3,可以调用f2,也可以调用私有方法__f1")
self.f2()
self.__f1()
per = Person2()
per.__f1()
AttributeError: 'Person2' object has no attribute '__f1'
同样私有方法外部不可以调用。
per.f3()
这是f3,可以调用f2,也可以调用私有方法__f1
这是f2不是私有方法
这是私有方法
让实例变得可迭代
class City:
def __init__(self, city_list):
self.city_list = city_list
def __getitem__(self, index):
return self.city_list[index]
city = City(['北京', '成都', '杭州'])
city[2]
'杭州'
for i in city:
print(i)
北京
成都
杭州