Python类与对象

一、类与对象

面向对象编程

类(class):现实世界中一些事物的封装(如:学生)
类:有属性(如:名字、成绩)

理解【类】最简单的方式:【类】是一个函数包。类中可以放置【函数】和【变量】,然后类中的函数可以很方便的使用类中的变量
——定义在类里面的函数,就是 类的方法 classmethod;
——定义在类里面的变量,就是 类的属性 val
类中的属性(变量)也不是不能改变,使用类名.变量名的格式,可以让我们在类的外面,增加或修改类的属性:

类对象、实例对象
引用:通过引用对类的属性和方法进行操作
实例化:创建一个类的具体实例对象(如:学生张三)

一个简单的例子

# 定义一个学生类
class Student:
    def __init__(self, name, grade):
        self.name = name
        self.grade = grade

    def introduce(self):
        print("Hi, my name is ", self.name)
        print("My grade is ", self.grade)

    def improve(self, amount):
        self.grade = self.grade + amount

Jack = Student("Jack", 86)
Jack.introduce()
Jack.improve(10)
Jack.introduce()

给类方法传参

1)类方法 只使用 类中的属性(内部)

class Class1():
    val1 = 100
    val2 = 200
    
    @classmethod
    def func1(cls):
        print(cls.val1)
        print(cls.val2)

Class1.func1()

1)@classmethod的中文意思就是“类方法”,@classmethod声明了 func1 是类方法,这样才能允许func1使用类属性中的数据
2)cls的意思是class的缩写。如果类方法func1想使用类属性(也就是类中的变量),就要写上cls为函数1的第一个参数,也就是把这个类作为参数传给自己,这样就能被允许使用类中的数据。
3)cls.变量。类方法想使用类属性的时候,需要在这些变量名称前加上cls.

  • 当类中的函数【不需要】用到类中的变量时,就不要用@classmethod、cls、cls.三处格式,否则终端也会报错。

2)类方法 只使用外部传入的参数(外部)

直接使用即可
只使用了外部的参数,没有使用类属性,所以格式上不需要 @classmethod 和 cls 。

3)类方法 同时使用 类中的属性 和 外部传入的参数(内部 & 外部)

定义类方法的时候,传入多个参数,其中属于类属性的参数,还是要加 cls, 并且前面要加 @classmethod

修改类属性

1)从内部,用类方法去增加/修改
2)从外部,用类.变量 = xx直接增加/修改类属性。

类方法 不但能调用类中的属性,还能调用类中的其他方法

装饰器 decorator

#加上装饰器
def add_candles(add_function):
    def insert_candles():
        return add_function + "candles"
    return insert_candles()

@add_candles		#加上装饰器使原来的函数拥有一些附加上去的功能
def make_cake():
    return "cake"

print(make_cake())

二、类的实例化

变成实例对象的过程,就叫做实例化

注意:当类需要被实例化后使用时,相应的在方法中调用自身属性的参数,要从 cls 换成 self;并且 不再需要 @classmethod 的声明!

同样是上面的代码,如果是类被实例化了使用:

class Class1():
    val1 = 'abc'
    
    def func1(self):
        print('类属性的值是:', self.val1)

a = Class1()  #实例化
a.func1()  #实例化后再使用
b = Class1()  #可以实例化多个不同的实例
b.func1()  #实例化后再使用

1)当类支持实例化的时候,self是所有类方法位于首位、默认的特殊参数。
(不管该类方法中 是否使用到了类属性,需要实例化的类方法,必须使用 self 参数,作为参数首位 传入,否则会报错)
2)当类支持实例化的时候,就不能再直接使用类方法了
通常来说,我们都是把类实例化后再调用。(哪怕取一个和类名相同的实例名称也可以)

  • 当我们完成实例化后,对应于一个实例的属性和方法,叫“实例属性、实例方法”,不再称为“类属性、类方法”

类属性和实例属性

实例直接从类上继承过来的属性和方法,是完全相同的。
不过,我们可以修改类属性,这会导致所有实例属性变化(因为类是模板)

—— 修改实例属性,但这不会影响到其他实例,也不会影响到类。因为每个实例都是独立的个体。
—— 新增也是一样的道理,在类中新增属性会影响到实例,但在实例中新增属性只影响这个实例自己。
—— 当实例自己的属性已经修改过一次后,类的同一个属性 再发生修改,不会反映到该实例上

类方法

和类属性一样,我们可以重写类方法,这会导致所有实例方法自动被重写。

——“重写类方法”分成两个步骤:第一个步骤是在类的外部写一个函数,第二个步骤是把这个新函数的名字赋值给类.原始函数:
—— 我们可以通过重写类方法,让实例方法发生变化,但我们不能重写实例方法,模板给的技能不是说换就能换的。

  • 小结(属性和方法):
    1、修改类属性和类方法,将会影响所有实例
    2、修改某个实例的属性,只会影响这个实例自身
    3、不能修改实例的方法

初始化函数

—— 很实用的类方法
—— 初始化函数的意思是,当你【创建一个实例】的时候,这个函数就会被调用。上面的代码在执行实例 = 类()的语句时,就【自动调用】了__init__(self)函数。
—— 初始化函数的写法是固定的格式:中间是“init”,这个单词的中文意思是“初始化”,然后前后都要有【两个下划线】,然后__init__()的括号中,第一个参数一定要写上self,不然会报错。
——同时,这个初始化函数照样可以传递参数

class Class2():
    def __init__(self):
        print('实例化成功!')

a = Class2()

通过 初始化函数传递参数 例子
(这样生成不同的实例就方便了很多)

class StudentScore():
    def __init__(self,name,chinese_score,math_score):
        self.name = name
        self.chinese_score = chinese_score
        self.math_score = math_score

score1 = StudentScore('张三',99,88)
score2 = StudentScore('李四',64,73)
score3 = StudentScore('王五',33,22)

三、继承与多态

两个类, 如果非常相似,通过【继承】可以避免在创建新类时 又要写同样的代码。

类的单继承

—— 子类从一个父类继承类方法,我们叫做单继承
—— 在Python里,我们统一把旧的类称为父类,新写的类称为子类。子类可以在父类的基础上改造类方法,所以我们可以说子类继承了父类。

# StudentScore2 比 StudentScore,多了一个 打印总分的方法

class StudentScore2(StudentScore):
    def print_score(self):
        score = self.chinese_score + self.math_score
        print(self.name + '的总分是:' + str(score))

# 创建一个跟父类完全一样的子类
class StudentScore2(StudentScore):
    pass
# 父类
class Car:
    def __init__(self, number_of_wheels, seating_capacity, maximum_velocity):
        self.number_of_wheels = number_of_wheels
        self.seating_capacity = seating_capacity
        self.maximum_velocity = maximum_velocity

# 子类
class ElectricCar(Car):
    def __init__(self, number_of_wheels, seating_capacity, maximum_velocity):
        Car.__init__(self, number_of_wheels, seating_capacity, maximum_velocity)

# 对象
car = ElectricCar(1, 2, 3)
car.maximum_velocity
'''
3
'''

子类除了可以定制新的类方法,还能直接覆盖父类的方法,只要使用相同的类方法名称就能做到这一点。

—— 我们能在子类中重写覆盖任意父类方法,哪怕是 覆盖初始化函数__init__

类的多重继承

—— 还有一种更复杂的继承情况,叫多重继承,就是一个子类从多个父类中继承类方法。
—— 格式是class 子类(父类1,父类2,……)。
—— 不过,多重继承有利有弊。过度使用继承容易把事情搞复杂(如果不是开发大型项目,不太需要用到太复杂的继承关系)

四、封装

封装 ----> 限制直接访问目标属性和方法的机制, 将抽象性函数接口的实现细节部分包装, 隐藏起来的方法

同时, 防止外界调用端, 去访问对象内部实现细节的手段,这个手段是由编程语言本身提供的

对象所有的内部表征对于外部来说都是隐藏的,只有对象 能直接与内部数据交互 --> 需要理解 公开 public 和 私有 non-public 实例变量和方法

# 公开实例变量
class Person:
    def __init__(self, first_name):
        self.first_name = first_name

tk = Person('TK')
print(tk.first_name)
'''
TK
'''
# 对象可以管理其变量的值
tk.first_name = 'custom_name'
print(tk.first_name)
'''
custom_name
'''

# 修改对象的变量值,不会对新从父类继承的对象产生影响
tk2 = Person()
print(tk2.first_name)
print(tk.first_name)
'''
TM
custom_name
'''
print(tk.__dict__)
'''
{'first_name': 'custom_name'}
'''
print(Person.__dict__)
'''
{'__module__': '__main__', 'first_name': 'TM', '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
'''
tk.custom_attr = 'apple'
print(tk.__dict__)
'''
{'first_name': 'custom_name', 'custom_attr': 'apple'}
'''

私有变量 —> 我们可以使用功能constructor方法 或者在类的内部声明而定义一个私有实例变量, 语法上 需要在前面加上一个下划线

class Person():
    def __init__(self, first_name, email):
        self.first_name = first_name
        self._email = email
        
print(Person.__dict__)
'''
{'__module__': '__main__', '__init__': <function Person.__init__ at 0x11de6fe60>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
'''

tk = Person('TK', 'tk@email.com')
print(tk.__dict__)
'''
{'first_name': 'TK', '_email': 'tk@email.com'}
'''
print(tk._email)
tk._email = 'new_email@email.com'
print(tk._email)
'''
tk@email.com
new_email@email.com
'''

私有变量 —> 我们可以使用功能constructor方法 或者在类的内部声明而定义一个私有实例变量, 语法上 需要在前面加上一个下划线

class Person():
    def __init__(self, first_name, email):
        self.first_name = first_name
        self.__email = email
    def get_email(self):
        return(self.__email)
    def set_email(self, new_email):
        self.__email = new_email
        
print(Person.__dict__)
'''
{'__module__': '__main__', '__init__': <function Person.__init__ at 0x11dedfb00>, 'get_email': <function Person.get_email at 0x11dedf830>, 'set_email': <function Person.set_email at 0x11dedfef0>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
'''

tk = Person('TK', 'tk@email.com')
print(tk.__dict__)
# print(tk.__email)
# tk._email = 'new_email@email.com'
# print(tk.__email)
'''
{'first_name': 'TK', '_Person__email': 'tk@email.com'}
'''


print(tk.get_email())
tk.set_email('new_email')
print(tk.get_email())
'''
tk@email.com
new_email
'''
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值