~~面向对象进阶:类方法~~

进击のpython


面向对象进阶-类方法


  • classmethod 类方法

    python的类方法是通过@classmethod装饰器实现的

    类方法和普通的方法的区别是

    类方法只能访问类变量,不能访问实例变量

    class Dog(object):
        def __init__(self, name):
            self.name = name
    
        @classmethod
        def eat(self):
            print("%s is eating" % self.name)
    
    d = Dog("Mjj")
    d.eat()

    可以看到我调用Dog里面的eat方法,显示报错

    AttributeError: type object 'Dog' has no attribute 'name'

    果然,加上了这个类方法之后就没有办法访问实例变量(name)

    但是她说可以访问类的变量,我们来定义一下

    class Dog(object):
        name = "我是类变量"
    
        def __init__(self, name):
            self.name = name
    
        @classmethod
        def eat(self):
            print("%s is eating" % self.name)
    
    d = Dog("Mjj")
    d.eat()

    执行结果如下:

    我是类变量 is eating

    熬 就可以看出来,使用了类变量之后

    真的就只能调用类变量,而无法调用实例变量

    但是为什么只能调用类变量不能调用实例变量呢?

    我们打印一下self看一下传过来的是什么

    class Dog(object):
        name = "我是类变量"
    
        def __init__(self, name):
            self.name = name
    
        @classmethod
        def eat(self):
            print(self)
            print("%s is eating" % self.name)
    
    d = Dog("Mjj")
    d.eat()
    <class '__main__.Dog'>
    我是类变量 is eating

    可以看到,这个传进来的是个类的本身

    而不是实例的对象

    所以当然就无法调用实例的属性了呀!

    而且你也发现了,当你先@classmethod

    再进行方法的定义的时候

    你的括号里自动补充的不是self而是cls

    那到底有什么用呢?

    我在别人写的代码上有的时候会看到

    但是在我自己进行开发的时候,基本上没用到

    但是还是要给你举个例子,让你看看作用

    现有一个Student类, 每生成一个Student实例,学生总数就自动+1

    class Student(object):
        stu_num = 0  # 学员计数需存在类变量里,不能存在每个实例里,因为每个实例的内存是独立的,每实例化一次,数据就会被重置一次,不会累加
    
        def __init__(self, name):
            self.name = name
            self.stu_num += 1
            print("total student num:", self.stu_num)
    
    s1 = Student("张1")
    s2 = Student("张2")
    s3 = Student("张3")
    s4 = Student("张4")

    执行结果如下

    total student num: 1
    total student num: 1
    total student num: 1
    total student num: 1

    为何每次都是1呢? 不应该累加么?

    self.stu_num += 1

    相当于对每个实例进行了一次赋值, 因为self代表实例本身

    self.stu_num += 1 相当于s1.stu_num =1 , s2.stu_num = 1 …

    把这句代码改成如下就可以:

    class Student(object):
        stu_num = 0  # 学员计数需存在类变量里,不能存在每个实例里,因为每个实例的内存是独立的,每实例化一次,数据就会被重置一次,不会累加
    
        def __init__(self, name):
            self.name = name
            Student.stu_num += 1  # 直接用类名调用
            print("total student num:", self.stu_num)
    
    s1 = Student("张1")
    s2 = Student("张2")
    s3 = Student("张3")
    s4 = Student("张4")

    由于stu_num是每增加一个学员才加1的,不应该允许直接Student.stu_num+=1,不安全

    可以封装成私有变量,再通过类方法调用并计数

    class Student(object):
        __stu_num = 0  # 学员计数需存在类变量里,不能存在每个实例里
    
        def __init__(self, name):
            self.name = name
            self.add_stu_num()  # 相当于Student.add_stu_num() 初始化学员时调用
    
        @classmethod
        def add_stu_num(cls):  # 注意这里调用时传进来的其实是类本身,不是实例本身,所以参数名一般改为cls
            cls.__stu_num += 1
            print("total student num:", cls.__stu_num)
    
    s1 = Student("张1")
    s2 = Student("张2")
    s3 = Student("张3")
    s4 = Student("张4")

    但是有的同学说!

    Student.add_stu_num()

    也是可以调的,你这样写是为了防止作弊

    我这也能作弊啊!

    你说的没错!

    那么我们如何才能真的判断是不是真的要执行这句话?
    关键点是不是在于我是否真的产生了一个类对象

    所以,在执行之前就要有个验证

        def __init__(self, name):
            self.name = name
            self.add_stu_num(self)
        def add_stu_num(cls,obj):
            if obj.name:
                cls.__stu_num += 1
                print("total student num:", cls.__stu_num)

    这里我们用了obj

    obj stands for self instance

    这里的obj就是实例的意思

    那经过这个操作之后,再进行“作弊操作”,就不行了!


  • staticmethod 静态方法

    类方法不能访问实例变量,只能访问类变量是吧

    静态方法更狠!

    不仅实例变量,连类变量都不能访问!

    !!!!!!!!!!!!!!!!!!!

    @staticmethod装饰器即可把其装饰的方法变为一个静态方法

    什么是静态方法呢?其实不难理解,普通的方法,可以在实例化后直接调用

    并且在方法里可以通过self.调用实例变量或类变量

    但静态方法是不可以访问实例变量或类变量的

    一个不能访问实例变量和类变量的方法

    其实相当于跟类本身已经没什么关系了

    它与类唯一的关联就是需要通过类名来调用这个方法

    class Student(object):
        role = "stu"
    
        def __init__(self, name):
            self.name = name
    
        @staticmethod
        def fly(self):
            print("%s is flying..." % self.name)
    
    s = Student("hah")
    s.fly()
    TypeError: fly() missing 1 required positional argument: 'self'

    可以看到,并没有在调用fly方法的时候,默认添加进去一个参数

    而是报了一个缺少一个参数的错误,一个实例对象

    而当我把实例对象传进去,就没有问题了

    s = Student("hah")
    s.fly(s)
    hah is flying...

    其实你也就看出来了

    这个装饰器,将fly方法,和Student类的关系隔离了

    就算你在我的类下,你也不能调用我的方法

    不常用


  • property 属性方法

    属性方法的作用就是通过@property把一个方法变成一个静态属性

    class Student(object):
        stu_num = 0
    
        def __init__(self, name):
            self.name = name
    
        @property
        def fly(self):
            print("%s is flying..." % self.name)
    
    s = Student("haha")
    s.fly()

    直接这么调用会给你返回一个错误:

    TypeError: 'NoneType' object is not callable

    因为此时fly已经从方法变成属性了

    而不再是一个方法了

    那么怎么调用属性呢?

    实例.属性 是吧

    s.fly

    执行出来就是这种效果

    haha is flying...

    理解起来很简单

    那么到底有什么用呢?

    如果我想要一个静态变量

    我直接定义就好了

    为什么要这么做呢?

    首先,定义一个静态变量可以,但是只是个变量

    他除了存储数据,没有别的卵用

    但是通过装饰器@property是可以把方法变成静态的

    而方法是可以做事情(调用)的

    那在现实场景,有什么用呢?

    比如我们要找火车票

    是不是会先给服务器发信息

    然后返回状态,最后打印啊

    那么问题就来了

    你在查询票的时候,你会关注他到底是怎么拿到数据的吗?

    不会吧,而是会更多的关注票的信息

    那你在获得票的信息的时候是不是想查询的是票的属性

    而不是怎么获得的票!

    那我们就可以模拟的写一下!

    class Train(object):
        def __init__(self, name):
            self.train_name = name
    
        def checking_status(self):
            print("connecting trainline company api...... ")
            print("checking train %s status " % self.train_name)
            return 1
    
        @property
        def train_status(self):
            status = self.checking_status()
            if status == 0:
                print("train got canceled...")
            elif status == 1:
                print("train is arrived...")
            elif status == 2:
                print("train has departured already...")
            else:
                print("cannot confirm the train status...,please check later")
    
    f = Train("k470")
    f.train_status

    这样,用户在使用的时候就直接查询了票的属性

    骚操作来了奥!既然他是个静态属性,是不是也是属性

    那我能不能修改呢?

    f.train_status = 0
    AttributeError: can't set attribute

    ┗|`O′|┛ 嗷~~,会报错!

    其实也能理解

    你只是看上去是在查看属性

    但是实际上,你还是在使用调用方法

    所以不能修改也是合情合理

    但是毕竟是个属性,如果用户提出修改的要求也无可厚非

    对吧,你给我个属性,然后你说不能改?

    说不过去吧!

    所以这种问题怎么处理呢?

    class Train(object):
        def __init__(self, name):
            self.train_name = name
    
        def checking_status(self):
            print("connecting airline company api...... ")
            print("checking train %s status " % self.train_name)
            return 1
    
        @property
        def train_status(self):
            status = self.checking_status()
            if status == 0:
                print("train got canceled...")
            elif status == 1:
                print("train is arrived...")
            elif status == 2:
                print("train has departured already...")
            else:
                print("cannot confirm the train status...,please check later")
    
        @train_status.setter
        def train_status(self, status):
            print("changing... ...", status)
    
    f = Train("k470")
    f.train_status = 0

    在下面再写一个同名的函数,然后在上面加一个装饰器

    名字是这个同名的函数加上.setter方法

    同时要把你要修改的参数传进去(status)

    changing... ... 0

    那到底是不是真的修改了呢?

    我们可以设置一个变量来接收

    然后打印看看

        @train_status.setter
        def train_status(self, status):
            print("changing... ...", status)
            self.status = status
    
    f = Train("k470")
    f.train_status = 0
    print(f.status)

    打印了一下,澳!确实是有所改变

    那我们能删除嘛?

    del f.train_status

    可以看到,报错了是吧

    那我就想删除怎么办呢?

    一样的!

    在下面再写一个同名的函数,然后在上面加一个装饰器

    名字是这个同名的函数加上.deleter方法

    所以到此为止,我们知道了如何将方法变成一个静态的变量

    并对这个静态的方法进行操作!


*有点用熬*
*自己敲敲*

~~面向对象进阶:类方法~~

原文地址:https://www.cnblogs.com/jevious/p/11258926.html

时间: 2024-10-09 05:18:45

~~面向对象进阶:类方法~~的相关文章

Python之路【第八篇】:Python基础(24)——面向对象进阶

参考连接: Python 面向对象(初级篇) http://www.cnblogs.com/wupeiqi/p/4493506.html python 面向对象(进阶篇) http://www.cnblogs.com/wupeiqi/p/4493506.html python 面向对象及相关 http://www.cnblogs.com/wupeiqi/articles/5017742.html 面向对象进阶: 类成员之字段.方法.属性: 类成员修饰符: 类成员之特殊成员 1.类方法 普通的方法

2Python全栈之路系列之面向对象进阶及类成员

Python全栈之路系列之面向对象进阶及类成员 再次了解多继承 先来一段代码 #!/usr/bin/env python # _*_ coding:utf-8 _*_ class A:     def bar(self):         print("BAR")         self.f1()          class B(A):     def f1(self):         print("B")          class C:     def 

python面向对象进阶版

面向对象基础知识: 1.面向对象是一种编程方式,此编程方式的实现是基于对类和对象的使用: 2.类是一个模板,模板中包装了多个'函数'供使用(可以将多函数中公用的变量封装到对象中): 3.对象,根据模板创建的实例(即:对象),实例用于被包装在类中的函数: 4.面向对象三大特性:封装.继承和多态. 面向对象进阶篇详细介绍python类的成员.成员修饰符和类的特殊成员. 类的成员 类的成员可以分为三大类:字段.方法和属性 注:所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多少对象,在内存

10、python全栈之路-面向对象进阶

十.面向对象进阶 http://www.cnblogs.com/Eva-J/articles/7351812.html 1.isinstance和issubclass 1.1 isinstance(obj,cls) isinstance(obj,cls)检查是否obj是否是类 cls 的对象 1.2 issubclass(sub, super) issubclass(sub, super)检查sub类是否是 super 类的派生类 2.反射 #把一个字符串数据类型的变量变成一个真实存在在这个程序

python(24)- 面向对象进阶

面向对象基础知识: 1.面向对象是一种编程方式,此编程方式的实现是基于对类和对象的使用: 2.类是一个模板,模板中包装了多个‘函数’供使用(可以将多函数中公用的变量封装到对象中): 3.对象,根据模板创建的实例(即:对象),实例用于被包装在类中的函数: 4.面向对象三大特性:封装.继承和多态. 面向对象进阶篇详细介绍python类的成员.成员修饰符和类的特殊成员. 类的成员 类的成员可以分为三大类:字段.方法和属性 注:所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多少对象,在内存

Python之面向对象进阶

Python之面向对象进阶 进阶有:Python 类的成员.成员修饰符.类的特殊成员. 一.类的成员 类的成员可以分为三大类:字段.方法和属性. 注:所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多少对象,在内存中就有多少个普通字段.而其他的成员,则都是保存在类中,即:无论对象的多少,在内存中只创建一份. 1.字段 字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同, 普通字段属于对象 静态字段属于类 1 class Province:

Python基础-面向对象进阶

面向对象进阶 一 类中的装饰器方法  classmethod staticmethod property 1.1 property 一般情况下,方法都是动词.指某一类事物的动作 在计算圆形的周长和面积的时候,他们应该是圆形的属性,但是这里确是一个方法.这不符合python面向对象(能够完全区分属性和方法)的理念. 所以我们可以用一个装饰器去将一个属性性质的函数,装饰成一个属性.可以以调用属性的方式去调用他. from math import pi class Circle: def __init

Python学习之面向对象进阶

面向对象进阶当然是要谈谈面向对象的三大特性:封装.继承.多态 @property装饰器 python虽然不建议把属性和方法都设为私有的,但是完全暴露给外界也不好,这样,我们给属性赋值的有效性九无法保证,因此,为了使得对属性的访问既安全又方便,可以通过属性的getter(访问器)和setter(修改器)方法进行对应的操作,在python中,可以考虑使用@property包装器来包装getter和setter方法 class Person(object): def __init__(self,nam

八、面向对象进阶

面向对象进阶 在前面的章节我们已经了解了面向对象的入门知识,知道了如何定义类,如何创建对象以及如何给对象发消息.为了能够更好的使用面向对象编程思想进行程序开发,我们还需要对Python中的面向对象编程进行更为深入的了解. @property装饰器 之前我们讨论过Python中属性和方法访问权限的问题,虽然我们不建议将属性设置为私有的,但是如果直接将属性暴露给外界也是有问题的,比如我们没有办法检查赋给属性的值是否有效.我们之前的建议是将属性命名以单下划线开头,通过这种方式来暗示属性是受保护的,不建