python的面向对象

类的写法

class 类名:
	def _init_(self,参数1,参数2)#构造函数
    	……
    def 成员函数1(self,参数1,参数2):
        ......
    def 成员函数2(self,参数1,参数2):
        ......
#所有成员函数,第一个参数都是self
class rectangle:
    def __init__(self,w,h):
        self.w,self.h=w,h
    def area(self):
        return self.w*self.h
    def perimeter(self):
        return 2*(self.w+self.h)
def main():
    w,h=map(int,input().split())
    rec=rectangle(w,h)#生成rectangle对象
    print(rec.area())
    print(rec.perimeter())

    rec.w,rec.h=10,5#在main里面,对对象的成员变量直接进行修改
    print(rec.area())
    print(rec.perimeter())
main()  

对象比较

  • python中所有的类,包括自定义的类,都有__ eq __方法

  • x==y的值,就是x.__ eq __(y)的值

    • 如果x.__ eq __ (y)没定义,则y. __ eq __(x)

    • 都没有定义则不适用

  • a!=b <=> a.__ ne __(b)
  • a<b <=> a.__ lt __(b)
  • a>b <=> a.__ gt__ (b)
  • a<=b <=> a.__ le __(b)
  • a>=b <=> a.__ ge __(b)

自定义对象的比较

  • 默认情况下,类的__ eq __方法,功能是判断两个对象的id是否相同
    • 即是不是同一块地址,功能等同于is
  • 默认情况下,自定义类的对象不能比较大小

因此,为实现自定义类的比较能力,应该进行重载

#二维平面点的重载
class point:
    def __init__(self,x,y=0):#y在这里是缺省参数
        self.x,self.y=x,y
    def __eq__(self,other):
        return self.x==other.x and self.y==other.y
    def __lt__(self,other):#相当于<号的重载
        if self.x!=other.x:
            return self.x <other.x
        else:
            return self.y<other.y
def main():
    m,n,a,b=map(int,input().split())
    p1=point(m,n)
    p2=point(a,b)
    print(p1==p2)
    print(p1<p2)
    lst=[p1,p2,point(-2,3),point(7,8),point(5,9),point(1,1)]
    lst.sort()#实现排序中,使用<号的重载
    for a in lst:
        print(a.x,a.y)
main()

对象输出

自定义类重写__ str __方法,将对象转为字符串(类型转换重载)

#二维平面点的重载
class point:
    def __init__(self,x,y=0):#y在这里是缺省参数
        self.x,self.y=x,y
    def __str__(self):
        return ("[%d,%d]"%(self.x,self.y))
print(str(point(2,4)))
#>>[2,4]
print(point(1,2))#也会自动将该对象类型,转换成可输出的字符串类型
#>>[1,2]

继承和派生

具有共同特点的类,避免重复写

#派生类写法
class 类名(基类):
    ......
import datetime
class Student:
    def __init__(self,id,name,gender,birthYear):
        self.id,self.name,self.gender,self.birthYear=id,name,gender,birthYear
    def __str__(self):#相当于流输出运算符的重载
        return ("Name:%s\nID:%s\nBirth Year:%d\nGender:%s\nAge:%d\n"%(self.name,self.id,self.birthYear,self.gender,self.countAge()))
    def countAge(self):
        return datetime.datetime.now().year-self.birthYear
class undergraduateStudent(Student):#本科生类,继承自学生,多增加一个系(department)成员变量
    def __init__(self,id,name,gender,birthYear,department):
        Student.__init__(self,id,name,gender,birthYear)
        self.department=department
    def qualifiedForBaoyan(self):
        print(self.name+" is qualified for BaoYan")
    def __str__(self):
        return Student.__str__(self)+"department:%s\n"%(self.department)
stu=Student("202100202098","Caaaaan","Boys",2002)
print(stu)
#>>Name:Caaaaan   
#>>ID:202100202098
#>>Birth Year:2002
#>>Gender:Boys    
#>>Age:20
stu2=undergraduateStudent("2021002020998","Caananan","Boys",2003,"Computer")
#>>Name:Caananan
#>>ID:2021002020998
#>>Birth Year:2003
#>>Gender:Boys
#>>Age:19
#>>department:Computer
print(stu2)

object类

python所有的类都有object类的派生类

因而都具有object类的各种属性

class A:
    def func(self):
        pass
print(dir(A))
#>>['__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__', 'func']

静态属性和静态方法

  • 静态属性被所有对象所共享,一共只有一份
  • 静态方法不是作用在具体的某个对象上的,不能访问非静态属性
  • 静态属性和静态方法这种机制存在的目的,就是为了少些全局变量和全局函数
class employee:
    totalSalary=0 #静态属性,记录发给员工的工资总数
    def __init__(self,name,income):
        self.name,self.income=name,income
    def pay(self,salary):
        self.income+=salary
        employee.totalSalary+=salary
    
    @staticmethod #不设置成静态函数,会报错
    def printTotalSalary():
        print(employee.totalSalary)
e1=employee("Can",1500)
e1.pay(2500)
e1.printTotalSalary()

对象作为集合的元素和字典的键

“可哈希”

  • 可哈希的东西,才可以作为字典的键和集合的元素
  • hash(x) 有定义,即x可哈希
  • hash(x) = x (如果x是整型常量)
    • hash(x) = x.__ hash __()(如果x不是整型常量)
  • object类有__ hash __()方法,返回值是个整数
  • 列表、集合、字典的__ hash __成员函数都被设置成None,因此他们都不能成为集合的元素或者字典的键,因为无法计算
  • 整数类型变量、小数、字符串、元组的哈希值,是根据自己的值算出来的
    • 只要值相同,哈希值就相同
    • 这个过程称为**“哈希映射”**

与集合、字典的关系

  • 只有两个对象的哈希值不同,才能处在同一个集合里或作为同一个字典的不同元素的键
    • 用哈希映射,实现集合的去重,和键值的去重
  • 若两个对象哈希值相同,但是a==b不成立,那么也可以处在同一个集合里或作为同一个字典的不同元素的键
  • 若dt是个字典,dt[x]计算过程如下:
    • 根据hash(x)去找x应该在的槽的编号
      • 如果该槽没有元素,则认为dt中没有键为x的元素
      • 如果有元素,则在槽中找一个元素y==x
        • 如果找到,则dt[x]=y的值(对应的键值)
        • 如果没有找到,则dt[x]没定义

自定义类的对象,默认情况下哈希值是根据对象id进行计算。

因此,只要 a is b不成立,a和b的哈希值就不同

可以重载自定义类的__ hash __()方法,使得对象的哈希值和对象的值相关,而不是id相关

  • 这样,只要对象的值相同,就不能处在一个集合里
  • 也不能作为同一字典不同元素的键
class A:
    def __init__(self,x):
        self.x=x
a,b=A(5),A(5)
dt={a:20,A(5):30,b:40}
print(len(dt),dt[a],dt[b])
#>>3 20 40
print(dt[A(5)])
#>>KeyError: <__main__.A object at 0x000001EE07C3CC10>

自定义类是否可哈希的讨论

默认情况下,a==b等价于a.__ eq __ (b);

  • 自定义类的默认 __ eq __函数是判断两个对象的地址是否相同
  • 自定义类的默认 __ hash __函数是判断两个对象的地址计算哈希值

如果自定义类重载了__ eq __ (self,other)成员函数,

则其__ hash __成员函数自动设置为None,变为不可哈希

因此表明,哈希的操作,是进行了a==b的调用

因此,想要满足自行定义哈希操作,应该重载eq和hash两个函数

class A:
    def __init__(self,x):
        self.x=x
    def __eq__(self,other):
        if isinstance(other,A):#判断other是不是类A的对象
            return self.x==other.x
        elif isinstance(other,int):#如果other是整数
            return self.x==other
        else:
            return False
    def __hash__(self):
        return hash(self.x)
a=A(3)
print(3==a)#>>True 重载过了
b=A(3)
d={A(5):10,A(3):20,a:30,b:20}
print(len(d))#>>2
print(d[a])#>>20
print(d[b])#>>20 保留最末尾那个
print(d[A(5)])#>>10
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Caaaaaan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值