文章目录
- 1.创建和使用类
- 2.属性私有化
- 3.类中的几种方法
- 3.1 类方法
- 3.2 静态方法
- 4. 对象属性的操作
- 5.getter和setter
- 6.类中的内置属性
- 7.继承多态
- 7.1继承
- 7.2多继承
- 7.3 多态
1.创建和使用类
python中通过class创建类,下面创建一个Animal类,类名首字母一般大写。__init__是一个特殊的方法,用来初始化对象属性
# 创建类
class Animal(object):
num = 18 # 可在类中创建此类字段
def __init__(self, name, age):
self.name = name
self.age = age
def eating(self):
print(f'the {self.name} is eating')
def singing(self, songname):
print(f'the {self.name} is singing a song ,the song is {songname}')
# 使用类
animal = Animal('rabbit', '1')
animal.eating()
animal.singing('两只老虎')
print(animal.num)
"""
输出结果:
rabbit is eating
rabbit is singing a song ,the song is 两只老虎
18
"""
2.属性私有化
python 中属性的私有化是通过给属性前加两个下划线来实现的,示例如下:
class Animal(object):
def __init__(self, gender, age):
self.__gender = gender
self.__age = age
def __get_gender(self):
animal_gender = self.__gender
print(animal_gender)
animal = Animal('xx')
animal.__get_gender()
# TypeError: __init__() missing 1 required positional argument: 'age'
print(animal.__age)
# TypeError: __init__() missing 1 required positional argument: 'age'
如上便实现了私有化。
但是,python的私有化并不是真正的私有化,python的一切类方法和属性都是“公开的”,它的私有化,只是改变了名字而已,只要我们知道它改变名字的规律,私有的属性我们都能访问到。之所以python会如此设置,是因为这个理念:“开放要比封闭好,程序员得为自己的行为负责”
下面是访问私有属性的代码:
class Animal(object):
def __init__(self, gender, age):
self.__gender = gender
self.__age = age
def __get_gender(self):
animal_gender = self.__gender
print(animal_gender)
animal = Animal('xx', 3)
animal._Animal__get_gender()
# 输出 xx
3.类中的几种方法
3.1 类方法
类方法用@classmethod声明,代码如下:
class Animal(object):
num = 18
def __init__(self, name, age):
self.name = name
self.age = age
def eating(self):
print(f'{self.name} is eating')
return ''
def singing(self, songname):
print(f'the {self.name} is singing a song ,the song is {songname}')
@classmethod # 在此使用了类方法
def action(cls):
a1 = cls('tutu', 4) # 注意此句
return a1.eating()
animal = Animal.action()
print(animal)
# tutu is eating
用@classmethod声明类方法后,定义函数时,pycharm会自动在括号里填充cls,cls指的是当前类,可以直接用其创建对象,也可以使用类中的方法,如上所示。
3.2 静态方法
在创建类时,对象方法都是给对象发送消息的,实际上我们并不需要每个类方法都是对象方法,比如你不确定某些对象能否合理创建时,就可以在此类中创建一个静态方法,专门用于判断能否合理 创建对象。例如,你创建了一个成年人类,只有成年人才能访问其中方法,静态方法用@staticmethod声明:
class Person(object):
def __init__(self, name, gender):
self.name = name
self.age = gender
@staticmethod
def judge_adult(age):
return age > 18
def wangba(self):
print(f'{self.name}可以去网吧')
return
p1 = Person('jony', 'male')
if p1.judge_adult(17):
p1.wangba()
else:
print('you are not a adult')
# you are not a adult
4. 对象属性的操作
我们可以对对象的属性进行增删改查
class Animal(object):
def __init__(self, name, age, breed):
self.name = name
self.age = age
self.breed = breed
def get_informations(self):
print(self.name, self.age, self.breed)
animal = Animal('doudou', 6, 'dog')
animal.get_informations()
# doudou 6 dog
animal.age = 7 # 可采用此形式直接改变属性值
animal.get_informations()
# doudou 7 dog
# 可通过getattr(对象,属性)直接获取属性值
print(getattr(animal, 'name'))
# doudou
# 可通过setattr(对象, 属性, 值)给对象修改属性值
setattr(animal, 'breed', 'cat')
print(getattr(animal, 'breed'))
# cat
# 可通过del(属性)删除对象对应属性
del animal.breed
print(animal.breed)
# AttributeError: 'Animal' object has no attribute 'breed'
注意: 使用del删除对象对应属性时,并不会把类中的属性也直接删除,下次用此类新创建一个对象时,该属性依然可用。
5.getter和setter
实际开发中,我们并不是以双下划线来将属性设置为私有,而是用单下划线来表示这个属性是受保护的,这个属性并不是私有,你仍然可以通过访问它的下划线形式来进行增删改查。
属性名前加单下划线,当我们希望在给它赋值前或者获取其属性前做点其他事,可以用getter和setter。
class Animal(object):
def __init__(self, name, age, breed):
self._name = name # 将属性名前加下划线,表示受保护
self._age = age
self._breed = breed
@property
def age(self):
return self._age
@age.setter
def age(self, value):
if isinstance(value, int):
if 0 < value <=150:
self._age = value
else:
print('年龄不符合常理')
animal = Animal('doudou', 6, 'dog')
print(animal._age)
# 6
animal.age = 180
# 年龄不符合常理
但是,我们仍然可以通过下划线方法来访问和修改受保护的属性,一般情况下别那么做
animal._age = 180
print(animal._age)
# 180
6.类中的内置属性
- __name__ : 获取类的名字
- __class__ : 获取当前对象对应的类
- __doc__ : 获取当前类的说明文档
- __dict__ : 获取所有的字段和属性及其对应的值
- __slots__ : 控制可修改的属性
class Animal(object):
"""
动物类,用于测试
"""
def __init__(self, name, age):
self.name = name
self.age = age
def eating(self):
print(f'the {self.name} is eating')
def singing(self, songname):
print(f'the {self.name} is singing a song ,the song is {songname}')
animal = Animal('qiqi', 6)
print(animal.fun1())
# Animal
print(animal.__class__)
# <class '__main__.Animal'>
print(Animal.__doc__)
# 动物类,用于测试
print(animal.__dict__)
# {'name': 'qiqi', 'age': 6}
print(Animal.__dict__)
# {'__module__': '__main__', '__doc__': '\n 动物类,用于测试\n ', '__init__': <function Animal.__init__ at 0x0000022A69408E18>, 'eating': <function Animal.eating at 0x0000022A69408EA0> ......
其中,__slots__单独测试如下:
class Animal(object):
__slots__ = ('name', 'age', 'breed')
def __init__(self, name, age, breed):
self.name = name
self.age = age
self.breed = breed
def eating(self):
print(f'the {self.name} is eating')
def singing(self, songname):
print(f'the {self.name} is singing a song ,the song is {songname}')
@classmethod
def fun1(cls):
return cls.__name__
animal = Animal('qiqi', 6, 'fish')
animal.name = 'ggbong'
animal.gender = 'male'
# AttributeError: 'Animal' object has no attribute 'gender'
当把 __slots__去掉后,不报错
7.继承多态
7.1继承
子类可以从父类那里继承属性和方法,通过super().__init__调用,也可以通过super().方法调用指定方法,静态方法不能用。
子类除了能使用父类的方法外,还可以自定义一些方法,所以子类比父类拥有更多的能力。
class Animal(object): # 父类
num = 2
def __init__(self, name=None):
self.name = name
self.gender = 'male'
def playing(self):
print('{} is playing'.format(self.name))
@staticmethod
def fun1():
return 'a+b' # 静态方法,期待返回 'a+b'
class Cat(Animal): # 子类
voice = 'mia~'
def __init__(self, name, age):
super().__init__(name) # 调用当前父类的init方法
self.color = 'black'
self.breed = 'jaffe'
def cat_play(self):
super().playing() # 继承的父类方法
return None
def getsome(self):
super().fun1() # 父类中的静态方法
return None
cat = Cat('caffe', 6)
print(cat.color)
# black
print(cat.cat_play())
# caffe is playing
print(cat.getsome()) # 尝试调用静态方法
# None
7.2多继承
关于多继承,示例如下:
class A:
def message(self):
print('A')
class B:
def message(self):
print('B')
class C(A, B):
def message(self):
super().message()
print('C')
class D(B, A):
def message(self):
super().message()
print('D')
C().message()
# A
# C
# 发现继承的是前面那个父亲
D().message()
# B
# D
7.3 多态
子类在继承了父类的方法后,可以对父类已有的方法给出新的实现版本,这个动作称之为方法重写。通过方法重写我们可以让父类的同一个行为在子类中拥有不同的实现版本,当我们调用这个经过子类重写的方法时,不同的子类对象会表现出不同的行为,这个就是多态。
下面是来自Github上jackfrued的例子:
from abc import ABCMeta, abstractmethod
class Pet(object, metaclass=ABCMeta):
"""宠物"""
def __init__(self, nickname):
self._nickname = nickname
@abstractmethod
def make_voice(self):
"""发出声音"""
pass
class Dog(Pet):
"""狗"""
def make_voice(self):
print('%s: 汪汪汪...' % self._nickname)
class Cat(Pet):
"""猫"""
def make_voice(self):
print('%s: 喵...喵...' % self._nickname)
def main():
pets = [Dog('旺财'), Cat('凯蒂'), Dog('大黄')]
for pet in pets:
pet.make_voice()
if __name__ == '__main__':
main()
""" 输出:
旺财: 汪汪汪...
凯蒂: 喵...喵...
大黄: 汪汪汪...
"""
Python从语法层面并没有像Java或C#那样提供对抽象类的支持,但是我们可以通过abc
模块的ABCMeta
元类和abstractmethod
包装器来达到抽象类的效果,如果一个类中存在抽象方法那么这个类就不能够实例化(创建对象)。上面的代码中,Dog
和Cat
两个子类分别对Pet
类中的make_voice
抽象方法进行了重写并给出了不同的实现版本,当我们在main
函数中调用该方法时,这个方法就表现出了多态行为(同样的方法做了不同的事情)。
关于面向对象的知识纷杂繁多,对于“一切皆为对象”的python而言,面向对象的知识无时无刻不在使用。上面的基础操作不过尔尔,具体灵活运用,还需自身多实践。