当前位置:   article > 正文

静态方法和类方法

静态方法和类方法

静态方法和类方法

静态方法

  • 通过装饰器@staticmethod 来进行装饰。静态方法既不需要传递类对象,也不需要传递实例对象
  • 静态方法也可以通过实例对象和类对象去访问。
class Dog:
    type = '狗'

    def __init__(self):
        name = None

    @staticmethod
    def introduce():  # 静态方法不会自动传递实例对象和类对象
        print('犬科哺乳类动物,属于肉食目')
    

dog = Dog()
Dog.introduce()
dog.introduce()
#输出
犬科哺乳类动物,属于肉食目
犬科哺乳类动物,属于肉食目
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

静态方法是类中的函数,不需要实例

静态方法主要是用来存放逻辑性的代码,逻辑上属于类,但和类本身没有关系。在静态方法中,不会涉及类中属性和方法的操作。

可以理解为静态方法是一个独立单纯的函数,仅仅是托管与某个类的名称空间中,便于维护和管理。

使用场景:

  • 当方法中 既不需要使用实例对象(如实例对象,实例属性),也不需要使用类对象 (如类属性、类方法、创建实例等)时,定义静态方法
  • 取消不需要的参数传递,有利于 减少不必要的内存占用和性能消耗
  • 如果在类外面写一个同样的函数来做这些事,打乱了逻辑关系,导致代码维护困难,使用静态方法。

类方法

  • 类对象所拥有的方法
  • 需要用装饰器@classmethod来标识其为类方法
  • 对于类方法,第一个参数必须是类对象,一般cls作为第一个参数
class Dog:
    __type = '狗'

    # 类方法,用class来进行装饰
    @classmethod
    def get_type(cls):
        return cls.__type

print(Dog.get_type())
#输出
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

使用场景

  • 当方法中需要使用类对象(如访问私有属性等)时,定义类方法。
  • 类方法一般和类属性配合使用。

注意:类中定义同名的方法,会优先调用最后一个定义的。

class Dog:
    def demo_method(self):
        print('对象方法。')

    @classmethod
    def demo_method(cls):
        print('类方法。')
    @staticmethod
    def demo_method():           #最后被定义,调用时优先进行
        print('静态方法。')
dog = Dog()
Dog.demo_method()
dog.demo_method()
#输出
静态方法。
静态方法。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

property

概述
  • 在Python中主要为属性提供一个便利的操作方式

如果我们现在需要设计一个银行账户类,这个类中包含账户人姓名和余额。(假如不考虑接口操作)

class Bank:
    def __init__(self, name, money):
        self.name = name
        self.money = money
        
  • 1
  • 2
  • 3
  • 4
  • 5

问题:

不安全(设计简单,所有属性可以被外部访问修改,非常不安全)

改进1 隐藏实现细节

金额不允许直接让用户修改,如果修改只能去窗口办理。

在使用对象时,尽量不要让使用者直接操作对象中的属性,因为直接操作会带来安全隐患。

这个时候考虑私有属性

class Bank:
    def __init__(self, name, money):
        self.__name = name
        self.__money = money
  • 1
  • 2
  • 3
  • 4

代码改进以后,将所有的属性设计成私有属性。确实从外部使用时,不知道内部的属性,不能直接修改对象,隐藏了实现的细节。

改进2 提供一个精确的访问

添加方法,访问私有属性。

class Bank:
    def __init__(self, name, money):
        self.__name = name
        self.__money = money

    def get_name(self):
        return self.__name

    def get_money(self):
        return self.__money

    def set_money(self, n):
        self.__money += n
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

经过修改,外部使用这个类的对象时,想使用对象中的属性,只能通过类中提供的 set/get 接口来操作,提高了程序的安全性。

这样,程序基本达到了设计需求,但是能不能更加完善呢?

如果在使用这个类的对象过程中,由于误操作,传入了不正常的数据,导致数据异常。该如何以避免这种情况发生呢?

比如:设置金额时出现了负数,或字符串,或其它类型的对象。

改进3 保证数据的有效性
class Bank:
    def __init__(self, name, money):
        self.__name = name
        self.__money = money

    def get_name(self):
        return self.__name

    def get_money(self):
        return self.__money

    def set_money(self, n):
        if isinstance(n, int):
            if n > 0:
                self.__money = n
            else:
                raise ValueError('输入金额错误')
        else:
            raise ValueError('输入金额不是数字')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

属性操作

property类

在python中,提供了一个property类,通过对创建这个类的对象的设置,可以使用对象的私有属性时,可以不再使用函数的调用方式,而是相对普通的公有属性一样去使用属性,为开发者提供便利。

格式:

property(fget=None,fset=None,fdel=None,doc=None)  #property attribute
  • 1

property 是一个类,__init__方法由四个参数组成,实例后返回一个用来操作属性的对象

  • 参数一:属性的获取方法
  • 参数二:属性的设置方法
  • 参数三:属性的删除方法
  • 参数四:属性描述
class Bank:
    def __init__(self, name, money):
        self.__name = name
        self.__money = money

    def __get_name(self):
        return self.__name

    def get_money(self):
        return self.__money

    def set_money(self, n):
        if isinstance(n, int):
            if n > 0:
                self.__money = n
            else:
                raise ValueError('输入金额错误')
        else:
            raise ValueError('输入金额不是数字')

    # 使用property类来为属性设置便利的访问方式
    name = property(__get_name)
    money = property(get_money, set_money)


ba = Bank('Tom', 10000)
print(ba.name)
print(ba.money)
ba.money = 1000
print(ba.money)
#输出
Tom
10000
1000
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

通过 property 类实例对象以后,在使用对象中的属性时,就可以像使用普通公有属性一样来调用,但是实际调用的还是 set/get 方法。 在实例 property 对象时,不是所有的参数都需要写,比如示例中的 name 只提供了 get 方法,并且是一个私有的方法。这样就完全隐藏了内部的实现细节 。

另一种写法。

class Bank:
    def __init__(self, name, money):
        self.__name = name
        self.__money = money

    @property
    def name(self):
        return self.__name

    @property
    def money(self):
        return self.__money

    @money.setter
    def money(self, n):
        if isinstance(n, int):
            if n > 0:
                self.__money = n
            else:
                raise ValueError('输入金额错误')
        else:
            raise ValueError('输入金额不是数字')

    
ba = Bank('Tom', 10000)
print(ba.name)
print(ba.money)
ba.money = 1000
print(ba.money)
#输出
Tom
10000
1000
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

self

如果对象的方法中需要使用该对象的属性,该怎么办?

  • 关键字’self’主要用于对象方法中,表示调用该方法的对象
  • 在方法中使用self,可以获取到调用当前方法的对象,进而获取该对象的属性和方法。

调用对象的方法时,为什么不需要设置self对应的参数?

  • 某个对象调用其方法时,Python解释器会把这个对象作为第一个参数传递给方法。所有,开发者只需要在定义的时候预留第一个参数self即可。
class Cat:
    # 方法
    def introduce(self):
        print('name is: %s,age is: %d' % (self.name, self.age))


cat = Cat()
cat.name = 'abc'
cat.age = 123
cat.introduce()
#输出
name is: abc,age is: 123
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

方法内定义属性

  • 使用self操作属性和对象的变量名在效果上类型。如果属性在赋值时没有被定义。就自动定义一个属性并赋值。
class Cat:
    # 方法
    def introduce(self):
        self.type = '小型动物'


cat = Cat()
cat.introduce()
print(cat.type)
#输出
小型动物
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

'_new_'方法

  • 创建对象时,系统会自动调用’_new_'方法。

  • 开发者可以使用’_new_'方法自定义对象的创建过程。

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

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

  • __init__有一个参数self,就是这个__new__返回的实例,__init____new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值

  • 如果创建对象时传递了自定义参数,且重写了new方法,则new也必须 “预留” 该形参,否则__init__方法将无法获取到该参数

class Cat:
    # 方法
    def __new__(cls, name):
        print('创建对象')
        return object.__new__(cls)

    def __init__(self, name):
        print('对象初始化')
        self.name = name

    def __str__(self):
        return '%s' % self.name


c = Cat('猫')
print(c)
#输出
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

'_call_'方法

对象后面加括号,触发执行

构造方法的执行是有创建对象触发的,即:对象=类名()

而对于,’_call_'方法的执行是由对象后加括号出发的,即对象()或者类()

class A:
    def __init__(self):
        pass
    def __call__(self, *args, **kwargs):
        print('__call__called,print x:',*args, **kwargs)

a=A()
a('123')
#输出
__call__called,print x: 123
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

‘_doc_’

调用类的说明,这个属性无法继承给子类。

class Foo:
    '''这是一段说明'''
    pass

print(Foo.__doc__)
#输出
这是一段说明
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/码创造者/article/detail/903511
推荐阅读
相关标签
  

闽ICP备14008679号