Python(7)——类

一、创建和使用

class Restaurant:
    """创建一个餐厅类"""
    def __init__(self, restaurant_name, cuisine_type):
        """"初始化自身的信息"""
        self.restaurant_name=restaurant_name
        self.cuisine_type=cuisine_type

    def describe_restaurant(self):
        """显示餐厅对象的信息"""
        print(f"name:{self.restaurant_name},type:{self.cuisine_type}")

    def open_restaurant(self):
        print("restaurant is opening")

""""1.创建一个餐厅对象"""
restaurant=Restaurant("abcd","Chinese food")

""""2.打印餐厅的名字"""
print(restaurant.restaurant_name)

""""3.打印餐厅的类型"""
print(restaurant.cuisine_type)

""""4.调用餐厅的函数"""
restaurant.describe_restaurant()

""""5.调用餐厅的函数"""
restaurant.open_restaurant()

执行结果:

1)__init__()方法

__init__()方法会在创建类对象时自动调用,通常利用该方法对对象的属性进行初始化。

2)方法中的参数(self)

在每个方法中,第一个参数应该是self,它会自动把当前对象当成实参传入方法。通过使用self.xxx可以调用当前对象中的一些属性

3)参数中也可以指定默认值

与函数的默认值一样,方法中形参也可以指定默认值

二、访问权限

Pthon的类中只有两种访问权限,公有类型私有类型

1)公有类型

公有类型分为公有变量和公有方法,他们都是通过点操作符( . )来进行访问

class Student:
    #公有变量定义方式1
    age = 18                    

    def __init__(self,name):
        #公有变量定义方式2 
        self.name = name        
    
    #公有方法定义方式
    def get_student(self):      
        print(f"学生:{self.name},年龄:{self.age},学历:{self.graduation}")

person = Student("None")

#可在类外直接修改公有变量
person.name = "Xiao Ming"      
person.age = 25

#可在类外直接调用公有方法
person.get_student()    #错误调用,因为该函数中的graduation变量找不到

#公有变量定义方式3
person.graduation = "Middle"

#可在类外直接调用公有方法
person.get_student()

#上面代码结果为:
#学生:Xiao Ming,年龄:25,学历:Middle

可以看出,公有变量的定义方式有三种:

  1. 在类中直接定义一个变量
  2. 在类中的函数使用self.xxx定义一个变量
  3. 在类的具体对象中(类外)使用点操作符定义一个变量

【注意】如果类成员函数使用到了类中尚未定义的变量时,记得在调用该函数时先在类外定义该变量,如上述代码的graduation变量

2)私有类型

私有类型分为私有变量和私有方法,他们的定义方式为在开头使用两个下划线__,他们只能在内部调用,不能在外部调用

class Student:
    #私有变量定义方式1
    __age = 18                    
    def __init__(self,name,graduation):
        #私有变量定义方式2
        self.__name = name
        self.__graduation = graduation
    #私有方法定义方法
    def __get_student(self):      
        print(f"学生:{self.__name},年龄:{self.__age},学历:{self.__graduation}")
    def get_student(self):
        self.__get_student()

person = Student("Xiao Ming","Middle")
#尝试改变类中的私有变量
person.__age = 25
person.get_student()

#上面代码结果为(发现年龄并没有发生变化):
#学生:Xiao Ming,年龄:18,学历:Middle

【注意】在上述代码中,我们尝试在类外访问类的私有变量,但是通过输出我们发现该变量并没有改变,说明无法直接调用私有类型,因此我们通常都是在类中利用公有方法访问私有类型

3)访问私有类型

在Python中,其实也可以直接访问私有类型。上述代码中,不能直接访问__age的原因是因为Python对外把__age变量改写成了_Student__age,所以也可以在外部通过_Student__age来访问类中的__age变量。(只是希望你看到这个变量是知道这是私有类型)

class Student:
    __age = 18                    
    def __init__(self,name,graduation):
        self.__name = name
        self.__graduation = graduation
    def __get_student(self):      
        print(f"学生:{self.__name},年龄:{self.__age},学历:{self.__graduation}")
    def get_student(self):
        self.__get_student()

person = Student("Xiao Ming","Middle")

person.__age = 25
print(person.__age)
person.get_student()

person._Student__age = 30
print(person._Student__age)
person.get_student()

#上面代码结果为:
#25
#学生:Xiao Ming,年龄:18,学历:Middle
#30
#学生:Xiao Ming,年龄:30,学历:Middle
  • 我们可以发现,如果在类外尝试用person.__person访问类中__person变量时会失败,反而会为类新定义了一个公有变量(并且该公有变量只能在类外通过点操作符才可以访问,在类中使用self.__age访问的会是私有变量)
  • 如果在类外用person._Student__person访问类中的__person变量则成功。但是强烈建议你不要这么干,因为不同版本的Python解释器可能会把__age改成不同的变量名

三、类的专用方法

Python除了自定义私有变量和方法外,还可以定义专有方法。专有方法是在特殊情况下或使用特殊语法时由python调用的,而不是像普通方法一样在代码中直接调用。在Python中,如果看到如__XXX__的变量或函数名时要注意,这在Python中是有特殊用途的:

方法名用途
__init__构造函数,在生成对象时调用
__del__析构函数,释放对象时调用
__repr__打印,转换
__setitem__按照索引赋值
__getitem__按照索引获取值
__len__获得长度
__cmp__比较运算
__call__函数调用
__add__加运算
__sub__减运算
__mul__乘运算
__div__除运算
__mod__求余运算
__pow__乘方

1)__str__和__repr__

1.__str__()

参数:只有self

作用:把一个类的对象在输出使变成一自定义字符串

返回值:需要返回一个字符串

class StudentA:
    def __init__(self,name):       
        self.name = name

class StudentB:
    def __init__(self,name):       
        self.name = name
    def __str__(self):
        return "学生的姓名:%s"%self.name

personA = StudentA("Xiao Ming")
print(personA)

personB = StudentB("Xiao Liu")
print(personB)

#执行结果:
#<__main__.Student object at 0x00000000277F6C0>
#学生的姓名:Xiao Liu

【注意】从上述代码得知,如果直接输出一个类的对象,会得到特殊字符串(程序开发者所用)

2.__repr__()

参数:只有self

作用:把一个类的对象在交互模式下输出时变成一自定义字符串

返回值:需要返回一个字符串

>>> class StudentA:
...     def __init__(self,name):
...         self.name = name
...     def __str__(self):
...         return "学生的姓名:%s"%self.name
... 
>>> class StudentB:
...     def __init__(self,name):
...         self.name = name
...     def __str__(self):
...         return "学生的姓名:%s"%self.name
...     def __repr__(self):
...         return "调试—学生的姓名:%s"%self.name
... 
>>> personA = StudentA("Xiao Ming")
>>> personA
<__main__.StudentA object at 0x0000000002C5EE48>
>>> print(personA)
学生的姓名:Xiao Ming
>>> personB = StudentB("Xiao Liu")
>>> personB
调试—学生的姓名:Xiao Liu
>>> print(personB)
学生的姓名:Xiao Liu

【注意】

  • __str__() 返回用户看到的字符串,而 __repr__() 返回程序开发者看到的字符串。也就是__repr__() 是为调试服务的
  • 除了直接定义__repr__函数外,也可以使用__repr__=__str__定义repr函数,让调试得到的字符串和输出的到的字符串一致

3.特殊情况

class Student:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def __str__(self):
        return f"({self.name},{self.age})"

a = Student('a',18)
b = Student('b',25)
c = Student('c',15)
students = [a,b,c]
print(students)
print(students[0])

执行结果

可以看出,当整个list输出时,Student对象返回的是一个用于调试的值,而具体访问列表中某个Student对象时,会调用__str__函数。因此,如果我们想无论哪种情况都输出一致时,记得加上__repr__ = __str__

2)__iter__和__next__

1.__iter__()

参数:只有self

作用:将一个类用于 for ... in 循环,类似 list 或 tuple 一样。

返回值:返回一个迭代对象,可以返回自身(self就是一个迭代对象)

2.__next__()

参数:只有self

作用:for  循环会不断调用__iter__()返回的迭代对象的__next__()  方法,获得循环的下一个值,直到遇到 StopIteration 错误时退出循环

返回值:可以返回任意值

class Fib:
    def __init__(self):
        self.a = 0

    def __iter__(self):
        print("run __iter__")
        return self             
    
    def __next__(self):
        self.a += 1
        if self.a > 5:
            raise StopIteration();
        return f"run __next__:{self.a}"
 
fib = Fib()
for n in fib:
    print(n)

#执行结果
#run __iter__
#run __next__:1
#run __next__:2
#run __next__:3
#run __next__:4
#run __next__:5

【注意】在for...in循环调用后,__iter__只会调用一次,而__next__调用次数与自身实现相关,当遇到StopIteration()会马上停止循环

3)__getitem__和__setitem__

类虽然能够作用于 for 循环,和 list 有点像,但是不能将它当成 list 使用。若要像list一样按照索引来获取元素或改变元素值,需要实现__getitem__()方法和__setitem__()方法

1.__getitem__()

参数:self和索引值

作用:使类像list一样按照索引来获取元素,在对象使用[]运算符时会调用该函数

返回值:可以返回任意值,但最好是会根据索引值变化

2.__setitem__()

参数:self,索引值,用于赋值的参数(实参为等号左边的值)

作用:使类像list一样按照索引来改变元素值,在对对象某个按索引获取的值赋值时会调用该函数,如a[2] = 10

返回值:可以返回任意值

class Student:
    def __init__(self):
        self.student = ['a','b','c','d','e','f']
    def __getitem__(self,n):
        return f"run __getitem__:student {self.student[n]}"
    def __setitem__(self,n,str):
        self.student[n] = str
        print("run __setitem__")

a = Student()
print(a[2])
a[2] = "xiao ming"
print(a[2])

#执行结果
#run __getitem__:student c
#("run __setitem__")
#run __getitem__:student xiao ming

【注意】在__setitem__中不可以使用self[n]进行赋值,这种情况会产生无限递归,递归调用__getitem__和__setitem__

4)__len__

参数:只有self

作用:对对象使用len()方法时,调用该__len__()方法

返回值:必须返回一个整形

class Student:
    def __init__(self):
        self.student = ['a','b','c','d','e','f']
    def __len__(self):
        print("run __len__")
        return len(self.student)

a = Student()
print(len(a))

#执行结果
#run __len__
#6

5)__cmp__

使用python内置的sorted()函数里默认的cmp函数对其排序。

参数:self和用于比较的参数

作用:对对象进行任何的比较时,都会调用该函数

返回值:返回-1,1,或0

class Student:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def __cmp__(self,student):
        if self.age < student.age:
            return -1
        elif self.age > student.age:
            return 1
        else:
            return 0
    def __str__(self):
        return f"({self.name},{self.age})"
    __repr__ = __str__

a = Student('a',18)
b = Student('b',25)
c = Student('c',15)
students = [a,b,c]
print(students)
sorted(students)

#执行结果
#[(a,18),(b,25),(c,15)]
#[(c,15),(a,18),(b,25)]

【注意】在Python3中,该函数已删除,而使用operator模块中的函数代替

函数作用
__lt__(a,b)a<b,从第一个数字或字母(ASCII)比大小
__le__(a,b)a<=b
__eq__(a,b)a==b,字母完全一样,返回True,
__ne__(a,b)a!=b
__gt__(a,b)a>b
__ge__(a,b)a>=b

四、继承

class Car:
    """一个Car类"""
    def __init__(self,make,model,year):
        self.make=make
        self.model=model
        self.year=year
        self.odometer_reading=0
    def update_odometer(self,mileage):
        if mileage>=self.odometer_reading:
            self.odometer_reading=mileage
        else:
            print("You can't roll back an odometer!")
    def increament_odometer(self,miles):
        self.odometer_reading+=miles

class Battery:
    """一个电池类"""
    def __init__(self,battery_size=75):
        self.battery_size=battery_size
    def get_range(self):
        if self.battery_size==75:
            range=260
        elif self.battery_size==100:
            range=315
        print(f"This car can go about {range} miles on a full charge.")

class ElectriCar(Car):
    """一个电动车类,继承自Car类,并且有一个属性为电池类对象"""
    def __init__(self, make, model, year):
        super().__init__(make, model, year)
        self.battery=Battery()
    def update_battery(self):
        if self.battery.battery_size!=100:
            self.battery.battery_size=100

elcar=ElectriCar("Toyota","A5","2020")
elcar.battery.get_range()
elcar.update_battery()
elcar.battery.get_range()

执行结果:

1)子类的__init__()方法

在创建一个子类对象时,如果你想子类对象也能调用父类中的方法和属性时,需要用到特殊函数super()。

super().__init__(make, model, year)会调用父类的__init__()方法

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值