Python--类(讲解)
后台-插件-广告管理-内容页头部广告(手机) |
Python类
1、面向对象:
根据类来创建对象称为实例化 ,这让你能够使用类的实例。
面向对象编程(Object-oriented Programming,简称 OOP),是一种封装代码的方法。
代码封装,其实就是隐藏实现功能的具体代码,仅留给用户使用的接口,就好像使用计算机,用户只需要使用键盘、鼠标就可以实现一些功能,而根本不需要知道其内部是如何工作的。
在 Python 中,所有的变量其实也都是对象,包括整形(int)、浮点型(float)、字符串(str)、列表(list)、元组(tuple)、字典(dict)和集合(set)。
面向对象中,常用术语包括:
- **类:可以理解是一个模板,通过它可以创建出无数个具体实例。**比如,前面编写的 tortoise 表示的只是乌龟这个物种,通过它可以创建出无数个实例来代表各种不同特征的乌龟(这一过程又称为类的实例化)。
- **对象:类并不能直接使用,通过类创建出的实例(又称对象)才能使用。**这有点像汽车图纸和汽车的关系,图纸本身(类)并不能为人们使用,通过图纸创建出的一辆辆车(对象)才能使用。
- **属性:类中的所有变量称为属性。**例如,tortoise 这个类中,bodyColor、footNum、weight、hasShell 都是这个类拥有的属性。
- **方法:类中的所有函数通常称为方法。**不过,和函数所有不同的是,类方法至少要包含一个 self 参数(后续会做详细介绍)。例如,tortoise 类中,crawl()、eat()、sleep()、protect() 都是这个类所拥有的方法,类方法无法单独使用,只能和类的对象一起使用。
2、定义类:
类的使用顺序:
- 创建(定义)类。
- 创建类的实例对象,通过实例对象实现特定的功能。
语法:
class 类名: 多个(≥0)类属性... 多个(≥0)类方法...- 1
- 2
- 3
注意:无论类属性还是类方法,都不是必须的,还有就是类属性和类方法的位置是任意的,没有固定的先后顺序。但一般都是属性在前,方法在后。
class TheFirstDemo(): """ 第一个python类 """ # 定义类属性: name = "萧楚河" # 定义say类方法: def say(self, content): print(content)- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
注意:定义在类里面的属性称为类属性,定义在类方法中的属性称为实例属性。
3、_ _ init _ _()类构造方法:
构造方法用于创建对象时使用,每当创建一个类的实例对象时,Python 解释器都会自动调用它。
语法:
def __init__(self,...): 代码块- 1
- 2
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
4、创建和使用类:
class initDemo(): """ 构造方法练习 """ name = 'jack' # 构造方法: def __init__(self, school, age): print(f"学校名字是:{school}, 今年{age}岁了。") # 定义say 方法 def say(self): print("我是say 方法。") pp2 = initDemo("师范附中", 21) # 学校名字是:师范附中, 今年21岁了。 pp2.say() # 我是say 方法。- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
在创建对象时,隐式的调用 __init()__方法。并且里面的self 不需要传参。
定义的类只有进行实例化,也就是使用该类创建对象之后,才能得到利用。
-
访问 或 修改类对象具有的实例变量,甚至可以添加新的实例变量或者删除已有的实例变量;
-
调用类对象的方法,包括调用现有的方法,以及给类对象动态添加方法。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
5、self 的用法:
无论是显式创建类的构造方法,还是向类中添加实例方法,都要求将 self 参数作为方法的第一个参数。
Python 只是规定,无论是构造方法还是实例方法,最少要包含一个参数,并没有规定该参数的具体名称。之所以将其命名为 self,只是程序员之间约定俗成的一种习惯,遵守这个约定,可以使我们编写的代码具有更好的可读性。
通过 self 参数,它就相当于每个房子的门钥匙,可以保证每个房子的主人仅能进入自己的房子(每个类对象只能调用自己的类变量和类方法)。
同一个类可以产生多个对象,当某个对象调用类方法时,该对象会把自身的引用作为第一个参数自动传给该方法,换句话说,Python 会自动绑定 类方法的第一个参数 指向 调用该方法的对象 。
# self 的使用 class Slee(): """ self详解 """ def __init__(self): print("调用构造函数") def say(self): print(self, "学习self的作用。") lili = Slee() lili.say() # <__main__.Slee object at 0x000002049B8466B0> 学习self的作用。 xiaom = Slee() xiaom.say() # <__main__.Slee object at 0x000002049B846650> 学习self的作用。- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
对于构造函数中的 self 参数,其代表的是当前正在初始化的类对象。
class Person(): """ 定义一个person类 """ name = "xxxx" def __init__(self, name): self.name = name pp = Person('tom猫') print(pp.name) # tom猫- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
6、类变量和实例变量:
-
类体中、所有函数之外:此范围定义的变量,称为类属性或类变量;
-
类体中,所有函数内部:以“self.变量名”的方式定义的变量,称为实例属性或实例变量;
-
类体中,所有函数内部:以“变量名=变量值”的方式定义的变量,称为局部变量。
和类变量不同,通过某个对象修改实例变量的值,不会影响类的其它实例化对象,更不会影响同名的类变量。
class Person(): """ person类 """ name = '小明' url = 'www.baidu.com' def __init__(self): self.name = 'linux' self.url = 'hello,linux' def say(self): self.age = 13 # 实例对象1 p01 = Person() p01.name = 'java' p01.url = 'java is very good.' print(p01.name , p01.url) # 实例对象2 p02 = Person() print(p02.name, p02.url) # 类变量 print(Person.name) print(Person.url)- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
Python 只支持为特定的对象添加实例变量。
通常情况下,定义局部变量是为了所在类方法功能的实现。需要注意的一点是,局部变量只能用于所在函数中,函数执行完成后,局部变量也会被销毁。
class Sum(): """ 求和类 """ def sum(self, num): s = 0.8 * num print(f"价格为:{s}") ss = Sum() ss.sum(10) # 8- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
7、实例方法、静态方法和类方法:
采用 @classmethod 修饰的方法为类方法;采用 @staticmethod 修饰的方法为静态方法;不用任何修改的方法为实例方法。
构造方法也是一种实例方法。
其中 @classmethod 和 @staticmethod 都是函数装饰器。
- 实例方法:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 类方法:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
类方法推荐使用类名直接调用,当然也可以使用实例对象来调用(不推荐)。
- 静态方法:
静态方法,其实就是我们学过的函数,和函数唯一的区别是,静态方法定义在类这个空间中,而函数则定义在程序所在的空间中。
静态方法没有类似 self、cls 这样的特殊参数,因此 Python 解释器不会对它包含的参数做任何类或对象的绑定。也正因为如此,类的静态方法中无法调用任何类属性和类方法。
# 静态方法: @staticmethod def show(name, age): print(f"姓名是:{name},年龄是:{age}") Person.show('小明', 21) # 姓名是:小明,年龄是:21 pp.show('小红', 19) # 姓名是:小红,年龄是:19- 1
- 2
- 3
- 4
- 5
- 6
- 7
用类的实例对象访问类成员的方式称为绑定方法,而用类名调用类成员的方式称为非绑定方法。
8、类特殊方法:
1、repr()方法:显示属性:
通常情况下,直接输出某个实例化对象。
class CLanguage: pass clangs = CLanguage() print(clangs) # <__main__.CLanguage object at 0x000001A7275221D0>- 1
- 2
- 3
- 4
如果想输出该对象的基本信息,例如该对象有哪些属性,它们的值各是多少等等。
class CLanguage: def __init__(self): self.name = "C语言中文网" self.add = "http://c.biancheng.net" def __repr__(self): return "CLanguage[name="+ self.name +",add=" + self.add +"]" clangs = CLanguage() print(clangs) # CLanguage[name=C语言中文网,add=http://c.biancheng.net]- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
repr() 方法是类的实例化对象用来做“自我介绍”的方法,默认情况下,它会返回当前对象的“类名+object at+内存地址”,而如果对该方法进行重写,可以为其制作自定义的自我描述信息。
2、 del()方法:销毁对象:
如果之前创建的类实例化对象后续不再使用,最好在适当位置手动将其销毁,释放其占用的内存空间(整个过程称为垃圾回收(简称GC))。
class CLanguage: def __init__(self): print("调用 __init__() 方法构造对象") def __del__(self): print("调用__del__() 销毁对象,释放其空间") clangs = CLanguage() del clangs大多数情况下,Python 开发者不需要手动进行垃圾回收,因为 Python 有自动的垃圾回收机制(下面会讲),能自动将不需要使用的实例对象进行销毁。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
3、dir()用法:列出对象的所有属性(方法)名:
dir() 函数,可以列出某个对象拥有的所有的属性名和方法名,该函数会返回一个包含有所有属性名和方法名的有序列表。
# __dir__()方法的用法 class Person: def __init__ (self,): self.name = "C语言中文网" self.add = "http://c.biancheng.net" def say(self): pass pp = Person() print(dir(pp)) ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'add', 'name', 'say']- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
注意:通过 dir() 函数,不仅仅输出本类中新添加的属性名和方法(最后 3 个),还会输出从父类(这里为 object 类)继承得到的属性名和方法名。
dir() 函数的内部实现,其实是在调用参数对象 dir() 方法的基础上,对该方法返回的属性名和方法名做了排序。
4、__dict__属性:查看对象内部所有属性名和属性值组成的字典:
# __dict__()方法 class Person(): a = 1 b = 2 def __init__(self): self.name = '萧楚河' self.age = 21 print(Person.__dict__) pp = Person() print(pp.__dict__) {'__module__': '__main__', 'a': 1, 'b': 2, '__init__': <function Person.__init__ at 0x000001E501CFA710>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None} {'name': '萧楚河', 'age': 21}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
对于具有继承关系的父类和子类来说,父类有自己的 dict,同样子类也有自己的 dict,它不会包含父类的 dict。
借助由类实例对象调用 dict 属性获取的字典,可以使用字典的方式对其中实例属性的值进行修改。
注意,无法通过类似的方式修改类变量的值。
5、setattr()、getattr()、hasattr()函数:
1、hasattr() 函数
用来判断某个类实例对象是否包含指定名称的属性或方法。
hasattr(obj, name)- 1
其中 obj 指的是某个类的实例对象,name 表示指定的属性名或方法名。同时,该函数会将判断的结果(True 或者 False)作为返回值反馈回来。
# hasattr()函数 class Person(): def __init__(self): self.name = "jack" self.add = "www.baidu.com" def say(self): print("我正在学Python。") pp = Person() print(hasattr(pp, "name")) # True print(hasattr(pp, "add")) # True print(hasattr(pp, "say")) # True- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
我们只能通过该函数判断实例对象是否包含该名称的属性或方法,但不能精确判断,该名称代表的是属性还是方法。
2、getattr() 函数:
getattr() 函数获取某个类实例对象中指定属性的值。
getattr(obj, name[, default])- 1
obj 表示指定的类实例对象,name 表示指定的属性名,而 default 是可选参数,用于设定该函数的默认返回值,即当函数查找失败时,如果不指定 default 参数,则程序将直接报 AttributeError 错误,反之该函数将返回 default 指定的值。
class Person(): def __init__(self): self.name = "jack" self.add = "www.baidu.com" def say(self): print("我正在学Python。") pp = Person() print(getattr(pp, "name")) # jack print(getattr(pp, "add")) # www.baidu.com print(getattr(pp, "say")) #- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
3、setattr()函数:
setattr() 函数的功能相对比较复杂,它最基础的功能是修改类实例对象中的属性值。其次,它还可以实现为实例对象动态添加属性或者方法。
setattr(obj, name, value)- 1
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
setattr() 函数,还可以将类属性修改为一个类方法,同样也可以将类方法修改成一个类属性。
def say(self): print("我正在学Python") class CLanguage: def __init__ (self): self.name = "hello" self.add = "china" clangs = CLanguage() print(clangs.name) # hello print(clangs.add) # china setattr(clangs,"name",say) clangs.name(clangs) # 我正在学Python- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
使用 setattr() 函数对实例对象中执行名称的属性或方法进行修改时,如果该名称查找失败,Python 解释器不会报错,而是会给该实例对象动态添加一个指定名称的属性或方法。
9、检查类型:(issubclass、isinstance)
- issubclass(cls, class_or_tuple):检查 cls 是否为后一个类或元组包含的多个类中任意类的子类。
- isinstance(obj, class_or_tuple):检查 obj 是否为后一个类或元组包含的多个类中任意类的对象。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
issubclass() 和 isinstance() 两个函数的第二个参数都可使用元组。
# str是list或tuple或object的子类,输出True print('str是否为list或tuple或object的子类 ', issubclass(str, (list, tuple, object)))- 1
- 2
- Python 为所有类都提供了一个 bases 属性,通过该属性可以查看该类的所有直接父类,该属性返回所有直接父类组成的元组。
- Python 还为所有类都提供了一个 subclasses() 方法,通过该方法可以查看该类的所有直接子类,该方法返回该类的所有子类组成的列表。
10、call()方法:
call()方法的功能类似于在类中重载 () 运算符,使得类实例对象可以像调用普通函数那样,以“对象名()”的形式使用。
class CLanguage: # 定义__call__方法 def __call__(self,name,add): print("调用__call__()方法",name,add) clangs = CLanguage() clangs("hello","china") # 调用__call__()方法 hello china- 1
- 2
- 3
- 4
- 5
- 6
用 call() 弥补 hasattr() 函数的短板:
class CLanguage: def __init__ (self): self.name = "张三" self.add = "china" def say(self): print("我正在学Python") clangs = CLanguage() if hasattr(clangs,"name"): print(hasattr(clangs.name,"__call__")) # False print("**********") if hasattr(clangs,"say"): print(hasattr(clangs.say,"__call__")) # True- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
11、运算符重载:
重载运算符,指的是在类中定义并实现一个与运算符对应的处理方法,这样当类对象在进行运算符操作时,系统就会调用类中相应的方法来处理。
class MyClass: #自定义一个类 def __init__(self, name , age): #定义该类的初始化函数 self.name = name #将传入的参数值赋值给成员交量 self.age = age def __str__(self): #用于将值转化为字符串形式,等同于 str(obj) return "name:"+self.name+";age:"+str(self.age) __repr__ = __str__ #转化为供解释器读取的形式 def __lt__(self, record): #重载 self- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
12、迭代器:
迭代器指的就是支持迭代的容器,更确切的说,是支持迭代的容器类对象,这里的容器可以是列表、元组等这些 Python 提供的基础容器,也可以是自定义的容器类对象,只要该容器支持迭代即可。
如果要自定义实现一个迭代器,则类中必须实现如下 2 个方法:
-
next(self):返回容器的下一个元素。
-
iter(self):该方法返回一个迭代器(iterator)。
生成器:
# 生成器 def intNum(): print("开始执行。。。") for i in range(5): yield i print("继续执行") num = intNum() for i in num: print(i)- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
相比迭代器,生成器最明显的优势就是节省内存空间,即它不会一次性生成所有的数据,而是什么时候需要,什么时候生成。
1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。
在线投稿:投稿 站长QQ:1888636
后台-插件-广告管理-内容页尾部广告(手机) |