类和对象

1|0一. 类和对象的概念


1|1概念:


面向对象的两个最重要的概念:类和对象

:共性事物的抽象,是对某一类具有共性事物的描述,是概念上的定义

对象:对象是共性事物的一个体现,是这类事物的每个个体,或者说是类的一个实例(instance)

 

1|2总结:


类是对象的模板,对象是类的实例

 

1|3类结构:


里面包含属性与函数

 

数据是对象的状态-->成员变量(属性)

方法是对象的行为-->函数(方法)

2|0二. 语法


#创造类的语法 class Math: a = 4 #属性 b = 5 def add(self): #方法 c = self.a + self.b return c

注意:1) 类名一般首字母大写,比如 class User    #class是关键字

     2) 类里面包含属性和方法

   3) 类函数自带self关键字(指向类的实例)。不能少!

   4) 如果类函数里面要调用属性,方法: self.属性名, self.方法名

 

2|1实例:


class Friend: height = None weight = None age = None money = None #定义功能——会做饭 def canCook(self, can=True): if can == True: print("我会做饭。。。") else: print("我不会做饭。。。") def canGetMoney(self): print("我会挣钱。。。") def setAge(self, age): self.age = age print("年龄为:", self.age) def setHeight(self, height): self.height = height print("身高为:", self.height) def setWeight(self, weight): self.weight = weight print("体重为:", self.weight) def setMoney(self, money): self.money = money print("资产为:", self.money) #对象一:身高180,会做饭,做挣钱,有200万的资产,而且才29岁 #实例化:类名() danqing = Friend() danqing.setAge(29) print(danqing.age) danqing.setMoney(2000000) print(danqing.money) danqing.canCook() print("===========================") #对象二:身高175,不会做饭,年龄只有25岁,资产5万 dancf = Friend() #改变对象的属性 dancf.setAge(25) print(dancf.age) dancf.setMoney(50000) print(dancf.money) dancf.setHeight(175) print(dancf.height) dancf.canCook(False)

运行结果:

年龄为: 29 29 资产为: 2000000 2000000 我会做饭。。。 =========================== 年龄为: 25 25 资产为: 50000 50000 身高为: 175 175 我不会做饭。。。

3|0三. 初始化函数的调用


初始化函数:def __init__(self, 参数1, 参数2, 参数3)

__init__函数,是两个下划线!经常会写错,写成单下划线,这样会报错!

 

3|1用法:


def __init__(self, a, b): self.a = a self.b = b self.c = 10

3|2注意:


1) 初始化里面做的是初始化操作,可以带参数也可以不带参数

2) 跟普通函数一样,可以带默认参数

3) 初始化里面可以有赋值好了的属性值

4) 每次创造一个实例,需要传递跟初始化函数参数个数一致的值

5) 每个实例都会自动调用初始化函数

6) 初始化参数的写法要注意,怎么把参数赋值给self.参数名,参数名字不一定要一致,但是赋值要正确

 

3|3实例1:


class Friend: def __init__(self, age, sex, height): self.age = age self.sex = sex self.height = height #定义功能——会做饭 def canCook(self, can=True): if can == True: print("我会做饭。。。") else: print("我不会做饭。。。") def canGetMoney(self): print("我会挣钱。。。")
xiaozhai
= Friend(26, "", 178) jian = Friend(18, "", 155)

3|4实例2:类也可以没有初始化


class Friend: #定义功能——会做饭 def canCook(self, can=True): if can == True: print("我会做饭。。。") else: print("我不会做饭。。。") def canGetMoney(self): print("我会挣钱。。。") def setAge(self, age): self.age = age print("年龄为:", self.age) def setHeight(self, height): self.height = height print("身高为:", self.height) def setWeight(self, weight): self.weight = weight print("体重为:", self.weight) def setMoney(self, money): self.money = money print("资产为:", self.money) jian = Friend() print(jian.age) 运行结果: Traceback (most recent call last): File "D:/python_workshop/python6/revise/类和对象(一).py", line 63, in <module> print(jian.age) AttributeError: 'Friend' object has no attribute 'age'

当直接调用函数后,再打印属性发现有age了,因为函数setAge里生成了一个全局属性age

jian = Friend() jian.setAge(25) print(jian.age) 运行结果: 年龄为: 25 25

 

4|0四. 类的继承


 

1. 子类拥有父类的所有属性和行为

2. 子类可以扩展自己的属性和行为

3. 父类的行为不够用,子类要升级和优化,子类可重写父类的方法——多态

4. 子类和父类都有的行为:子类实例优先使用自己的,没有再去用父类的

 

4|1支持多继承


多继承语法:用逗号隔开父类

      class 子类类名(父类1, 父类2):

class Son(Father, Mother):   def __init__():     XXXX

4|2实例


class Father: def __init__(self, id, name, sex, age): self.id = id self.name = name self.sex = sex self.age = age def eat(self, food): print("eat:", food) def earnMoney(self, money): print("Father earn money:", money) class Mother: def sing(self): print("xxxxxx") def earnMoney(self, money): print("Mother earn money:", money) #子类继承了两个类的所有属性和方法 class Son(Father, Mother): #方法重写,调用该方法时会调用自己的方法 def eat(self, food): print("eat:", food) print("我吃的更快,比father更快!!!") def dance(self): print("xxxxxx") #子类没有定义的初始化方法,但是父类定义了初始化方法 #则子类实例化时会调用父类的初始化方法 jian = Son(123, "jian", "male", 22) jian.eat("apple") #当子类继承了多个类中同样的方法时,子类会优先使用第一个继承类的方法(从左向右) jian.earnMoney(2000) #父类实例化 jianBB = Father(111, "li", "male", 56) jianBB.eat("orange")

运行结果

eat: apple 我吃的更快,比father更快!!! Father earn money: 2000 eat: orange

 

4|3继承—super用法


在子类的行为中,想调用父类的行为,然后再做额外扩展,可以使用super类

语法:super().行为(参数)

 

class Son(Friend):   def __init__(self, age, sex, name):     super().__init__(age, sex)     #Friend.__init__(age, sex) 这样也可以     self.name = name

 

5|0五. 封装数据


 

5|1实现方式:遵循一定的属性和方法命名规约


不希望这些变量或者方法被外部使用

 

5|2• 任何以单下划线_开头的名字都应该是内部实现


即不希望通过实例名字,变量名/方法名来调用,但是python并不会真的阻止别人访问内部名称,子类也可以继承并重写父类的方法,只是一种约定

 

5|3• 以双下划线__开头的名字,仅类自己可访问


继承——这种方法通过继承是无法被覆盖(重写)的。其实也是可以访问的,只不过换成了_类名__变量名/函数名

 

class MyClass: def __init__(self): self._private_data1 = "私有方式一" self.__private_data1 = "私有方式二" pass def _pri_func(self): print("私有方法一") def __pri_func(self): print("私有方法二") def public_func(self ): print("公开方法") #类内部调用自己的私有方法一 self._pri_func() mc = MyClass() #仍然可以调用单下划线的属性和方法,只不过作为一种约定,告诉别人请不要这样调用 mc._pri_func() mc._private_data1 #mc.__private_data2 双下划线的方法无法调用 class SonClass(MyClass): #子类继承父类的单下划线私有方法并重写,也是可以的 def _pri_func(self): print("我是子类的私有方法") #子类无法继承父类的双下划线私有方法并重写,运行时报错 def __pri_func(self): print("我是子类的私有方法二") son = SonClass() son.__pri_func()

运行结果

Traceback (most recent call last): File "D:/python_workshop/python6/revise/私有属性和方法.py", line 37, in <module> son.__pri_func() AttributeError: 'SonClass' object has no attribute '__pri_func' 私有方法一

 

5|4哪种方式好


两种不同的编码约定(单下划线和双下划线)来命名私有属性,问题就来了:到底哪种方式好呢?

大多数而言,你应该让你的非公共名称以单下划线开头,但是,如果你清楚你的代码会涉及到子类,并且有些内部属性应该在子类中隐藏起来,那么才考虑使用双下划线方案

 

6|0六. @property和@属性名.setter


实例属性,除了访问和修改之后,增加其他逻辑处理,如合法性等

@property #获取属性值:实例.属性名 def age(self): return self._age @age,setter #给属性赋值时添加了逻辑处理 def age(self.age): if age in range(0, 121 ): self._age = age else: print("输入的年龄不符合要求哦!!")

6|1实例


class People: #age是people类的属性名 @property def age(self): return self._age @age.setter def age(self, age): if age in range(0, 121): self._age = age print(self._age) else: print("年龄不符合要求") p = People() p.age = 134

运行结果:

年龄不符合要求

 

6|2注意:


不能写成return self.age和self.age = age,原因如下

class People: ''' ========================================== @property和@属性名.setter可以用来对属性的值进行一定的逻辑处理。 但是: @property和@属性名.setter的小坑 =========================================== 在以下代码中,setter函数表示:当你使用self.age时就会自动的去调用setter 所以在@age.setter对应的函数中,else操作中,有使用self.age。 所以,这里的self.age相当于又去调用了setter,即又去调用了自己。就进入了一直在调用自己的状态。 于是,就会报错:递归次数超限制。 这个是个坑!!! 如何解决这个问题呢?如果设置可以爬出这个坑呢?? @property def age(self): return self.age @age.setter def age(self,age): if age not in range(0,121): print("age is not valid data") else: self.age = age ============================================ ================以下是爬坑策略==================== 为了不要重复的来调用自己,也就是在@age.setter对应的函数当中,不要使用self.age 所以用了另外一个变量名:self._age。这样子就不会一直调用。 ====代码不同之处 一:@property对应的函数中,return self._age ======= ====代码不同之处 二:@age.setter对应的函数中,else:self._age = age ======= 对外部使用者而言,还是age属性,即可以通过实例名.age来设置值。 对类内部而言,就是_age属性了。 以下是代码部分 ''' def __init__(self,name,sex): self.name = name self.sex = sex @property def age(self): return self._age @age.setter def age(self,age): if age not in range(0,121): print("age is not valid data") else: self._age = age p = People("jian","female") p.age = 100 print(p.age) p.age = 122 print(p.age)

 

 

 


__EOF__

本文作者cnhkzyy
本文链接https://www.cnblogs.com/my_captain/p/9243168.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   cnhkzyy  阅读(335)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示