zoukankan      html  css  js  c++  java
  • [ python ] 封装

    类中的私有属性

    在类中定义一个私有属性如下:

    class Person(object):
        def __init__(self, name):
            self.__name = name    # 定义私有属性 self.__name
    
    p = Person('hkey')
    print(p.__name)    # 外部不能直接调用私有属性
    
    执行结果:
    Traceback (most recent call last):
      File "E:/learn_python/day26/test6.py", line 11, in <module>
        print(p.__name)
    AttributeError: 'Person' object has no attribute '__name'

    私有属性的使用场景:

    1. 隐藏起一个属性,不想让类的外部调用
    2. 想要保护这个属性,不想让属性随便被改变
    3. 保护这个属性,不被子类继承

    虽然私有属性不能直接从外部调用,但是我们可以通过对象.__dict__ 尝试来获取这个属性试试:

    class Person(object):
        def __init__(self, name):
            self.__name = name
    
    p = Person('hkey')
    print(p.__dict__)
    print(p._Person__name)
    
    执行结果:
    {'_Person__name': 'hkey'}    # 执行 p.__dict__ 会直接获取对象的属性和方法
    hkey    # 在外部可以通过 p._Person__name 来获取类中的私有属性

    使用对象通过 _类名__属性名 来获取属性的方式并不推荐,在python中没有强制不允许查看类中私有属性,一切都靠自觉;

    将类中的方法当作属性查看修改删除

    property  将方法变成属性


    一个实例: 写一个类,计算圆的周长和面积

    from math import pi
    
    
    class Circle(object):
        def __init__(self, r):
            self.__r = r
    
        def per(self):    # 圆的周长
            return 2*pi*self.__r
    
        def area(self):    # 圆的面积
            return pi * self.__r **2
    
    c = Circle(5)
    print(c.area())
    print(c.per())

    在上面的代码中,我们要计算圆的周长和面积,都是通过对象.方法名() 去获取的。当我们使用 property 可以通过 对象.属性名 的方式调用函数内的方法,如下:

    from math import pi
    
    
    class Circle(object):
        def __init__(self, r):
            self.__r = r
        @property    # 通过装饰器的形式,将类中方法调用的方式修改为函数调用的方式
        def per(self):
            return 2*pi*self.__r
        @property
        def area(self):
            return pi * self.__r **2
    
    c = Circle(5)
    print(c.area)
    print(c.per)

    属性可以重新赋值,但是当使用 property 转换为属性调用的方式后,是不能直接赋值的。

    class Person(object):
        def __init__(self, name):
            self.__name = name
    
        @property    # 使用 property 改变类中函数的调用方式
        def name(self):
            return self.__name + ' run.'
    
    
    p = Person('hkey')
    print(p.name)

    setter

    当我们要修改对象 p 的 name 属性时,就需要使用 setter

    class Person(object):
        def __init__(self, name):
            self.__name = name
    
        @property
        def name(self):
            return self.__name + ' run.'
        @name.setter    # 使用 setter 装饰器
        def name(self, new_name):
            self.__name = new_name
    
    
    p = Person('hkey')
    print(p.name)
    p.name = 'xiaofei'    # 就可以实现从新赋值
    print(p.name)

    当使用 setter 时, 我们要明确命名规则:

    当使用 setter 时,我们不仅可以赋值,还可以做一些判断

    class Person(object):
        def __init__(self, name):
            self.__name = name
    
        @property
        def name(self):
            return self.__name + ' run.'
    
        @name.setter
        def name(self, new_name):
            if new_name.isalpha():  # new_name 必须是有字母或汉字组成
                self.__name = new_name
    
    
    p = Person('hkey')
    print(p.name)
    p.name = '123'  # 字符串是由数字组成,赋值失败
    print(p.name)

    deleter

    这个组合中最不常用的装饰器:

    作用:当要删除类中某个属性的时候使用 deleter 具体使用如下

    class Person(object):
        def __init__(self, name):
            self.__name = name
    
        @property
        def name(self):
            return self.__name + ' run.'
    
        @name.setter
        def name(self, new_name):
            if new_name.isalpha():  # new_name 必须是有字母或汉字组成
                self.__name = new_name
        @name.deleter
        def name(self):
            print('33[31;1m我要删除类中【__name】属性了.33[0m')
            del self.__name
    
    
    p = Person('hkey')
    del p.name
    
    执行结果:
    我要删除类中【__name】属性了.

    一个实例, 商品打折的例子。

    class Goods(object):
        dicount = 0.5
    
        def __init__(self, name, price):
            self.name = name
            self.__price = price
    
        @property
        def price(self):
            return self.__price * Goods.dicount
    
    
    apple = Goods('apple', 10)
    pear = Goods('pear', 5)
    print(apple.price)
    print(pear.price)

    在上面的实例中,当要改变所有商品的折扣时,只需要修改 dicount, 所有商品的折扣都会改变了。

    classmethod 类方法

    当要使用类方法时,需要满足以下两点:

    1. 把一个方法变成一个类中的方法,这个方法就直接可以被类调用,不需要依托任何对象
    2. 当一个方法的操作只涉及静态属性的时候,就应该使用 classmethod来装饰这个方法

    还是上面商品打折的例子:

    dicount 是一个类属性,我们就可以通过定义一个类方法来修改这个属性

    class Goods(object):
        dicount = 0.5
    
        def __init__(self, name, price):
            self.name = name
            self.__price = price
    
        @property
        def price(self):
            return self.__price * Goods.dicount
    
        @classmethod    # 定义一个类方法
        def modify_discount(cls, new_discount):    # cls: 类名,普通形参
            cls.dicount = new_discount
    
    apple = Goods('apple', 10)
    pear = Goods('pear', 5)
    Goods.modify_discount(0.2)  # 打 0.2 折    # 调用方式 类名.类方法(普通形参)
    print(apple.price)
    print(pear.price)
    
    执行结果:
    2.0
    1.0

    staticmethod 静态方法

    在完全面向对象的程序中,如果一个函数即和对象没有关系,也和类没有关系。那么就用 staticmethod 将这个函数变成一个静态方法

    比如在纯面向对象的编程中,编写一个用户登录的类:

    class Login(object):
        def __init__(self, user, pwd):
            self.user = user
            self.pwd = pwd
        def login(self):
            pass
    
        @staticmethod    # 静态方法虽然是在类中,和类是完全无关的;
        def get_user_pwd():
            user = input('输入用户名:')
            pwd = input('输入密码:')
            Login(user, pwd)
    
    Login.get_user_pwd()    # 进行登录

    使用类方法和静态方法要注意以下几点:

    1. 类方法和静态方法 都是类调用的
    2. 对象可以调用类方法和静态方法,但是一般建议使用类名去调用
    3. 类方法有一个默认参数 cls 代表这个类,静态方法 没有默认的参数 就像函数一样
  • 相关阅读:
    how to pass a Javabean to server In Model2 architecture.
    What is the Web Appliation Archive, abbreviation is "WAR"
    Understaning Javascript OO
    Genetic Fraud
    poj 3211 Washing Clothes
    poj 2385 Apple Catching
    Magic Star
    关于memset的用法几点
    c++ 函数
    zoj 2972 Hurdles of 110m
  • 原文地址:https://www.cnblogs.com/hukey/p/9963474.html
Copyright © 2011-2022 走看看