类的定义

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 [, 形参列表]):
  函数体

方法的调用格式如下:
对象.方法名([实参列表])

要点:

  1. 定义实例方法时,第一个参数必须为 self。和前面一样,self 指当前的实例对象。
  2. 调用实例方法时,不需要也不能给 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 [,形参列表]) :
  函数体

要点如下:

  1. @classmethod 必须位于方法上面一行
  2. 第一个 cls 必须有;cls 指的就是“类对象”本身;
  3. 调用类方法格式:“类名.类方法名(参数列表)”参数列表中,不需要也不能给 cls 传值
  4. 类方法中访问实例属性和实例方法会导致错误
  5. 子类继承父类方法时,传入 cls 是子类对象,而非父类对象
  6. 类方法可以引用类属性
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
将一个方法变成属性