• python之路 -- 面向对象进阶


    property、classmethod、staticmethod

    1.property

    把方法伪装成了属性

     1 from math import pi
     2 class Circle:
     3     def __init__(self,r):
     4         self.r = r
     5     @property        #把方法伪装成了属性
     6     def perimeter(self):
     7         return 2*pi*self.r
     8     @property
     9     def area(self):
    10         return self.r**2*pi
    11 
    12 c1 = Circle(5)
    13 print(c1.area)     
    14 # 圆的面积   #之前的调用方法为c1.area()
    15 print(c1.perimeter) 
    16 # 圆的周长   #之前的调用方法为c1.perimter()
     1 #练习
     2 #BMI指数(BMI是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解)
     3 # 成年人的BMI数值
     4 # 过轻:低于18.5
     5 # 正常:18.5~23.9
     6 # 过重:24~27
     7 # 肥胖:28~32
     8 # 非常肥胖:28~32
     9 #     体质指数(BMI)=体重(kg)/身高^2(m)
    10 #     例如:70kg÷(1.75*1.75)=22.86
    11 
    12 class People:
    13     def __init__(self,name,high,weight):
    14         self.name = name
    15         self.high = high
    16         self.weight = weight
    17 
    18     @property
    19     def bmi(self):
    20         return self.weight/self.high**2
    21 
    22 xiaoli = People("小黎",1.66,47)
    23 print(xiaoli.bmi()) #未加@property时,用此调用
    24 print(xiaoli.bmi)   #加了@property时,用此调用
    练习
     1 class Goods:
     2     def __init__(self):
     3         # 原价
     4         self.original_price = 100
     5         # 折扣
     6         self.discount = 0.8
     7 
     8     @property
     9     def price(self):
    10         # 实际价格 = 原价 * 折扣
    11         new_price = self.original_price * self.discount
    12         return new_price
    13 
    14     @price.setter    #使用了这个可以修改类中的属性
    15     def price(self, value):
    16         self.original_price = value
    17 
    18     @price.deleter
    19     def price(self):
    20         del self.original_price
    21         print('已删除')
    22 obj = Goods()
    23 print(obj.price)  # 获取商品价格
    24 obj.price = 100   # 修改商品原价
    25 print(obj.price)
    26 del obj.price     # 删除商品原价
    27 #执行del,会调用deleter装饰的方法
    28 
    29 #执行结果为:
    30 # 80.0
    31 # 80.0
    32 # 已删除
    View Code

    classmethod   类方法

    把一个方法 变成一个类中的方法,这个方法就直接可以被类调用,不需要依托任何对象

    1 class Classmethod_Demo():
    2     role = 'dog'
    3 
    4     @classmethod
    5     def func(cls):
    6         print(cls.role)
    7 
    8 Classmethod_Demo.func()
    9 #输出结果为:dog
     1 class Goods:
     2     __discount = 0.8
     3     def __init__(self,name,price):
     4         self.name = name
     5         self.__price = price
     6     @property
     7     def price(self):
     8         return self.__price * Goods.__discount
     9     @classmethod   
    10     # 把一个方法 变成一个类中的方法,这个方法就直接可以被类调用,不需要依托任何对象
    11     def change_discount(cls,new_discount):  # 修改折扣
    12         cls.__discount = new_discount
    13 apple = Goods('苹果',5)
    14 print(apple.price)  #--》4.0
    15 Goods.change_discount(0.5)   # Goods.change_discount(Goods)
    16 print(apple.price)  #--》2.5
    17 # 当这个方法的操作只涉及静态属性的时候 就应该使用classmethod来装饰这个方法
    View Code

    staticmathod 静态的方法

    用staticmethod将这个函数变成一个静态方法

     1 class Login:
     2     def __init__(self,name,password):
     3         self.name = name
     4         self.pwd = password
     5     def login(self):pass
     6 
     7     @staticmethod
     8     def get_usr_pwd():   # 静态方法
     9         usr = input('用户名 :')
    10         pwd = input('密码 :')
    11         Login(usr,pwd)
    12 
    13 Login.get_usr_pwd()
    14 # 在完全面向对象的程序中,
    15 # 如果一个函数 既和对象没有关系 也和类没有关系 那么就用staticmethod将这个函数变成一个静态方法

    # 类方法和静态方法 都是类调用的

    # 对象可以调用类方法和静态方法。但是,一般情况下 推荐用类名调用

    # 类方法 有一个默认参数 cls 代表这个类 cls

    # 静态方法 没有默认的参数 就像函数一样


    内置函数isinstance()和issubclass()

    isinstance(obj,cls)检查是否obj是否是类 cls 的对象

    issubclass(sub, super)检查sub类是否是 super 类的子类

    class A:pass
    class B(A):pass
    a = A()
    print(isinstance(a,A)) ->True   #检查对象a是否是类A中的对象,是返回True
    print(issubclass(B,A)) ->True   #检查类B是否是类A的子类
    print(issubclass(A,B)) ->False

    反射

    python面向对象中的反射:通过字符串的形式操作对象相关的属性。

    python中的一切事物都是对象(都可以使用反射)

    面向对象中的几个内置函数

      ——hasattr,setattr,getattr,delattr

     1 class Foo:
     2     f = '类的静态变量'
     3     def __init__(self,name,age):
     4         self.name=name
     5         self.age=age
     6 
     7     def say_hi(self):
     8         print('hi,%s'%self.name)
     9 
    10 obj=Foo('egon',73)
    11 
    12 #检测某个类是否含有某属性
    13 print(hasattr(obj,'name'))    
    14 print(hasattr(obj,'say_hi'))
    15 
    16 #获取某个类中的属性
    17 #第一个位置为所属的对象,第二个为变量的字符串形式
    18 n=getattr(obj,'name')    #等价于obj.name
    19 print(n)
    20 func=getattr(obj,'say_hi')
    21 func()
    22 
    23 print(getattr(obj,'aaaaaaaa','不存在啊')) #报错
    24 
    25 #设置属性
    26 setattr(obj,'*名字*',True)
    27 setattr(obj,'show_name',lambda self:self.name+'-名字')
    28 print(obj.__dict__)
    29 print(obj.show_name(obj))
    30 
    31 #删除属性
    32 delattr(obj,'age')
    33 delattr(obj,'show_name')
    34 # delattr(obj,'show_name111')#不存在,报错
    35 
    36 print(obj.__dict__)
    37 
    38 输出结果为:
    39 True
    40 True
    41 egon
    42 hi,egon
    43 不存在啊
    44 {'name': 'egon', 'age': 73, '*名字*': True, 'show_name': <function <lambda> at 0x000002DBD32D2E18>}
    45 egon-名字
    46 {'name': 'egon', '*名字*': True}

    __str__、__repr__

    当使用print输出对象的时候,只要自己定义了__str__(self)方法,那么就会打印从在这个方法中return的数据 

     1 class Car:
     2     def __init__(self, newWheelNum, newColor):
     3         self.wheelNum = newWheelNum
     4         self.color = newColor
     5 
     6     def __str__(self):
     7         msg = "嘿。。。我的颜色是" + self.color + "我有" + int(self.wheelNum) + "个轮胎..."
     8         return msg
     9 
    10     def move(self):
    11         print('车在跑,目标:夏威夷')
    12 
    13 BMW = Car(4, "白色")
    14 print(BMW)
    15 #输出结果:嘿。。。我的颜色是白色,我有4个轮胎...
    View Code
     1 class B:
     2     def __str__(self):
     3         return 'str : class B'
     4 
     5     def __repr__(self):
     6         return 'repr : class B'
     7 
     8 b = B()
     9 print('%s' % b)
    10 print('%r' % b)
    11 #执行结果为:
    12 # str : class B
    13 # repr : class B
    View Code

    __del__

    创建对象后,python解释器默认调用__init__()方法;

    当删除一个对象时,python解释器也会默认调用一个方法,这个方法为__del__()方法

    (在实例化一个对象的时候也会调用__del__方法)

     1 class Foo:
     2 
     3     def __del__(self):
     4         print('执行我啦')
     5 
     6 f1=Foo()
     7 del f1
     8 print('------->')
     9 
    10 #输出结果
    11 执行我啦
    12 ------->
    13 #在调用del时自动执行了类的内部__del__方法
    View Code

    __getitem__、__setitem__、__delitem__

     1 class Foo:
     2     def __init__(self,name):
     3         self.name=name
     4 
     5     def __getitem__(self, item):
     6         print(self.__dict__[item])
     7 
     8     def __setitem__(self, key, value):
     9         self.__dict__[key]=value
    10     def __delitem__(self, key):
    11         print('del obj[key]时,我执行')
    12         self.__dict__.pop(key)
    13     def __delattr__(self, item):
    14         print('del obj.key时,我执行')
    15         self.__dict__.pop(item)
    16 
    17 f1=Foo('sb')
    18 f1['age']=18
    19 f1['age1']=19
    20 del f1.age1
    21 del f1['age']
    22 f1['name']='alex'
    23 print(f1.__dict__)
    24 
    25 #执行结果为:
    26 # del obj.key时,我执行
    27 # del obj[key]时,我执行
    28 # {'name': 'alex'}
    View Code

    __new__

    __new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供

    __new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例

     1 class A(object):
     2     def __init__(self):
     3         print("这是 init 方法")
     4 
     5     def __new__(cls):
     6         print("这是 new 方法")
     7         return object.__new__(cls)
     8 
     9 A()
    10 #输出结果为:
    11 #这是init方法
    12 #这是new方法
    View Code

    类在实例化的时候会自动执行__init__方法和__new__方法 

     1 class A:
     2     def __init__(self):
     3         self.x = 1
     4         print('in init function')
     5     def __new__(cls, *args, **kwargs):
     6         print('in new function')
     7         return object.__new__(A, *args, **kwargs)
     8 
     9 a = A()
    10 #实例化时自动会调用__new__方法和__init__方法,先调用__new__方法
    11 
    12 #执行结果为:
    13 # in new function
    14 # in init function
    View Code
    class Foo(object):
        def __init__(self):
            print(111)
    
        def __new__(cls, *args, **kwargs):
            return 'new'
    
    obj = Foo()
    print(obj)
    
    # new
    
    # 只会输出new,不会打印111
    View Code

    __call__

    对象后面加括号,触发执行。
    注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

     1 class Foo:
     2     def __init__(self):
     3         pass
     4     
     5     def __call__(self, *args, **kwargs):
     6 
     7         print('__call__')
     8 
     9 obj = Foo() # 执行 __init__
    10 obj()       # 执行 __call__
    11 
    12 #执行结果:__call__
    View Code

    __len__

     1 class A:
     2     def __init__(self):
     3         self.a = 1
     4         self.b = 2
     5         self.c = 1
     6 
     7     def __len__(self):
     8         return len(self.__dict__)   #返回内中属性的个数
     9 a = A()
    10 print(len(a))
    11 #执行结果为:3
    12 #执行len方法会自动调用类中的__len__方法
    View Code

    __hash__

     1 class A:
     2     def __init__(self):
     3         self.a = 1
     4         self.b = 2
     5 
     6     def __hash__(self):
     7         return hash(str(self.a)+str(self.b))
     8 a = A()
     9 print(hash(a))
    10 #类的外部执行hash()时会调用类中的__hash__方法
    View Code

    __eq__

    当判断两个对象的值是否相等时,就会执行类中__eq__方法,且得到的返回值将和在类中定义的__eq__的返回值的真假一致
     1 class A:
     2     def __init__(self):
     3         self.a = 1
     4         self.b = 2
     5 
     6     def __eq__(self,obj):
     7         if  self.a == obj.a and self.b == obj.b:
     8             return True
     9 a = A()
    10 b = A()
    11 print(a == b)
    12 #True
    View Code

    文章中大部分实例都来自Eva_J老师的文章,原文见博客

  • 相关阅读:
    盘符格式转换成NTFS格式
    jdk环境变量配置
    修改mysql密码
    端口占用解决
    程序执行原理
    第一个Python程序
    pip安装第三方库失败的问题
    windows本地安装mongoDB并且安装可视化工具studio 3t
    开发时前端测试方法
    虚拟机配置vimrc
  • 原文地址:https://www.cnblogs.com/aberwang/p/9333947.html
Copyright © 2020-2023  润新知