侧边栏壁纸
  • 累计撰写 5 篇文章
  • 累计创建 0 个标签
  • 累计收到 1 条评论

目 录CONTENT

文章目录

Pytorch学习-类基础

Administrator
2022-07-22 / 0 评论 / 1 点赞 / 70 阅读 / 50868 字 / 正在检测是否收录...

Python类基础

一、类中常见术语介绍

1、类(Class)

用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例

2、方法

类中定义的函数

3、类成员(类属性)

类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体(方法)之外。类变量通常不作为实例变量使用,类变量也称作属性

4、数据成员

类变量或者实例变量用于处理类及其实例对象的相关的数据

5、方法重写(Override)

如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写

6、实例变量

定义在__init__方法中的变量,只作用于当前实例的类

7、继承

即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待,以普通的类为基础建立专门的类对象

8、实例化

创建一个类的实例,类的具体对象。一个类可以实例化出无数个对象

9、对象

通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法

10、多态

对不同类的对象使用同样的操作

11、封装

对外部世界隐藏对象的工作细节

二、Python中的类

1、类提供了一种组合数据和功能的方法。创建一个新类意味着创建一个新的对象类型,从而允许创建一个该类型的新实例

2、每个类的实例可以拥有保存自己状态的属性。一个类的实例也可以有改变自己状态的(定义在类中的)方法

3、Python的类提供了面向对象编程的所有标准特性:

  • 类继承机制允许多个基类,派生类可以覆盖它基类的任何方法,一个方法可以调用基类中相同名称的的方法
  • 对象可以包含任意数量和类型的数据
  • 和模块一样,类也拥有Python天然的动态特性:它们在运行时创建,可以在创建后修改

2.1 Python中定义类

1、python中定义类使用class关键字,class后面紧接类名,类名通常是大写开头的单词(无类继承时类名后可以加括号也可以不加括号)

2、python中类的定义语法如下:

 class ClassName:
  语句1
  ...
  语句n

注:

1、类定义与函数定义(def语句)一样:只有在被执行才会起作用
⑴在定义阶段只是语法检查

2、类是属性和方法的组合,所以语句1可能是内部变量(数据、属性)的定义和赋值语句,也可能是内部方法(函数)的定义语句
⑴一个对象的特征称为"属性"
⑵一个对象的行为称为"方法"
⑶属性在代码层面上来看就是变量,方法实际就是函数,通过调用这些函数来完成某些工作

3、进入类定义时,就会创建一个新的命名空间,并把它用作局部作用域
⑴因此,所有对局部变量的赋值都是在这个新命名空间内进行的。特别的,函数定义会绑定到这个局部作用域里的新函数名称

4、正常离开(从结尾出)类定义时,就会创建一个类对象
⑴它基本上是一个包围在类定义所创建的命名空间内容周围的包装器
⑵元素的(在进入类定义之前起作用的)局部作用域将重新生效,类对象将在这里被绑定到类定义头给出的类名称(在上面的例子中就是ClassName)

例1:

class MyClass:
    """定义一个MyClass类"""
    i = 12345
 
    def func(self):
        return 'hello world'

注:

1、类包含属性和方法
⑴属性:分为类属性和实例属性
①"i = 12345":表示定义了一个类属性i其值为12345(实例属性后面介绍)
⑵方法:即定义在类中的函数(与普通的函数类似)
②func:表示定义了一个名为func的实例方法,实际上就是一个稍微特殊点的函数(方法的第一个参数必须为self)

2、在类中定义方法的形式和函数差不多,但其不称为函数,而是叫方法。方法的调用需要绑定到特定的对象上(通过self.或实例对象名),而函数不需要
⑴类内部的函数定义通常具有一种特别形式的参数列表,这个特别形式就是第一个参数必须是self(self参数后面介绍)
⑵方法是所有实例都共用的:类外所有实例都可以调用类中的方法,类中方法之间也可以相互调用

3、上面例子中创建了一个MyClass抽象类,定义好类后会在当前作用域定义名字MyClass,指向类对象MyClass

4、类也是一种对象类型,跟前面学习过的数值、字符串、列表等等是一样的
⑴比如这里构建的类名字叫做MyClass,那么就是我们要试图建立一种对象类型,这种类型被称之为MyClass,就如同有一种对象类型是list一样

5、Python中一切皆对象。不管是我们自己定义的类、6种基本数据类型还是内置的类(第三方类)等都称作为对象
⑴一个对象,就会拥有自己的属性和方法
①我们可以通过一定的方式来调用一个对象的属性和方法。这一点自定义类与其他Python类型是一样的
②可以通过"."点操作符来调用类的方法和属性,具体调用方式后面介绍
⑵对于内置的类(对象:如6种基本数据类型)、第三方类(对象:如datetime类)是人家已经定义好了的,我们可以直接调用它的属性和方法来实现某些操作
①而我们自己定义的类(对象),需要我们按照实际需求去定义它的属性和方法,进而进行调用

6、Python类中的方法分为:实例方法、类方法、静态方法。这里主要介绍实例方法(方法中第一个参数必须为self),感觉其他两种方法用的比较少

2.2 类对象

1、类是抽象的概念,它是一种数据结构:就好比一个模型,该模型是生活中具有相同属性(特征)和方法(动作)的同一类事务,可以用它来生产真实的物体(实例)
⑴在python中,把具有相同属性和方法的对象归为一个类(class)

2、比如,我们可以将类看做是一个"饼干模具",这个模具上有一些饼干的特征(属性)和行为(方法)
⑴有了这个模具之后我们就可以通过这个模块来制作很多具有相同属性和行为的不同饼干了(制作出来的肯定不是同一块饼干)

3、定义一个类后,就相当于有了一个类对象了:Python中"一切皆对象"。类也称为"类对象"
⑴比如前面例1中定义了类MyClass,其也可以成为类对象

4、类对象支持两种操作:属性引用和实例化
⑴实例化:使用instance_name = class_name()的方式实例化,实例化操作创建该类的实例(格式:实例对象名 = 类名(),实例对象名是我们自己定义的)
⑵属性引用:使用class_name.attr_name的方式引用类属性(类名.属性名)

**例2:**属性引用

class MyClass:
    """定义一个MyClass类"""
    i = 12345
 
    def func(self):
        return 'hello world'
 
print(MyClass.i) # 引用类属性
print(MyClass.func) # 引用实例方法:实例方法可以这样被引用,但是这样引用无意义(知道即可)
 
# 类属性也可以被赋值,因此可以通过赋值来更改类属性的值
MyClass.i = 123
print(MyClass.i)
 
"""
12345
<function MyClass.func at 0x00000229FB3F0840>
123
"""

**例3:**实例化

class MyClass:
    """定义一个MyClass类"""
    i = 12345
 
    def func(self):
        return 'hello world'
 
 
# 实例化一个类
my_class = MyClass()
print(my_class)
# <__main__.MyClass object at 0x0000025C05DFE4A8>
 
print("对象类型为:",type(my_class))
# 对象类型为: <class '__main__.MyClass'>
 
"""
可以看到实例化类后返回的是一个MyClass对象,其类型为class(类对象:MyClass)
    这个对象跟python中的数字、字符串、列表等是一样的,只是说一个是自定义的一个是人家定义好了的
    第三方类(库)也是一样的道理
对象都可以拥有属性、方法
"""

注:
1、类的实例化:是使用函数表示法,可以把类对象看做是会返回一个新的类实例的函数
⑴比如上面类对象的实例化就是:my_class = MyClass()。这就创建了一个类的新实例并将此对象分配给局部变量my_class

2、实例化操作可以看成是"调用"类对象:将一个类实例化后获得的对象(所赋值的变量)称为实例对象。my_class就称为实例对象

3、类只是一个抽象的概念,只有经过实例化后(获得实例对象),才会有意义,才能正常使用这个类中的属性和方法

2.3 实例对象

1、实例对象就是具有类属性和方法的具体事物:是基于类而创建的一个具体的事物
⑴比如类可以看做制作饼干的模板,那么通过这个模板制作出来的一块块饼干就是实例对象

2、通过类产生实例对象的过程称为实例化
⑴格式:实例对象名 = 类名()
⑵通过简单的赋值操作,就实例化了一个对象,得到一个实例对象

3、一个类可以实例化出无数个实例对象:这些实例对象之间的属性和方法都是独立的,互不干扰
⑴一个饼干模具可以生产出无数块饼干

4、实例对象是类对象实例化的产物,实例对象仅支持一个操作:属性引用
⑴实例对象名.属性名
⑵实例对象名.方法名()

例4:

class MyClass:
    """定义一个MyClass类"""
    i = 12345
 
    def func(self):
        return 'hello world'
 
#第一个实例对象
my_class = MyClass()
print(id(my_class))
print(my_class.i)   # 引用类属性
print(my_class.func()) # 引用实例方法
 
#第二个实例对象
my_class1 = MyClass()
print(id(my_class1))
# 类属性重新赋值
my_class1.i = 123
print(my_class1.i)   # 引用类属性
print(my_class1.func()) # 引用实例方法
 
#第三个实例对象
my_class2 = MyClass()
print(id(my_class2))
print(my_class2.i)   # 引用类属性
print(my_class2.func()) # 引用实例方法
 
"""
2205374276776
12345
hello world
2205374276552
123
hello world
2205374279632
12345
hello world
"""

注:
1、一个类可以实例化出无数个实例对象:这些实例对象之间的属性和方法都是独立的,互不干扰
⑴my_class、my_class1、my_class2...这些都是通过MyClass类实例化后得到的实例对象,他们之间是互不干扰的

2、在未实例化类时(my_class = MyClass()前),只是定义了类对象的属性和方法,此时其还不是一个完整的对象,将定义的这些称为类(抽象类)。需要使用类来创建一个真正的对象,这个对象就叫做这个类的一个实例,也叫作实例对象(一个类可以有无数个实例)

3、创建一个对象也叫做类的实例化,即my_class = MyClass()(此时得到的my_class变量称为类的具体对象)。注意此时类名后面是跟着小括号的,这跟调用函数一样
⑴另外赋值操作是必须的,但如果没有将创建好的实例对象赋值给一个变量,那这个对象就没办法使用,因为没有任何引用指向这个实例(其实也可以说赋值操作是必须的)

4、使用class语句只能创建一个类,而无法创建类的实例对象,因此要想使用已创建好的类,还需要手动创建类的实例对象,创建类对象的过程又称为类的实例化

例5:

"""这种写法知道就好了,实际中肯定不能这么写:未进行赋值操作!!!!!"""
class MyClass:
    """定义一个MyClass类"""
    i = 12345
 
    def __init__(self,name):
        self.name = name
 
 
    def func(self):
        print(self)
        print("名字是:%s" % self.name)
 
 
# 未进行赋值操作
print(MyClass("张三").i)   # 引用类属性
print(MyClass("张三").func()) # 引用实例方法
 
print(MyClass("李四").i)   # 引用类属性
print(MyClass("李四").func()) # 引用实例方法
 
"""
12345
<__main__.MyClass object at 0x000001356F83D780>
名字是:张三
None
12345
<__main__.MyClass object at 0x000001356F83D780>
名字是:李四
None
"""

注:
1、如果在实例化类时,未将实例赋值给一个变量:虽然可以正常调用类的属性和方法
⑴但是这样是没有意义的。因为:没有任何引用指向这个实例,都没法调用这个实例(只有赋值后才会产生实例对象)

2、如果这样写的话,每次调用这个类的实例对象都需要去实例化一次了,那么就显得很麻烦了,还不如实例化一次并赋值给一个变量,此后每次去调用这个变量(实例对象)就好了

3、因此:类在使用前必须先实例化,并将实例赋值给一个变量(得到实例对象)

三、self参数

1、在定义实例变量、实例方法时的第一个参数必须是self
⑴其实:self名称不是必须的,在python中self不是关键词,你可以定义成a或b或其它名字都可以,只是约定成俗都使用了self
⑵也就是说在定义实例方法时必须有一个参数是默认已经存在了的,可以是self,可以是a,也可以是b。不管这个参数名是什么,但必须得有这个参数

2、self在定义时需要定义,但是在调用时会自动传入(不需要手动传入了)

3、self其实就相当于C++中的this指针

4、如果把类比作图纸,那么由类实例化后的对象才是真正可以住人的房子。根据一张图纸就可以设计出成千上万的房子,他们都长得差不多,但他们都有不同的主人,每个人都只能回自己的家里.....所以self这里就相当于每个房子的门牌号,有了self就可以轻松找到自己房子

5、python中的self参数就是同一个道理,由同一个类可以生成无数对象,当一个对象的方法被调用的时候,对象会将自身的引用作为第一个参数传给该方法,那么python就知道需要操作哪个对象的方法了

6、简单的来说就是:self代表的当前的实例对象本身,这样在调用实例方法等时Python就知道当前是哪个实例对象了
⑴一个抽象类实例化后,实例对象为a,那么此时self就代表实例对象a
⑵一个抽象类实例化后,实例对象为b,那么此时self就代表实例对象b

例6:

class MyClass:
    """定义一个MyClass类"""
    i = 12345
 
    def func(self):
        print("self参数:",self)
        return 'hello world'
 
a = MyClass()
print("实例对象:",a)
a.func()
 
b = MyClass()
print("实例对象:",b)
b.func()
 
"""
实例对象: <__main__.MyClass object at 0x000002D29354E3C8>
self参数: <__main__.MyClass object at 0x000002D29354E3C8>
实例对象: <__main__.MyClass object at 0x000002D29354EFD0>
self参数: <__main__.MyClass object at 0x000002D29354EFD0>
"""

注:
1、通过打印的id值可以看出,self参数实际上就是类通过实例化后得到的实例对象。不同的实例对象对应的self参数是不一样的(self参数始终与当前实例对象时一一对应的)

2、在这个例子可中可能并不能很好的理解self参数的含义,感觉是实例变量中能更好的理解self参数

3、目前我们只需记住:
⑴实例方法第一个参数必须是self,在调用时会自动传入(不需要手动传入了)
⑵self代表的当前的实例对象本身

例7:

class Ball:
    def setname(self,name,age):
        self.name = name
        print(age)
 
    def kick(self):
        return "我叫%s" % self.name
 
a = Ball()
b = Ball()
c = Ball()
 
a.setname("A",1)
b.setname("B",2)
c.setname("C",3)
 
print(a.kick())
print(b.kick())
print(c.kick())
 
"""
1
2
3
我叫A
我叫B
我叫C
"""

**注:**从上面例子可以看出

1、有Ball类生成了三个实例对象a,b,c,这三个对象在调用kick()方法时,是通过self参数去确定究竟当前是哪个对象在调用方法的。因此在写实例方法时一定要写self参数且其位置在第一个,在调用时就不需要传入self参数了

2、在方法中定义的参数,一般来说只能在当前方法中使用(作用域)
⑴如果想要一个方法中的参数能在其他方法中使用,那么就可以使用"self."来将这个参数变成一个实例变量(实例变量后面介绍,这里主要是遇到了这种写法)
⑵name参数:在方法中使用了"self.name = name",这步就相当于是将这个name参数变成了一个实例变量,因此可以在所有方法中使用(这种写法了解即可,没啥意义,因为一个实例变量最好直接定义在__init__方法中)
⑶age参数:age参数就没有使用name参数那样的写法,仅仅是在setname()方法中定义并使用,因此age参数就只能在setname()方法中使用,而不能在kick()方法中使用,即使他们是在同一个类中(经常遇到的是这种写法)

四、类变量

1、类变量:是该类所有实例对象共享的属性(也可以叫"类属性")
⑴类属性是所有实例都共用的:所有实例都可以调用这个类属性
⑵在类中任意地方(所有方法中)都可以使用"类名.类属性名"来调用类属性
⑶在类外任意地方都可以使用"类名.类属性名"或"实例名.类属性名"来调用类属性

2、类变量是直接定义在类中的,比如例1中的"i = 12345",变量i就是一个类属性,该变量是所有实例对象共有的。类中的所有方法、实例都可以使用它

例8:


class Car():
    """这是一个汽车类"""
    brand = "宝马"
 
    def run(self, s):
        # 类中调用类属性:类名.属性名
        print("当前车型为:%s,当前行驶速度:%s KM/S" % (Car.brand,s))
 
 
a = Car()
# 类外调用类属性:实例名.属性名
print(a.brand, id(a.brand))
a.run(110)
 
b = Car()
print(b.brand, id(b.brand))
b.run(200)
 
"""
宝马 1744629351728
当前车型为:宝马,当前行驶速度:110 KM/S
宝马 1744629351728
当前车型为:宝马,当前行驶速度:200 KM/S
"""

五、实例变量

1、类变量是所有实例公用的属性。也就是说一些属性是所有实例都共有的,那么此时我们可以将该属性定义为类属性
⑴那么如果某些属性是每个实例独有的(每个实例的属性值都不一致),那么我们就可以将这些属性定义为实例属性

2、实例变量:是每个实例都独有的数据(也可以叫"实例属性")
⑴即某个属性对于每个实例都是独有的,就需要将其定义为实例变量
⑵某个属性是每个实例同共有的就可以定义为类属性

3、实例变量是定义在__init__方法中的
⑴__init__()方法也是类中的一个方法,因此其第一个参数也必须是self
⑵实例变量是每个实例对象独有的,因此在定义实例变量时,必须是:self.实例变量名 = 外部形参名(通过self来绑定当前实例对象)
⑶在类中任意地方(所有方法中)都可以使用"self.实例属性名"来调用实例属性
⑷在类外任意地方都可以使用"实例名.实例属性名"来调用实例属性

例9:

class People():
    country = "china"
 
    def __init__(self,name):
        self.name = name
 
    def speak(self, age):
        # 类中调用类属性:类名.属性名
        # 类中调用实例属性:self.属性名
        print("我的名字是:%s,来自:%s,年龄是:%s" % (self.name,People.country,age))
 
# 实例化类时传入实例变量值
a = People("Tom")
a.speak(11)
 
b = People("Jack")
b.speak(12)
 
"""
我的名字是:Tom,来自:china,年龄是:11
我的名字是:Jack,来自:china,年龄是:12
"""

注:
1、上面例子中定义了一个类属性"country",是所有实例共有的;定义了一个实例属性"name",是每个实例独有的

2、一个类中存在实例变量(定义了init方法且init方法中存在形参)时,那么在实例化类时就需要传入对应的实参,否则会报错

3、实例方法、类方法、静态方法中可以有自己参数(例子中的参数age),方法中的参数的作用域为方法本身内部(只能在该方法中使用,即使是同一个类中的不同方法,也不能使用)
⑴方法中的参数类型与普通函数的参数类型是一样的(只是第一个参数必须是self)。可以是位置参数(必填参数)、关键字参数、默认参数、可变参数等
⑵如果方法中定义了一些参数,那么在调用这些方法时就必须传入对应参数的值了

4、上面实例化了两个实例对象a、b,在方法speak()中都调用了实例属性name。那么Python是怎么确定当前实例变量name的值是"Tom"或"Jack"的呢?其实就是通过self参数来确定的:一个类可以实例化出无数个实例对象,通过self参数来确定当前是哪个实例对象在调用了
⑴比如当前为实例对象a在调用时,此时self参数就表示实例对象a,此时Python就去找实例对象a的实例属性name的值
⑵比如当前为实例对象b在调用时,此时self参数就表示实例对象b,此时Python就去找实例对象b的实例属性name的值
⑶这样就不会出现什么,实例对象a在调用,但找的是实例对象b的实例属性值了

5、在类中是不可能出现实例对象名的(实例对象是实例化后才产生的),因此在类中使用self参数来表示实例对象
⑴类中的self参数就相当于一个形参,当类实例化后,实例对象就相当于self参数的实参
⑵哪个实例对象在调用,self参数就表示哪个实例对象

6、self.name = name表示:将外部传来的变量name的值赋值给当前实例对象的name属性(两个name之间无任何关系,只是变量名一致)
⑴name:只是一个形参,用来接收外部传入的实参值
⑵self.name:表示当前实例对象的实例属性(当前是哪个实例对象,就表示哪个实例对象的实例属性)

7、因此在类中调用实例属性时都必须使用"self.实例属性名"的方式来调用,这样才能通过self参数来确定当前是哪个实例对象在调用

六、类变量与实例变量

1、在调用一个类中的属性时,Python会按照一定的顺序去查找这个属性:先在当前实例中找,有就用当前实例中的,如果没有就找类中的

例10:

class C:
    count = 0
a = C()
b = C()
c = C()
print(a.count,b.count,c.count)   #output:0,0,0
 
a.count += 10   #实例对象调用类属性
print(a.count,b.count,c.count)   #output:10,0,0
 
C.count += 100  #类对象调用类属性
print(a.count,b.count,c.count)   #output:10 100 100
 
#print(count)   #name 'count' is not defined,不能直接访问类属性,具体访问方法参考前面的属性访问

注:

1、对实例对象的count属性进行赋值后,就相当于覆盖了类对象C的count属性,如果没有赋值覆盖,那么引用的就是类对象的count属性
⑴通过"实例对象名.属性名"来覆盖类属性,只会影响到当前实例对象,不会影响到其他实例对象中的类属性
⑵通过"类名.属性名"来覆盖类属性,会影响到所有实例的类属性
⑶因此在类外调用类变量时,最好使用"实例对象名.属性名",避免在重新赋值时影响到其他实例

2、类变量和实例变量的区别在于:类变量是所有对象共有,其中一个对象将它值改变,其他对象得到的就是改变后的结果;而实例变量则属对象私有,某一个对象将其值改变,不影响其他对象

3、获取一个实例对象的属性时,其属性名后面都是不需要加园括号的(不管是我们自己定义的类还是Python自带的类);如果属性名后面带上了园括号,那么就变成了一个方法名了。这肯定是不对的。所以要分清楚调用的是类的属性还是类的方法
⑴不管是调用类方法还是属性,都是通过"."点操作来实现的

七、类中的方法

1、Python类中的方法分为:实例方法、类方法、静态方法

2、实例方法、类方法、静态方法是所有实例对象共用的
⑴一个类可以实例化出无数个实例对象,这些实例对象都可以调用类的方法和属性

3、实例方法、类方法、静态方法中可以有自己参数(除self之外的参数)
⑴方法中的参数的作用域为方法本身内部:只能在该方法中使用,即使是同一个类中的不同方法,也不能使用
⑵方法中的参数类型与普通函数的参数类型是一样的(只是第一个参数必须是self)
①可以是位置参数(必填参数)、关键字参数、默认参数、可变参数等
⑶如果方法中定义了一些参数,那么在调用这些方法时就必须传入对应参数的值了

4、在类的方法中可以调用同一个类自己的其他方法
⑴如:在实例方法中调用其他实例方法(同一个类的不同方法)
①类中访问实例方法:self.方法名(参数)或类名.方法名(self,参数)
②类外访问实例方法:实例名.方法名(参数)
⑵总的来说对类的方法的定义、调用跟普通函数是差不多的

5、这里先介绍实例方法

例11:

class MyClass:
    className = "三年2班"  # 定义一个类属性className
 
    def __init__(self, name):  # 定义一个实例变量name
        self.name = name
 
    # 方法中定义自己的变量
    def BaseInfo(self, Hobby):
        # 类中调用实例变量、类变量、自己的变量
        baseInfo = "My name is %s,I am a student in %s,my Hobby is %s" % (
            self.name, MyClass.className, Hobby)
        return baseInfo
 
    # 方法中定义自己的变量
    def ComeFrom(self, info, country, *args):  # 在方法中定义一些局部变量(只能在该方法中使用)
        # 在类中调用实例方法,并将其返回值赋值给变量
        baseInfo = self.BaseInfo(info)
        comeFrom = baseInfo + ".I comefrom " + country + "," + ",".join(args)
        return comeFrom
 
x = MyClass("张三")  # 实例化类
# 类外访问实例方法
print(x.ComeFrom("swim", "china", "chengdu", "高新区", "茂业中心"))
 
y = MyClass("李四")  # 实例化类
# 类外访问实例方法
print(y.ComeFrom("reading", "china", "meishan", "hongya", "gaomiao"))
 
"""
My name is 张三,I am a student in 三年2班,my Hobby is swim.I comefrom china,chengdu,高新区,茂业中心
My name is 李四,I am a student in 三年2班,my Hobby is reading.I comefrom china,meishan,hongya,gaomiao
"""

八、类的使用

1、定义个类主要是将一些具有相同属性的数据、方法放到一个类中整合起来方便代码的管理。最终目的还是调用类中的属性和方法

2、在调用类中的方法或属性时都必须遵循一定的规则:调用类的属性或方法分类在类中调用、在类外调用。不同地方调用,调用的方式也会有一定的差距

3、调用类属性:
⑴类中访问类变量:类名. 类变量名
⑵类外访问类变量:类名.类变量名或实例名.类变量名

4、调用实例属性:
⑴类中访问实例变量:self.实例变量名
⑵类外访问实例变量:实例名.实例变量名

4、调用实例方法:
⑴类中访问实例方法:self.方法名(参数)或类名.方法名(self,参数)
⑵类外访问实例方法:实例名.方法名(参数)

例11:

class MyClass:
    """一个简单的类实例"""
    i = 12345#定义一个类属性
 
    def f(self):#定义一个实例方法
        print(MyClass.i) #类中调用类属性
        return 'hello world'
 
    def g(self):
        # 类中调用实例方法
        self.f()
        MyClass.f(self)
 
x = MyClass()   # 实例化类
 
# 访问类的属性和方法
print("MyClass 类的属性 i 为:", x.i) #类外调用类属性
print("MyClass 类的属性 i 为:", MyClass.i)
print("MyClass 类的方法 f 输出为:", x.f()) #类外调用实例方法
x.g()
 
"""
MyClass 类的属性 i 为: 12345
MyClass 类的属性 i 为: 12345
12345
MyClass 类的方法 f 输出为: hello world
12345
12345
"""

注:
1、在未实例化类时(x = MyClass()前),只是定义了对象的属性和方法,此时其还不是一个完整的对象,将定义的这些称为类(抽象类)。需要使用类来创建一个真正的对象,这个对象就叫做这个类的一个实例,也叫作实例对象(一个类可以有无数个实例)

2、创建一个对象也叫做类的实例化,即x = MyClass()。(此时得到的x变量称为类的具体对象)。注意此时类名后面是跟着小括号的,这跟调用函数一样。另外赋值操作并不是必须的,但如果没有将创建好的实例对象赋值给一个变量,那这个对象就没办法使用,因为没有任何引用指向这个实例

3、如果要调用对象里的方法,就需要判断是在类中调用还是在类外调用:
⑴在类中调用实例方法:self.方法名(参数)或类名.方法名(self,参数)这个这里只是提一下,可以先不纠结
⑵在类外调用实例方法:实例对象名.方法名(参数)。这里的例子就是类外调用方法,只是说实例方法中没有定义参数。x.f():x为实例对象名,f()为类中定义的实例方法

4、 x.i和MyClass.i都是用于调用类的属性,也就是我们前面所说的类变量;x.f()用于调用类的实例方法
⑴调用类属性可以使用:实例对象名.类属性名或类名.类属性名。虽然这两种方法都可以调用类属性,但是两者在调用使用还是有区别的,后面介绍

5、类中定义方法的要求:在类中定义方法时,第一个参数必须是self,除第一个参数外,类的方法和普通的函数没什么区别,如可以使用默认参数,可变参数,关键字参数和命名关键字参数等
⑴虽然在定义方法时会定义一个self参数,但是不管是在类中或是在类外调用方法都不用传递self,其他参数正常传入
⑵self参数究竟是什么,这里也可以先不纠结,目前只需要知道定义一个实例方法时,第一个参数必须是self,但是在调用实例方法时,不需要传递这个self参数

6、类对象(抽象类)支持两种操作:即属性引用和实例化
⑴属性引用:方法为类名.类属性名(也可以实例对象名.类属性名)
⑵实例化:将一个抽象类实例化成一个实例对象(x = MyClass() )。一个类可以实例化出无数个对象

7、类是一个抽象的概念,对象则是一个实际存在的东西。就像我们说的"狮子",它只是一个抽象的东西,只有具体到狮子这种动物身上它才是实际存在的。在比如设计房子的图纸只能告诉你房子是什么样的,并不是真正的房子,只有通过钢筋水泥建造出来的房子才实际存在,才能住人。
⑴"造房子"这个过程就相当于是"实例化类',一个抽象类只有实例化成一个具体的实例对象后,才会有意义(抽象类只有实例化后才能使用,才会有意义)

例12:

class Student():
    address = "china"     #定义类变量address
 
    def __init__(self,name,age):    #定义实例变量age和name
        self.name = name
        self.age = age
 
    def Info(self,score):#定义在方法中的变量(普通的变量:作用域为这个方法内)
        return "学生来自于%s,名字为%s,年龄为%s,成绩为%s"%(Student.address,self.name,self.age,score)
        #类中访问实例变量:self.实例变量名
        #类中访问类变量:类名.类变量名
        #类中访问方法中的普通变量:直接变量名(且该变量只能在这个方法中使用,不能再其他方法或类外调用)
 
 
student = Student("张三",18)  #实例化类
print(student.name) #类外访问实例变量:实例名.实例属性名
print(Student.address)  #类外访问类变量:类名.类属性名(也可以实例名.类属性名)
print(student.Info(98)) #类外访问实例方法:实例名.方法名(参数)
 
#另一个实例对象
student_1 = Student("李四",20)
print(student_1.name)
print(student_1.address)
print(student_1.Info(100))
 
"""
张三
china
学生来自于china,名字为张三,年龄为18,成绩为98
李四
china
学生来自于china,名字为李四,年龄为20,成绩为100
"""

注:
1、在Student类中,类属性address为所有实例所共享;实例属性name和age每个student的实例独有(每个实例有不同的name和age)
⑴类属性:实例对象student和student_1拥有一样的address属性
⑵实例属性:实例对象student和student_1拥有不一样的name和age属性(每个实例独有的属性)

九、属性绑定

1、在定义类时,通常我们说的定义属性,其实是分为两个方面的:类属性绑定、实例属性绑定(也就是定义类属性或实例属性)

2、用绑定这个词更加确切;不管是类对象还是实例对象,属性都是依托对象而存在的。我们说的属性绑定,首先需要一个可变对象,才能执行绑定操作,使用objname.attr = attr_value的方式,为对象objname绑定属性attr。这分两种情况:
⑴若属性attr已经存在,绑定操作会将属性名指向新的对象
⑵若不存在,则为该对象添加新的属性,后面就可以引用新增属性

十、类属性绑定

Python作为动态语言,类对象和实例对象都可以在运行时绑定任意属性。因此,类属性的绑定发生在两个地方
⑴类定义时
⑵运行时任意阶段
例13:

class Dog:
 
    kind = 'canine'
 
Dog.country = 'China' #绑定一个新的类属性country
 
print(Dog.kind, ' - ', Dog.country)  # 输出: canine  -  China
del Dog.kind
print(Dog.kind, ' - ', Dog.country)  #由于上一行删除的kind属性,因此输出为AttributeError: type object 'Dog' has no attribute 'kind'

注:
1、在类定义中,类属性的绑定并没有使用objname.attr = attr_value的方式,这是一个特例,其实是等同于后面使用类名绑定属性的方式

2、因为是动态语言,所以可以在运行时增加属性,删除属性

十一、实例属性绑定

与类属性绑定相同,实例属性绑定也发生在两个地方:类定义时、运行时任意阶段
例14:

class Dog:
 
    def __init__(self, name, age):
        self.name = name
        self.age = age
 
dog = Dog('Lily', 3)
dog.fur_color = 'red' #为实例对象dog增加一个fur_color属性
 
print('%s is %s years old, it has %s fur' % (dog.name, dog.age, dog.fur_color))
 
#上面代码的输出结果为:Lily is 3 years old, it has red fur

注:
1、语句self.name = name,self.age = age以及后面的语句dog.fur_color = 'red'为实例dog增加三个属性name, age, fur_color。

2、Python类实例有两个特殊之处:
⑴__init__在实例化时执行
⑵Python实例对象调用方法时,会将实例对象作为第一个参数传递因此,__init__方法中的self就是实例对象本身,这里是dog

十二、类属性引用

类属性的引用,肯定是需要类对象的,属性分为两种:数据属性、函数属性。只是通常很少有引用类函数属性的需求

例15:数据属性引用很简单


class Dog:
 
    kind = 'canine'
 
Dog.country = 'China'
 
print(Dog.kind, ' - ', Dog.country)  # output: canine  -  China

例16:

class Dog:
    kind = 'canine'
 
    def tell_kind(self):
        print(Dog.kind)
 
    def info(self):
        return self.tell_kind() #类中调用实例方法
 
dog = Dog()
dog.tell_kind()  # Output: canine
dog.info()  # Output: canine

十三、实例属性引用

使用实例对象引用属性稍微复杂一些,因为实例对象可引用类属性以及实例属性。但是实例对象引用属性时遵循以下规则:
⑴总是先到实例对象中查找属性,再到类属性中查找属性
⑵属性绑定语句总是为实例对象创建新属性,属性存在时,更新属性指向的对象

例17:

class Dog:
 
    kind = 'canine'
    country = 'China'
 
    def __init__(self, name, age, country):
        self.name = name
        self.age = age
        self.country = country
 
dog = Dog('Lily', 3, 'Britain')
print(dog.name, dog.age, dog.kind, dog.country)   #output:Lily 3 canine Britain

注:
类对象Dog与实例对象dog均有属性country,按照规则,dog.country会引用到实例对象的属性;但实例对象dog没有属性kind,按照规则会引用类对象的属性

例18:

class Dog:
 
    kind = 'canine'
    country = 'China'
 
    def __init__(self, name, age, country):
        self.name = name
        self.age = age
        self.country = country
 
dog = Dog('Lily', 3, 'Britain')
 
print(dog.name, dog.age, dog.kind, dog.country)   # Lily 3 canine Britain
print(dog.__dict__)                               # {'name': 'Lily', 'age': 3, 'country': 'Britain'}
 
dog.kind = 'feline'
 
print(dog.name, dog.age, dog.kind, dog.country)   # Lily 3 feline Britain
print(dog.__dict__)                               # {'name': 'Lily', 'age': 3, 'country': 'Britain', 'kind': 'feline'}
print(Dog.kind)                                   # canine (没有改变类属性的指向)

注:
使用属性绑定语句dog.kind = 'feline',按照规则,为实例对象dog增加了属性kind,后面使用dog.kind引用到实例对象的属性。这里不要以为会改变类属性Dog.kind的指向,实则是为实例对象新增属性,可以使用查看__dict__的方式证明这一点。

十四、可变类属性引用

例19:

class Dog:
    
    tricks = []
 
    def __init__(self, name):
        self.name = name
 
    def add_trick(self, trick):
        self.tricks.append(trick)
 
d = Dog('Fido')
e = Dog('Buddy')
d.add_trick('roll over')
e.add_trick('play dead')
print(d.tricks)             output:# ['roll over', 'play dead']

注:语句self.tricks.append(trick)并不是属性绑定语句,因此还是在类属性上修改可变对象

十五、拓展

1、python中的self参数

例20:定义任意一个类:

class Student(object):
    pass
student = Student()

注:由于类起到模板的作用,因此,可以在创建实例的时候,把我们认为必须绑定的属性强制填写进去(绑定实例变量)。这里就用到Python当中的一个内置方法__init__方法,例如在Student类时,把name、score等属性绑上去

例21:

class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.score = score
 
>>>student = Student("Hugh", 99)
>>>student.name
"Hugh"
>>>student.score
99

注:

1、__init__方法的第一参数永远是self,表示创建的当前类实例本身,因此,在__init__方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身

2、有了__init__方法,在创建实例的时候(类实例化),就不能传入空的参数了,必须传入与__init__方法匹配的参数,但self不需要传,Python解释器会自己把实例变量传进去

3、这里self就是指当前实例对象本身,self.name就是当前student实例对象的name属性,是该student实例对象独有的

4、name是外部传来的参数,不是Student类自带的。故,self.name = name的意思就是把外部传来的参数name的值赋值给student当前实例对象自己的实例属性name(只是实例变量的名字和形参的一样而已)

例22:


class Student(object):
    def __init__(self, name_1, score_1):
        self.name = name_1
        self.score = score_1
 
student = Student("zh",12)
print(student.name)
print(student.score)
 
"""
zh
12
"""

注:这个例子中就特意把实例变量名和形参名定义成不一样了:self.name = name_1
⑴name_1相当于是占位的形参,只是方便外部向类中传递参数(给实例变量传递值),没有什么实际意义
⑵self.name中的name才是真正的实例变量了,是每个实例独有的属性
⑶只是说这两个变量表示的属性意义是一样的,因此更多的是将两个写成一样的名字。不然,有一个实例属性是"名字",形参用的是"a",实例属性用的是"name",这样就看起来比较奇怪的,都表示的是"名字"却用了不一样的名字

例23:

class Person:
    def __init__(self, name, job=None, pay=10):
        self.name = name
        self.job = job
        self.pay = pay
 
    def getRaise(self, percent):
        self.pay = int(self.pay * (1 + percent))
        return self.pay
 
 
p = Person("xiaoming", "jixie")
print(p.getRaise(0.8))  # output:18

注:self是指当前被调用的对象,对的,就是上边刚被你实例化的对象p。当你需要调用当前对象(实例对象)的方法或者属性时,要用self.来进行调用(类中调用实例属性或方法:self.)

例24:

class CC:
    def setXY(self,x,y):
        self.x = x
        self.y = y
    def printXY(self):
        print(self.x ,self.y)
 
dd = CC()
dd.setXY(4,5)

注:self参数:当实例对象dd去调用setXY方法的时候,它传入的第一个参数就是dd,那么self.x = 4,self.y = 5也就相当于dd.x = 4,dd.y = 5,所以你在实例对象,甚至类对象中都看不到x和y,因为这两个属性是只属于实例对象dd的

例25:


class TestClass(object):
    val1 = 100
 
    def __init__(self):
        self.val2 = 200
 
    def fcn(self, val=400):
        val3 = 300
        
        self.val4 = val
        self.val5 = 500
 
 
if __name__ == '__main__':
    inst = TestClass()
 
    print(TestClass.val1)
    print(inst.val1)
    print(inst.val2)
    #print(inst.val3)
    #val3为局部变量,无法在函数为调用'TestClass' object has no attribute 'val3'
    #print(inst.val4)
    #print(inst.val5)

注:
1、val1是类变量,可以由类名直接调用,也可以有对象来调用;

2、val2是实例变量,可以由类的对象来调用,这里可以看出成员变量一定是以self.的形式给出的,因为self的含义就是代表实例对象

3、val3既不是类变量也不是实例变量,它只是函数fcn内部的局部变量

4、val4和val5也都不是实例变量,虽是以self.给出,但并没有在构造函数中初始化

2、在实例方法中调用其他方法

例26:


class Dog():
    def __init__(self,name,age):
        self.name = name
        self.age = age
 
    def get_dog_information(self):
        dog_information = "name is {0},age is {1}".format(self.name,self.age)
        return dog_information
 
    def get_dog_speak(self,love):
        dog_speak = self.get_dog_information() + love
        return dog_speak
 
dog = Dog("jake",13)
print(dog.get_dog_speak("swimming"))
 
#name is jake,age is 13swimming

注:在上面例子中
在get_dog_information()方法中调用了get_dog_information(),且get_dog_information()方法前加了self参数,该参数的意义与其他self的意思一样,都是代表实际本身

3、实例方法、类方法、静态方法

1、在面向对象的编程中,类属性可细分为类属性和实例属性一样,同样的,对于类中的方法也可以具体可划分为类方法、实例方法和静态方法

实例方法

1、在类编程中,一般情况下在类中定义的方法、函数默认都是实例方法

2、python的类编程中实例方法最大的特点就是最少要包含一个self参数,该参数必须定义,但调用时不需要传
⑴该self参数的作用是绑定调用此方法的实例对象(确定当前是哪个实例对象在调用方法、实例变量,Python会自动完成绑定),类比C++中的this指针
⑵实例方法:方法中第一个参数都是self,实例变量、实例方法都需要要绑定self(self参数表示当前实例对象本身)
⑶调用实例方法:只能由实例对象调用

3、感觉经常用到的都是实例方法,所以前面主要介绍了实例方法。类方法和静态方法感觉不是经常用到,所以在这里补充下

例27:

class MyClass:
    className = "三年2班"  # 定义一个类属性className
 
    def __init__(self,name):#定义一个实例变量name
        self.name = name
 
    def BaseInfo(self):
        # 类中调用实例变量、类变量
        baseInfo = "My name is %s,I am a student in %s" % (self.name,MyClass.className)
        return baseInfo
 
    def ComeFrom(self,country,*args): # 在方法中定义一些局部变量(只能在该方法中使用)
        # 类中调用类方法
        baseInfo = self.BaseInfo()
        comeFrom = baseInfo + ".I comefrom " + country + "," + ",".join(args)
        return comeFrom
 
x = MyClass("张三")  # 实例化类
# 类外访问实例方法
print(x.ComeFrom("china","chengdu","高新区","茂业中心"))
 
y = MyClass("李四")  # 实例化类
# 类外访问实例方法
print(y .ComeFrom("china","meishan","hongya","gaomiao"))
 
"""
My name is 张三,I am a student in 三年2班.I comefrom china,chengdu,高新区,茂业中心
My name is 李四,I am a student in 三年2班.I comefrom china,meishan,hongya,gaomiao
"""

类方法

1、Python中的类方法和实例方法类似,但类方法需要满足以下要求:
⑴类方法至少需要包含一个参数,与实例方法不同的是该参数并非self,而是python程序员约定俗成的参数:cls(cls表示当前类对象)
⑵Python会自动将类本身绑定到cls参数(非实例对象),故在调用类方法时,无需显式为cls参数传递参数
⑶类方法需要使用修饰语句: @classmethod

2、调用类方法:类和实例对象都可以调用
⑴类方法推荐使用类名直接调用,当然也可以使用实例对象来调用(不推荐)

例28:

class CLanguage:
    #类构造方法,也属于实例方法
    def __init__(self):
        self.name = "C语言中文网"
        self.add = "http://c.biancheng.net"
    #下面定义了一个类方法
    @classmethod
    def info(cls):
        print("正在调用类方法",cls)
 
 
#使用类名直接调用类方法
CLanguage.info()
#使用类对象调用类方法
clang = CLanguage()
clang.info()
 
"""
正在调用类方法 <class '__main__.CLanguage'>
正在调用类方法 <class '__main__.CLanguage'>
"""

例29:

# 文件在工程中的路径:Py_Project/zxc.py
class People():
    def __init__(self,name):
        self.name = name
 
    # 定义了一个类方法:类方法中是不能有实例变量的
    @classmethod
    def Age(self,age):
        age = "age is %s" % (age)
        return age
    # 定义一个实例方法:可正常使用实例变量
    def Info(self,age):
        info = "name is %s,age is %s" % (self.name,age)
        return info
 
 
# 导入所需模块
from Py_Project.zxc import People
 
#调用实例方法:在调用实例方法前必须实例化类
people = People("jack")
print(people.Info(12))
 
# name is jack,age is 12
 
 
# 导入所需模块
from Py_Project.zxc import People
 
#调用类方法:通过实例名来调用类方法,也要先实例化类
people = People("jack")
print(people.Age(13))
 
# 调用类方法:通过类名来调用类方法,就不需要实例化类
print(People.Age(14))
 
# age is 13
# age is 14

注:

1、在一个类中可以同时定义实例方法、类方法、静态方法

2、类方法中是不能调用实例变量的,但是可以调用类变量:因为类方法是指向类的,而不是实例对象的

3、调用实例方法前必须实例化类;调用类方法就可以直接使用类名进行调用

静态方法

1、类中的静态方法,实际上就是大家众所周知的普通函数,存在的唯一区别是:
⑴类静态方法在类命名空间中定义,而函数则在程序的全局命名空间中定义

2、需要注意的是:
⑴类静态方法没有self、cls这样的特殊参数,故Python解释器不会对其包含的参数做任何类或对象的绑定
⑵类静态方法中无法调用任何类和对象的属性和方法,类静态方法与类的关系不大
⑶静态方法需要使用@staticmethod修饰

3、静态方法的调用,既可以使用类名,也可以使用类对象

4、静态方法是类中的函数,不需要实例等
⑴静态方法主要是用来存放逻辑性的代码,逻辑上属于类,但是和类本身没有关系
⑵也就是说在静态方法中,不会涉及到类中的属性和方法的操作(静态方法中不能使用实例变量、类变量、实例方法等)
⑶可以理解为,静态方法是个独立的、单纯的函数,它仅仅托管于某个类的名称空间中,便于使用和维护

例30:

class CLanguage:
    @staticmethod
    def info(name,add):
        print(name,add)
#使用类名直接调用静态方法
CLanguage.info("C语言中文网","http://c.biancheng.net")
 
#使用类对象调用静态方法
clang = CLanguage()
clang.info("Python教程","http://c.biancheng.net/python")
 
"""
C语言中文网 http://c.biancheng.net
Python教程 http://c.biancheng.net/python
"""

1

评论区