类的定义
class Student:
def __init__(self,name,score): #构造方法第一个参数必须为 self
= name #实例属性
self.score = score
def say_score(self): #实例方法
print(,'的分数是:',self.score)
s1 = Student('张三',80) #s1 是实例对象,自动调用__init__()方法
s1.say_score() # 张三 的分数是: 80
init()
创建对象,我们需要定义构造函数方法。构造方法用于执行“实例对象的初始化工作”,即对象创建后,初始化当前对象的相关属性,无返回值。
init()的要点如下
- 名称固定,必须为:__init__()
- 第一个参数固定,必须为:self。 self 指的就是刚刚创建好的实例对象。
- 构造函数通常用来初始化实例对象的实例属性,如下代码就是初始化实例属性:name和 score。
- 通过“类名(参数列表)”来调用构造函数。调用后,将创建好的对象返回给相应的变量。比如:s1 = Student('张三', 80)
- init()方法:初始化创建好的对象,初始化指的是:“给实例属性赋值”
- new()方法: 用于创建对象,但我们一般无需重定义该方法。
- 如果我们不定义__init__方法,系统会提供一个默认的__init__方法。如果我们定义了带参的__init__方法,系统不创建默认的__init__方法。
实例属性
class Student:
def __init__(self,name,score):
=name # 实例属性
self.score=score # 实例属性
def say_score(self):
print(,"的分数为:",self.score)
s1=Student('言深',75)
s1.say_score()
s1.age=1000 # 可以通过这种方法为s1这个对象加属性,但不能对类加属性
print(s1.age)
s2=Student('NaLiu',85)
# print(s2.age) # 这个对象s2就没有age这个属性了
实例方法
实例方法是从属于实例对象的方法。实例方法的定义格式如下:
def 方法名(self [, 形参列表]):
函数体
方法的调用格式如下:
对象.方法名([实参列表])
要点:
- 定义实例方法时,第一个参数必须为 self。和前面一样,self 指当前的实例对象。
- 调用实例方法时,不需要也不能给 self 传参。self 由解释器自动传参。
类对象
class Student:
def __init__(self,name,score):
=name # 实例属性
self.score=score # 实例属性
def say_score(self): # 实例方法
print(,"的分数为:",self.score)
s1=Student('言深',75)
s1.say_score() # 言深 的分数为: 75
stu2=Student
s2=stu2('NaLiu',85)
s2.say_score() # NaLiu 的分数为: 85
类属性
类属性是从属于“类对象”的属性,也称为“类变量”。由于,类属性从属于类对象,可以被所有实例对象共享。
类属性的定义方式:
class 类名:
类变量名= 初始值
在类中或者类的外面,我们可以通过:“类名.类变量名”来读写。
class Student:
count = 0 # 类属性
def __init__(self,name,score):
=name # 实例属性
self.score=score # 实例属性
Student.count=Student.count+1 # 类属性
def say_score(self): # 实例方法
print(,'的分数为:',self.score)
s1=Student('NaLiu',12)
s2=Student('NaLiu',12)
s3=Student('NaLiu',12)
print("类Student建立了{0}个对象".format(Student.count))
类方法
类方法是从属于“类对象”的方法。类方法通过装饰器@classmethod 来定义,格式如下:
@classmethod
def 类方法名(cls [,形参列表]) :
函数体
要点如下:
- @classmethod 必须位于方法上面一行
- 第一个 cls 必须有;cls 指的就是“类对象”本身;
- 调用类方法格式:“类名.类方法名(参数列表)”参数列表中,不需要也不能给 cls 传值
- 类方法中访问实例属性和实例方法会导致错误
- 子类继承父类方法时,传入 cls 是子类对象,而非父类对象
- 类方法可以引用类属性
class Student:
@classmethod # 类方法
def Print(cls):
print("hahahaha")
def __init__(self,name,score):
=name # 实例属性
self.score=score # 实例属性
def say_score(self): # 实例方法
print(,'的分数为:',self.score)
Student.Print() # hahahaha
class Student:
count = 0 # 类属性
@classmethod # 类方法
def Print(cls,a,b):
print(cls.count) # 可以引用类属性
print("{0}+{1}={2}".format(a,b,a+b))
def __init__(self,name,score):
=name # 实例属性
self.score=score # 实例属性
Student.count=Student.count+1
def say_score(self): # 实例方法
print(,'的分数为:',self.score)
Student.Print(2,3) # 2+3=5
静态方法
Python 中允许定义与“类对象”无关的方法,称为“静态方法”。
“静态方法”和在模块中定义普通函数没有区别,只不过“静态方法”放到了“类的名字空间里面”,需要通过“类调用”
静态方法通过装饰器@staticmethod 来定义,格式如下:
@staticmethod
def 静态方法名([形参列表]) :
函数体
- @staticmethod 必须位于方法上面一行
- 调用静态方法格式:“类名.静态方法名(参数列表)”
- 静态方法中访问实例属性和实例方法会致错误
- 静态方法可以引用类属性
class Student:
count = 0
@classmethod
def Print(cls, a, b):
print(cls.count,end=" ") # 类方法可以引用类属性 cls.类属性
print("{0}+{1}={2}".format(a, b, a + b))
@staticmethod
def rePrint(a, b, c, d):
print(Student.count,end=" ") # 静态方法可以引用类属性 类名.类属性
print("{0}{1}{2}{3}".format(a, b, c, d))
def __init__(self, name, score):
= name
self.score = score
Student.count = Student.count + 1
def say_score(self):
print(, '的分数为:', self.score)
Student.Print(1,2) # 0 1+2=3
Student.rePrint(1, 2, 3, 4) # 0 1234
__call__方法和可调用对象
定义了__call__方法的对象,称为“可调用对象”,即该对象可以像函数一样被调用。
class Student:
def __call__(self,name):
Name=name
return Name
s=Student()
print(s('NaLiu')) # NaLiu
Python没有方法重载
方法的动态性
Python 是动态语言,我们可以动态的为类添加新的方法,或者动态的修改类的已有的方法。
class Person:
def word(self):
print("好好工作")
def play_game(self):
print("好好玩")
def re_work(self):
print("去你妈的好好工作")
Person.play=play_game # 添加了一个实例方法
Person.work=re_work # 改变了一个实例方法
s1=Person()
s1.play() # 好好玩
s1.work() # 去你妈的好好工作
私有属性和私有方法(实现封装)
关于私有属性和私有方法,有如下要点:
- 通常我们约定,两个下划线开头的属性是私有的(private)。其他为公共的(public)。
- 类内部可以访问私有属性(方法)
- 类外部不能直接访问私有属性(方法)
- 类外部可以通过“_类名__私有属性(方法)名”访问私有属性(方法)
私有属性
class Employee:
def __init__(self,name,age):
= name
self.__age = age #私有实例属性
e=Employee('言深',18)
print()
print(e._Employee__age) # 必须这样访问
# print(e.age) # 错误
私有方法
class Employee:
__company = "CSDN程序员" # 私有类属性. 通过 dir 可以查到
def __init__(self, name, age):
= name
self.__age = age # 私有实例属性
def __work(self): # 私有实例方法 通过 dir 可以查到
print(self.__company) # 私有方法可以调用私有属性
print(self.__age) # 私有方法可以调用私有属性
print("工作!好好工作你妈呢")
p1 = Employee("言深", 32)
print(p1._Employee__age)
p1._Employee__work()
print(p1._Employee__company)
'''
32
CSDN程序员
32
工作!好好工作你妈呢
CSDN程序员
'''
@property 装饰器
@property 可以将一个方法的调用方式变成“属性调用”。
# 一般实例方法
class Employee:
def salary(self):
return 30000
emp1 = Employee()
print(emp1.salary()) # 30000
class Employee:
@property
def salary(self):
return 30000
emp1 = Employee()
print(emp1.salary) # 30000
print(type(emp1.salary)) # 打印<class 'int'>
# emp1.salary =1000 错误
# @property 修饰的属性,如果没有加setter方法,则为只读属性。
class Employee:
def __init__(self, name, salary):
= name
self.__salary = salary
@property # 相当于 salary 属性的 getter 方法
def salary(self):
print("月薪为{0},年薪为{1}".format(self.__salary,(12*self.__salary)))
return self.__salary;
@salary.setter
def salary(self, salary): # 相当于 salary 属性的 setter 方法
if (0 < salary < 1000000):
self.__salary = salary
else:
print("薪水录入错误!只能在 0-1000000 之间")
emp1 = Employee("言深", 100)
print(emp1.salary)
emp1.salary = -200
'''
月薪为100,年薪为1200
100
薪水录入错误!只能在 0-1000000 之间
'''
继承
Python 支持多重继承,一个子类可以继承多个父类。继承的语法格式如下:
class 子类类名(父类 1[,父类 2,...]):
类体
定义子类时,必须在其构造函数中调用父类的构造函数。调用格式如下:父类名.__init__(self, 参数列表)
class Person:
def __init__(self, name, age):
= name
self.__age = age
def say_age(self):
print(, "的年龄是:", self.__age)
class Student(Person):
def __init__(self, name, age, score):
self.score = score
Person.__init__(self,name,age)
# 构造函数中包含调用父类构造函数。
# 根据需要,不是必须。子类并不会自动调用父类的__init__()
# 我们必须显式的调用它。
s1 = Student("张三", 15, 85)
s1.say_age()
print(s1.score)
方法重写
class Person:
def __init__(self,name,age):
=name
self.age=age
def self_introduce(self):
print("{0}的年龄为:{1}".format(,self.age))
class Student(Person):
def __init__(self,name,age,score):
self.score=score
Person.__init__(self,name,age)
def self_introduce(self):
print("{0}岁的{1}的分数为:{2}".format(self.age,,self.score))
s1=Student('言深',16,75)
s2=Person('言深',16)
s1.self_introduce() # 16岁的言深的分数为:75
s2.self_introduce() # 言深的年龄为:16
查看类的继承层次结构
通过类的方法 mro()或者类的属性__mro__可以输出这个类的继承层次结构。
class A:pass
class B(A):pass
class C(B):pass
print(C.mro())
#[<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
重写__str__()方法
# 原版
class Person: # 默认继承Object类
def __init__(self,name):
=name
p=Person('言深')
print(p) # <__main__.Person object at 0x000001DA68196128>
# 重写__str__()方法后
class Person: # 默认继承Object类
def __init__(self,name):
=name
def __str__(self):
return "我的名字是{0}".format()
p=Person('言深')
print(p) # 我的名字是言深
多重继承
class A:pass
class B:pass
class C(A,B):pass
super()获得父类定义
class A:
def say(self):
print("A:",self)
class B(A):
def say(self):
A.say(self)
print("B:",self)
b=B()
b.say()
# A: <__main__.B object at 0x000001F2D73C0128>
# B: <__main__.B object at 0x000001F2D73C0128>
class A:
def say(self):
print("A:",self)
class B(A):
def say(self):
super().say()
print("B:",self)
b=B()
b.say() # A: <__main__.B object at 0x000001F2D73C0128>
# B: <__main__.B object at 0x000001F2D73C0128>
多态
多态为一种方法调用,根据对象不同而调用不同方法
class Man:
def eat(self):
print("饿了,要吃饭啦")
class Chinese(Man):
def eat(self):
print("中国人用筷子")
class English(Man):
def eat(self):
print("英国人用叉子")
class Indian(Man):
def eat(self):
print("印度人用左手")
def manEat(m):
if isinstance(m,Man): # 如果m和Man是同类
m.eat()
else:
print("不能吃放")
manEat(Chinese()) # 中国人用筷子
manEat(English()) # 英国人用叉子
manEat(Indian()) # 印度人用左手
特殊方法和运算符重载
class Person:
def __init__(self, name):
= name
def __add__(self, other):
if isinstance(other, Person): # 如果other是Person的同类
return "{0}--{1}".format(, )
else:
return "不是同类对象,不能相加"
p1 = Person("言深")
p2 = Person("言柒陆")
print(p1+p2) # 言深--言柒陆
组合与继承的区别
“is-a”关系,我们可以使用“继承”。从而实现子类拥有的父类的方法和属性。“is-a”关系指的是类似这样的关系:狗是动物,dog is animal。狗类就应该继承动物类。 “has-a”关系,我们可以使用“组合”,也能实现一个类拥有另一个类的方法和属性。”has-a”关系指的是这样的关系:手机拥有 CPU。 MobilePhone has a CPU。
由于这章知识我有点得懵懵懂懂的,所以我决定再总结一遍。
# 实例属性 def内部的变量
# 实例方法 对象.方法名(参数)第一个参数必须为self
# 类属性 class内def外的变量
# 类方法
@classmethod
def 方法名(cls):
类名.方法名(参数)
不能引用实例属性和方法
可以引用类属性
# 静态方法
@staticmethod
def 方法名(参数)
参数不需要有self或cls
# 私有属性
# 私有方法
__开头的属性/方法名
对象._类名__私有属性/方法
# @property
将一个方法变成属性