python2需要在类名后括号内写明父类,python3如果不写后面的括号则默认继承object
pass是占位语句,用来保证函数(方法)或类定义的完整性,表示无内容,空的意思
#class 类名(父类,没有就是object):
class Student(object):
"""
类注释
Attributes:
attr1: 属性1
attr2: 属性2
attr3: 属性3
"""
pass
class Student(object):
pass
#实例变量名 = 类名()
stu = Student()
print(stu)
>>>>
#打印可以看到,实例属于Student
<__main__.Student object at 0x000001538F0097F0>
由于类可以起到模板的作用,因此,可以在创建实例的时候,把一些我们认为必须绑定的属性强制填写进去。通过定义一个特殊的__init__
方法(构造方法),在创建实例的时候,就把属性绑上去
__init__
方法的第一个参数永远是self
,表示创建的实例本身,因此,在__init__
方法内部,就可以把各种属性绑定到self
,因为self
就指向创建的实例本身
class Student(object):
#构造方法
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
stu = Student('lucy',18,'女')
print(stu.name)
print(stu.age)
print(stu.sex)
要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__
,在Python中,实例的变量名如果以__
开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问
不能直接访问__name
是因为Python解释器对外把__name
变量改成了_Student__name
,所以,仍然可以通过stu._Student__name
来访问__name
变量,但是不要这么做
class Student(object):
#构造方法
def __init__(self,name,age,sex):
self.__name = name
self.__age = age
self.__sex = sex
stu = Student('lucy',18,'女')
要定义一个方法,除了第一个参数必须是self
外,其他和普通函数一样
class Student(object):
#默认值私有属性
__sex = '男'
#构造方法
def __init__(self,name,age,sex):
self.__name = name
self.__age = age
self.__sex = sex
def showMsg(self):
"展示学生信息"
print("姓名:",self.__name,"年龄:",self.__age,"性别:",self.__sex)
stu = Student('lucy',18,'女')
stu.showMsg()
私有方法和私有属性一样,在方法名前加两个下划线__
,方法就变成了私有的
私有方法同样可以通过stu._Student__sayHello()
进行访问,但是不要这么做
class Student(object):
#构造方法
def __init__(self,name,age,sex):
self.__name = name
self.__age = age
self.__sex = sex
def showMsg(self):
"展示学生信息"
print("姓名:",self.__name,"年龄:",self.__age,"性别:",self.__sex)
def __sayHello(self):
"私有方法"
print('Hello')
stu = Student('lucy',18,'女')
stu.showMsg()
除了前面我们使用的__init__
外,Python还提供了很多的类的内置方法,这些内置方法我们称之为:魔术方法
我们可以通过__str__
方法,控制类转换为字符串的行为。
class Student:
def __init__(self,name,age):
self.name = name
self.age = age
def __str__(self):
return f'我叫{self.name},今年{self.age}岁'
stu = Student("Lucy",18)
print(stu) # 我叫Lucy,今年18岁
小于符号比较方法
直接对2个对象进行比较是不可以的,但是在类中实现__lt__
方法,即可同时完成:小于符号 和 大于符号 2种比较
比较大于符号的魔术方法是:__gt__
,不过,实现了__lt__
,__gt__
就没必要实现了
class Student:
def __init__(self,name,age):
self.name = name
self.age = age
def __lt__(self,other):
return self.age < other.age
stu1 = Student("Lucy",18)
stu2 = Student("Tom",20)
print(stu1 < stu2) # True
小于等于的比较符号。同上。
>=
符号实现的魔术方法是:__ge__
。不过,实现了__le__
,__ge__
就没必要实现了
等于的比较符号。不实现__eq__
方法,对象之间可以比较,但是是比较内存地址,也即是:不同对象==
比较一定是False结果。
在类中直接定义的属性,就是静态属性,这个属性属于类,被该类所有实例共有
需要注意:
当我们根据使用实例对象
修改静态属性
时,该实例对象的类属性会改变,但只会作用于自身(修改的实例对象),不会影响其他实例的属性值。
当我们通过类
直接修改静态属性
时,静态属性会发生改变,并且生效作用于其他的实例对象,其他的实例对象访问结果会变成类修改静态属性后的结果,而实例对象修改过后的静态属性却没有受到影响,它的静态属性的值是它(实例对象)修改过后的值。
class MyClass:
class_attr = "I am a class attribute"
def __init__(self, ins_attr):
self.ins_attr = ins_attr
if __name__ == '__main__':
obj1 = MyClass("I am an instance attribute of obj1")
obj2 = MyClass("I am an instance attribute of obj2")
print(obj1.class_attr) # 输出 "I am a class attribute"
print(obj2.class_attr) # 输出 "I am a class attribute"
print(obj1.ins_attr) # 输出 "I am an instance attribute of obj1"
print(obj2.ins_attr) # 输出 "I am an instance attribute of obj2"
obj1.class_attr = "I am a new update class attribute of obj1"
print(obj1.class_attr) # 输出 "I am a new update class attribute of obj1"
print(obj2.class_attr) # 输出 "I am a class attribute"
MyClass.class_attr = "I am a new MyClass attribute"
print(obj1.class_attr) # 输出 "I am a new update class attribute of obj1"
print(obj2.class_attr) # 输出 "I am a new MyClass attribute"
print(MyClass.class_attr) # 输出 "I am a new MyClass attribute"
python中,可以使用装饰器@classmethod
或@staticmethod
,
@staticmethod
不需要表示自身对象的self和自身类的cls参数,就跟使用函数一样。@classmethod
也不需要self参数,但第一个参数需要是表示自身类的cls参数。如果在@staticmethod
中要调用到这个类的一些属性方法,只能直接类名.属性名
或类名.方法名
。
而@classmethod
因为持有cls
参数,可以来调用类的属性,类的方法,实例化对象等,避免硬编码。
class Student:
@staticmethod
def good():
print('good')
@classmethod
def hello(cls):
cls.good()
print('hello')
@staticmethod
def bye():
Student.good()
print('bye')
在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)
可以使用isinstance(obj,class)
来查看对象obj是否属于类class
class Animal(object):
pass
#狗、猫类继承于动物类
class Dog(Animal):
pass
class Cat(Animal):
pass
#实例化
d = Dog()
c = Cat()
print(isinstance(d,Animal))
print(isinstance(c,Animal))
子类会继承父类中已经声明的属性,并且可以使用默认值
class Animal(object):
name = '动物'
#狗类继承于动物类
class Dog(Animal):
pass
#实例化
d = Dog()
#调用父类声明的属性
print(d.name)
子类会继承父类的所有方法,包括构造方法__init__()
class Animal(object):
def __init__(self,name):
self.__name = name
def run(self):
"动物都有的行为"
print('%s在跑' % self.__name)
#狗、猫类继承于动物类
class Dog(Animal):
pass
class Cat(Animal):
pass
#实例化,继承父类的构造方法
d = Dog("狗")
c = Cat("猫")
#继承父类的方法
d.run()
c.run()
如果你的父类方法的功能不能满足你的需求,你可以在子类重写你父类的方法
class Animal(object):
def run(self):
print("动物在跑")
class Dog(Animal):
#重写父类方法run()
def run(self):
print("狗子在跑")
dog = Dog()
dog.run()
super() 函数是用于调用父类(超类)的一个方法,也就是使用子类对象,调用父类已被重写的方法
super() 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。
MRO就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表。
class Animal(object):
def run(self):
print("动物在跑")
class Dog(Animal):
# 重写父类方法run()
def run(self):
# 调用父类方法run()
super().run()
print("狗子在跑")
d = Dog()
d.run()
# 动物在跑
# 狗子在跑
# 调用实例的父类方法
super(Dog,d).run() # 动物在跑
python支持多继承,即可以继承于多个父类
需要注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,python从左至右搜索即方法在子类中未找到时,从左到右查找父类中是否包含方法
class Animal(object):
def run(self):
"动物都有的行为"
print('动物可以跑')
class Pet(object):
def play(self):
"宠物都有的行为"
print('宠物可以和主人玩')
class Cat(Animal,Pet):
pass
cat = Cat()
cat.play()
cat.run()
python不支持多态也用不到多态,多态的概念是应用于Java和C#这一类强类型语言中,而Python崇尚鸭子类型(Duck Typing)
鸭子类型:是一种动态类型的风格。一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由当前方法和属性的集合决定。这个概念的名字来源于由James Whitcomb Riley提出的鸭子测试,“鸭子测试”可以这样表述:“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”
也就是说,我们可以编写一个函数,它接受一个类型为鸭的对象,并调用它的走和叫方法。在使用鸭子类型的语言中,这样的一个函数可以接受一个任意类型的对象,并调用它的走和叫方法。如果这些需要被调用的方法不存在,那么将引发一个运行时错误
class Duck(object):
def go(self):
print('鸭子走')
def run(self):
print('鸭子跑')
class Dog(object):
def go(self):
print('狗走')
def run(self):
print('狗跑')
#python的多态,不在于是哪个类,而是只要该对象有这两个方法就可以
def handler(duck):
duck.go()
duck.run()
duck = Duck()
dog = Dog()
handler(duck)
handler(dog)
type()可以获取对象的类型,返回一个Class类型的变量,可以使用==
判断两个对象是否同一类型
class Person(object):
def __init__(self,name,age):
self.__name = name
self.__age = age
def showMsg(self):
print('姓名',self.__name,'年龄',self.__age)
person = Person('lucy',18)
print(type(person)) # <class '__main__.Person'>
isinstance(obj,class)
来查看对象obj是否属于类class
class Person(object):
def __init__(self,name,age):
self.__name = name
self.__age = age
def showMsg(self):
print('姓名',self.__name,'年龄',self.__age)
person = Person('lucy',18)
print(isinstance(person,Person)) # Ture
如果要获得一个对象的所有属性和方法,可以使用dir()
函数,它返回一个包含字符串的list
class Person(object):
def __init__(self,name,age):
self.__name = name
self.__age = age
def showMsg(self):
print('姓名',self.__name,'年龄',self.__age)
person = Person('lucy',18)
print(dir(person))
'''
['_Person__age', '_Person__name', '__class__', '__delattr__',
'__dict__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__',
'__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__setattr__', '__sizeof__', '__str__', '__subclasshook__',
'__weakref__', 'showMsg']
'''
仅仅把属性和方法列出来是不够的,配合getattr()
、setattr()
以及hasattr()
,我们可以直接操作一个对象的状态,类似java的反射机制
获取对象某个属性的值
class Person(object):
def __init__(self,name,age):
self.__name = name
self.__age = age
def showMsg(self):
print('姓名',self.__name,'年龄',self.__age)
person = Person('lucy',18)
#获取person对象_Person__name属性的值
print(getattr(person,'_Person__name'))
#获取person对象_Person__name属性的值,如果不存在,返回404
print(getattr(person,'_Person__name',404))
设置对象某个属性的值
class Person(object):
def __init__(self,name,age):
self.__name = name
self.__age = age
def showMsg(self):
print('姓名',self.__name,'年龄',self.__age)
person = Person('lucy',18)
#设置person对象,_Person__name属性值为tom
setattr(person,'_Person__name','tom')
person.showMsg()
判断对象是否含有某个属性
class Person(object):
def __init__(self,name,age):
self.__name = name
self.__age = age
def showMsg(self):
print('姓名',self.__name,'年龄',self.__age)
person = Person('lucy',18)
#判断对象person中是否含有属性_Person__name
print(hasattr(person,'_Person__name'))
此外,这三个函数也可以作用于对象的方法
class Person(object):
def __init__(self,name,age):
self.__name = name
self.__age = age
def showMsg(self):
print('姓名',self.__name,'年龄',self.__age)
person = Person('lucy',18)
#判断对象person中是否含有方法showMsg
print(hasattr(person,'showMsg'))
#获取对象person的方法showMsg
show = getattr(person,'showMsg')
#调用方法
show() # 姓名 lucy 年龄 18
Python在3.5版本的时候引入了类型注解,以方便静态类型检查工具,IDE等第三方工具。
类型注解:在代码中涉及数据交互的地方,提供数据类型的注解(显式的说明)。
支持:
# 变量的类型注解
a: int = 10
b: float = 2.5
c: str = 'hello'
d: bool = True
e: dict[str,int] = {'a':1,'b':2}
f: list[int] = [1,2,3,4]
g: set[int] = {1,2,3,4,5}
h: tuple[int] = (1,2,3,4,5)
# 函数的类型注解
def test(a: int,b: str) -> str:
pass
使用Union[类型, ......, 类型]
可以定义联合类型注解,可以理解为,里面的类型都是可以的
from typing import Union
a: list[Union[int,str]] = [1,2,'3','4']