Python面向对象

面向对象的两个概念

  • 类和对象

1.类class

  • 一个模块里面可以定义多个类 ,但是一个类只能在一个模块里面定义

类的命名规范(与变量的命名规则不同)

1.首字母大写
2.用多个英文单词组合命名时,不建议用下划线,而用驼峰命名法,例如:StudentUser;
如:class StudentUser():

类定义后可以填哪些内容:

1.可以定义若干个变量
2.可以定义若干个函数

举例:

class Student():
      name = 'ZXY'
      age = 18
      def print_file():
          print('name:'+name)
          print('age:'+str(age))

如何引用一个类:

实例化一个类,得到一个对象

举例:

student1 = Student() ----- 此时,student1就是一个对象

如何调用一个类中的方法:

思考:为什么叫方法,不叫函数(不必过于纠结)

对象名.函数名()

举例:

student1.print_file()

尝试运行之后,发现会报错
原因:print_file()函数定义时,没有加self关键字

在函数的列表里一定要加入self
def print_file(self):
同样函数里引用的变量,也要加self来引用
print('name:'+self.name)
print('age:'+str(self.age))

完整的代码应该是这样:

class Student():
      name = 'ZXY'
      age = 18
      def print_file(self):
          print('name:'+self.name,end=' ')
          print('age:'+str(self.age))
student1 = Student()
student1.print_file()
#输出:name:ZXY age:18

注意:调用方法不能在类的内部调用,因为类只负责定义,不能执行;类的作用是封装,如果把执行也放入类里面,那这个封装就毫无意义

在外部模块里调用这个模块的类

假设这个模块名字叫test

from test import Student
student2 = Student()
student2.print_file()

回应上面的思考:为什么叫方法,不叫函数

在C和C++中,称为函数;在java和C#中,称为方法
方法:更多是设计层面,面向对象的开发,需要更多结构和封装的设计
函数:更多是过程层面,面向过程
同样,类里面的变量也不称为变量,而叫做数据成员

类的基本定义:

类是现实世界或思维世界中的实体在计算机中的反映
它将数据以及这些数据的操作封装在一起

还是以上面那段代码为例:

class Student():
      name = 'ZXY'
      age = 18

行为特征

思考:把print_file这个方法放在Student这个类下面合适吗

答:不合适,因为print_file的主体不是Student,而应该是Printer
行为没有搞对主体是很多情况设计面向对象时出现的问题

def print_file(self):
    print('name:'+self.name,end=' ')
    print('age:'+str(self.age))

修改后重新设计:

class Student():
      name = 'ZXY'
      age = 18
      def say_hello(self):
          print('hello, my name is ' + self.name)

2.对象

上面的的将一个类实例化,就得到一个对象

student1 = Student()

类更像一个模板,可以创造出各个不同的对象,但这些对象都有共同的特性
但就上面的代码,创造的student1、student2、student3,它们的值在逻辑上都是相同的,但在计算机里面它们的id并不同

那怎么让这三个对象在实例化之后变得不同呢

直接用关键字参数改实例化的参数是不行的
student1 = Student(name='ABC',age=15)---------错误的示范

要在原来的类里面定义另外的函数__init__
这个名字是固定的,不能改,一般称之为 构造函数

class Student():
      name = 'ZXY'
      age = 18
      def __init__(self): //构造函数,同样不能忘记加入self
          print('student')

      def say_hello(self):
          print('hello, my name is ' + self.name)
student1 = Student()
student1.__init__()
#输出:student 
      student  ----------思考:为什么会输出两遍

答:在定义构造函数的时候会自动调用一次,所以后面很少会手动再去调用这个构造函数

进一步思考:a = student1.__init__();print(a)会输出什么

None-----因为上面的__init__中没有return值

设置了return 'StudentUser',结果报错了
说明,构造函数本身不允许返回None以外的值

构造函数的作用

如何输出任意的变量值,即创造不同的对象

class Student():
    name = 'ZXY'
    age = 18
    def __init__(self,name,age):   
    #可以在构造函数里放入前面的变量,在实例化的时候就可以改变变量的值
          print('student')

    def say_hello(self):
        print('hello, my name is ' + self.name)

student1 = Student(name='ABC',age=12)  
#一定要传入前面构造函数里的两个变量,不传入还保持空会报错
student1.say_hello()

#输出:student  
      hello, my name is ZXY
#还是会输出一次__init__里的内容,因为构造函数里有print命令,实例化的时候会先执行构造函数
#而且name值还是没改变

优化:
在构造函数里初始化类的特征值

class Student():
   name = 'ZXY' # ?全局变量
   age = 18

   def __init__(self,name,age):
   name = name     
   #这句话的意思就是,把后面'name'这个参数值传给前面这个'name'变量   
   //局部变量,局部变量并不会覆盖全局变量
   age = age  
   #后面这个参数就来源于def __init__(self,name,age)括号里这个,尽量就保持和前面的变量同名

   def say_hello(self):
       print('hello, my name is ' + self.name)

student1 = Student('ABC',12)
print(student1.name)

#输出:ZXY
不是想要的ABC,思考问题,创造函数的实例变量要加self

全局变量和局部变量

变量的作用域

c = 50
def add(x,y):
    c = x + y
    print(c)
add(10,20)
Sprint(c)

#输出:30
      50
由于在函数内部有print命令,所以先输出了c=x+y的结果,再输出了全局变量c

说明内部变量c没有覆盖全局变量c,这两个是互相独立的变量,互不影响

说明:在函数内部定义的变量,在函数外部是无法访问的,函数内部定义的变量,在函数外部是无法访问的
如果要把外部的全局变量也改变,需要在函数内部声明c是全局变量:用global

c = 50
def add(x,y):
    global c
    c = x + y
    print(c)
add(10,20)
print(c)

#输出:30
      30
全局变量改变了

类中的类变量和实例变量

class Student():
    name = 'ZXY'  #类变量,不同对象的特征值不能改变这个变量
    age = 18  
    #和其他语言不同,其他语言这个位置放的是实例变量,但是Python里,这个位置放的是类变量

    def __init__(self, names, ages):  
    #改为names和ages在这里更有助于理解,实际应用中还是要和前面的变量名一致
        self.name = names  
        #实例变量,使用self.name,来保存name这个特征值
        #self这个值不是固定不变的,可以取任意的名字,但后面都要保持一致
        self.age = ages  
        #实例变量只和对象相关,和类无关

student1 = Student('ABC', 8)
print(student1.name)
print(Student.name)

#输出:ABC
      ZXY
说明Student类里面的变量name没变,但是student1的name变了

print(student1.__dict__)
#输出:{'name': 'ABC', 'age': 8} ---------不是names和ages,而是类变量的名字

在创造函数中,print(name)-------会报错;
print(names)-------输出ABC; 
print(self.name)-------输出ABC

name和age都应该是实例变量,不应该放在类变量这个抽象的描述里,类变量不应该设置为具体的特征值,应该是更宏观上的东西,比如sum总数

在构造函数中引用类变量除了print(self.name)还可以这么写:

1.print(Student.name);
2.print(self.__class__.name)

举例:

class Student():
    sum1 = 0

    def __init__(self, names, ages):
        self.name = names
        self.age = ages
    Student.sum1 += 1  
    #也可以写成:self.__class__.sum1 += 1;
    #但不能写成:self.sum1 += 1 ; 猜测是self引用不能用于计算

    print('当前班级总人数为: '+self.sum1)    
    #也可以写成:self.__class__.sum1 以及 Student.sum1

    def say_hello(self):
        print('hello, my name is ' + self.name)

student1 = Student('A', 8)
student2 = Student('B', 8)
student3 = Student('C', 8)
#报错---------因为self.sum1是int类型

#应该改为str类型:print('当前班级总人数为: '+str(self.sum1))
#输出:当前班级总人数为: 1 
      当前班级总人数为: 2 
      当前班级总人数为: 3

#如果写成 self.sum1 += 1-----------返回结果都是1

类方法:@classmethod

类方法可以用来直接调用类变量,而不需要实例化,类方法以@classmethod开头,类方法用于操作类变量

语法糖装饰器
用类方法实现上面的在实例方法里增加学生数的操作:

calss Student():
    sum1 = 0
    @classmethod    #这个在python里称为 装饰器
    #要有@classmethod,否则下面定义的不是类方法,而是实例方法,因为self是可以改变名字的
    def plus_sum(cls):
        cls.sum1 += 1
        print('当前班级总人数为: '+str(cls.sum1))
        #但是这个和构造函数不同,类方法不能直接调用,需要用类名调用,所以要写成:Student.plus_sum(),用类去调用类方法

student1 = Student()
Student.plus_sum()
#输出:当前班级总人数为: 1

也可以用对象调用类方法,是可以运行的,但逻辑上说不通,最好不要用

静态方法:@staticmethod

静态方法不像类方法和实例方法,它不需要创建cls,self这样的名字,cls代表类本身,self代表对象本身

class Student():
    @ststcimethod
    def add(x,y):
        return x + y
student1 = Student()

#类和对象都可以调用静态方法:
Student.add(1,2)
student1.add(1,2)

类方法和静态方法都不能引用实例方法里的变量,即都不能使用self.name引用实例变量name,但可以引用类变量

  • 静态方法功能基本和类方法一致,但是和面向对象的关联性比较弱,不要经常去使用静态方法

变量的内部调用和外部调用

class Student():
    name = 'ZXY'
    age = 18
    def __init__(self,name,score):
        self.name = name
        self.score = 0
    def marking(self,score):
        self.score = score
        print(self.name + '的分数为:' + str(self.score))
student1 = Student('abc',90) #注意第二个参数是score,而不是age

#外部调用:student1.score = -1 -------外部调用变量是很不安全的
#内部调用:student1.marking(60) ------内部调用就不用直接改变量值,是调用的方法,因为方法里可以用条件语句控制输入的值的范围

例如:

class Student():
    name = 'ZXY'
    age = 18
    def __init__(self,name,score):
        self.name = name
        self.score = 0
    def marking(self,score):
        if score < 0:
            return '不能打负分'
        self.score = score
        print(self.name + '的分数为:' + str(self.score))
student1 = Student('abc',16)
result = student1.marking(-1)
print(result)
#输出:不能打负分
#所以用调用方法的方式改变量更加安全

但是现在问题是,即使设置了一个marking函数,还是不能防止别人从外部更改内部变量,有没有什么方法能防止外部读取变量呢?

成员的可见性

概念:公开的public和私有的private,公开的函数或者变量是可以在外部读取或者更改的,而私有的函数和变量是无法在外部读取和更改的

在其他语言里设置变量都需要在前面加上public和private,明确的表示了这个变量是公开的还是私有的,但是python不是,所以其他语言是更加直观的

python里面,创建的函数名称和变量名称前面,如果没有双下划线__,就说明这个函数和变量是公开的,加了__才是私有的,构造函数__init__除外,其实前后都加__反而不是私有的

举例:

class Student():
    name = 'ZXY'
    age = 18
    def __init__(self,name,score):
        self.name = name
        self.score = 0
    def __marking(self,score):
        if score < 0:
            return '不能打负分'
        self.score = score
        print(self.name + '的分数为:' + str(self.score))
student1 = Student('abc',90)
result = student1.__marking(-1)
print(result)
#结果为报错,说__marking函数不存在 

但是这样就不能调用marking函数了,如果不是把marking函数变为私有,而是把score变量变为私有呢

举例:

class Student():
    name = 'ZXY'
    age = 18
    def __init__(self,name,__score):
        self.name = name
        self.__score = 0
    def marking(self,score):
        if score < 0:
            return '不能打负分'
        self.__score = score
        print(self.name + '的分数为:' + str(self.__score))
student1 = Student('abc',90)
student1.__score = -1
print(student1.__score)

还是能输出 -1 ; 这是为什么呢?
实际上并不是score没有变成私有变量,而是由于python的动态特性,在student1.__score = -1的时候,给student1添加了一个新的属性__score

student2 = Student('qwe',90)
print(student2.__score)
#说找不到__score,说明上面的__score并不是全局变量,而是student1的局部变量,也就是说函数里的__score其实并没有改变

print(student1,__dict__)
#现在就可以更明显的看出来了,原来的__score私有变量被改名为'_student__score',而多出了一个'__score'的变量,它的值为-1

其实这里就可以看出来所谓的私有变量到底是这么回事了,是把原来的__变量名改名为了_类名__变量名,所以在外部调用原来的变量名是提示找不到该变量

没绷住,python的私有转换实在太捞了,只能靠自觉,不去访问

面向对象三大特性

1.继承性
2.封装性
3.多态性

1.继承性

举例:
H.py模块里建立了类Human , 在S.py模块的类Student里继承类Human

from H import Human
class Student(Human):
#上面就是最标准的继承表示方法,Human是Man的父类,Man是Human的子类
#在 M.py模块里可以直接引用Human里的变量
#而且在实例化的时候要输入Human里的必要参数

继承的好处就是一个父类可以被多个子类引用,不必重复书写
一个子类可以继承多个父类,但需要保证不出问题

H.py的内容:

class Human():
    sum = 0
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def print_name(self):
        print(self.name)

S.py的内容:

from H import Human
class Student(Human):
      def __init__(self,school,name,age):  #这里记得也要加入父类里要调用的变量,这里是name
          self.school = school
          Human.__init__(self,name,age)   #可以直接引用类Human里的方法以引用变量,格式为:父类名.父类函数名(self,xxx,xxx) ; 记得这里依然要加self,不然会报错
      def do_homework(self):
          print('homework has been done')
student1 = Student('人民路小学','小红',10)
print(student1.name)
print(student1.age)

父类名.父类函数名(self,xxx,xxx)这个方法最好不要用,因为如果这个子类Student更换了父类,而下面有很多方法都调用了父类里的方法,要改非常多的地方,非常不建议这么做

关于self:

上面的父类名.父类函数名(self,xxx,xxx),是必须要加self的,而用实例化的对象去引用函数的时候是不用加self的,因为self就是指代的对象,在用类调用的时候,是没有指定对象的,所以要加self
可以用Student.do_homework()这样来调用试试,肯定会报错,提示没有传入self
但可以Student.do_homework(student1),可是这样完全是多此一举,还是建议用student1.do_homework()

优化 S.py

from H import Human
class Student(Human):
    def __init__(self,school,name,age):
        self.school = school
        super(Student,self).__init__(name,age)   
        #推荐使用这种方法调用父类里的方法,格式为:super(子类名,self).父类函数名(xxx,xxx,xxx),要包含所有父类方法里的变量,不然会报错

    def print_name(self):      
    #子类里的方法可以和父类里的方法同名,只是调用方法不同
        print('my name is ' + self.name)
student1 = Student('人民路小学','小红',10)
student1.print_name()     
#思考:这里是调用了Human里的print_name 还是Student里的print_name
#输出:my name is 小红 ----------- 说明调用了Student里的print_name

那怎么调用Human里的print_name呢?

from H import Human
class Student(Human):
    def __init__(self,school,name,age):
        self.school = school
        super(Student,self).__init__(name,age)

    def print_name(self):
        super(Student,self).print_name()  # ?这是方法,在执行student1.print_name()的时候会按这里的顺序执行print_name;这里是先执行父类的print_name,再执行子类的
        print('my name is ' + self.name)
student1 = Student('人民路小学', '小红', 10)
student1.print_name()
#输出:小红     
      my name is 小红
  • 22
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python面向对象编程是一种编程范式,它将程序组织成对象的集合,每个对象都有自己的属性和方法。在Python中,可以通过定义类来创建对象,并通过实例化类来创建具体的对象。引用[1]中的代码示例展示了一个Animal类,其中包含了初始化方法和一个__str__方法来返回对象的描述信息。通过这个类,可以创建Animal对象,并通过print函数输出对象。引用中的代码示例展示了如何使用@property装饰器来定义类的属性和属性的访问方法。通过这种方式,可以在访问属性时像访问普通属性一样使用点号,而不需要使用方法调用的方式。引用中的代码示例展示了多态在Python中的应用。多态是面向对象编程的重要概念,它允许不同的对象以相同的方式对外部访问,但具体的实现可能不同。在这个示例中,father、son和daughter类都继承了father类,并重写了tell方法。通过调用不同的对象的tell方法,可以看到不同的输出结果。总之,Python面向对象编程是一种灵活且强大的编程方式,它允许开发者以对象为中心来思考和组织代码,提高了代码的可读性和可维护性。通过定义类、创建对象和使用类的属性和方法,可以实现丰富多样的功能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Python面向对象(全套)](https://blog.csdn.net/Thewei666/article/details/126652501)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值