Python静态方法和类方法

静态方法和类方法

1.静态方法

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

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

dog = Dog()
Dog.introduce()
dog.introduce()

犬科哺乳动物,属于肉食目
犬科哺乳动物,属于肉食目

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

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

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

类方法

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

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

使用场景:

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

注意:

类中定义了同名的对象方法,类方法以及静态方法时,调用方法会优先执行最后定义的方法

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

    @classmethod
    def demo_method(cls):
        print('类方法。')

    @staticmethod
    def demo_method(): #最后被定义。调用时优先执行
        print('静态方法。')

dog = Dog()
Dog.demo_method()
dog.demo_method()

静态方法。
静态方法。

property

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

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

简单的实现

class Account(object):
    def __init__(self,name,money):
        self.name = name
        self.money = money
        

问题:

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

改进1

隐藏实现细节

对于账户信息而言,金额不允许让用户直接修改。如果修改,只能去窗口办理。

程序的实现该如何去做?

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

这个时候,考虑私有属性

class Account(object):
    def __init__(self,name,money):
        self.name = name
        self.money = money

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

但是有一个新的问题,如果确实需要对这两个属性进行修改,该怎么办?

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

class Account(object):
    def __init__(self,name,money):
        self.name = name
        self.__balance = money

    def get_name(self):
        return self.name
    def set_balance(self,money):
        self.__balance = money
    def get_balance(self):
        return self.__balance
    

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

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

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

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

改进3 保证数据的有效性

set_balance方法中,对传入数据进行有效判断,如果是无效数据,提示用户出问题。

class Account(object):
    def __init__(self,name,money):
        self.name = name
        self.__balance = money

    def get_name(self):
        return self.name
    def set_balance(self,money):
        if isinstance(money,int):
            if money > 0:
                self.__balance = money
            else:
                raise ValueError('输入金额不正确')
        else:
            raise ValueError('输入金额不是数字')

        self.__balance = money
    def get_balance(self):
        return self.__balance

经过几版本的迭代,程序看上去越来越健壮,安全性也越来越高。

但是使用过程中,可以更精炼一点。

属性操作

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

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

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

  • 参数1:属性的获取方法
  • 参数2:属性的设置方法
  • 参数3:属性的删除方法
  • 参数4:属性描述

(要按照顺序来,不然会报错)

class Account(object):
    def __init__(self,name,money):
        self.__name = name
        self.__balance = money

    def __get_name(self):
        return self.__name

    def set_balance(self,money):
        if isinstance(money,int):
            if money > 0:
                self.__balance = money
            else:
                raise ValueError('输入金额不正确')
        else:
            raise ValueError('输入金额不是数字')


    def get_balance(self):
        return self.__balance
    #使用property类来为属性设置遍历的访问方式
    name = property (__get_name)
    balance = property(get_balance,set_balance)

ac = Account('Tom',10000)
print(ac.name)
print(ac.balance)
ac.balance = 1000
print(ac.balance)

Tom
10000
1000

class Account(object):
    def __init__(self, name, money):
        self.__name = name
        self.__balance = money

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

    @property
    def balance(self):
        return self.__balance

    @balance.setter
    def balance(self, money):
        if isinstance(money, int):
            if money > 0:
                self.__balance = money
            else:
                raise ValueError('输入金额不正确')
        else:
            raise ValueError('输入金额不是数字')


ac = Account('Tom', 10000)
print(ac.name)
print(ac.balance)
ac.balance = 1000
print(ac.balance)

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

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 = 'aa'
cat.age = 8
cat.introduce()

name is aa,age is : 8

方法内定义属性

  • 使用self操作属性和对象的变量名在效果上类似。
class Cat:
    def introuce(self):
        self.type = '小型动物'

cat = Cat()
cat.introuce()
print(cat.type)

__new__方法

  • 创建对象时,系统会自动调用__new__方法。
  • 开发者可以使用__new__方法来自定义对象的创建过程。

__new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供
__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例
__init__有一个参数self,就是这个__new__返回的实例,__init____new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值
- 如果创建对象时传递了自定义参数,且重写了new方法,则new也必须 “预留” 该形参,否则__init__方法将无法获取到该参数

class A(object):
    def __new__(cls, x):
        print ('this is in A.__new__, and x is ', x)

        return super(A, cls).__new__(cls)

    def __init__(self, y):
        print ('this is in A.__init__, and y is ', y)

class C(object):
    def __new__(cls, n):
        print ('this is in C.__new__, and n is ', n)
        return super(C, cls).__new__(cls)

    def __init__(self, a):
        print ('this is in C.__init__, and a is ', a)


class B(A):
    def __new__(cls, z):
        print ('this is in B.__new__, and z is ', z)
        return A.__new__(cls, z)

    def __init__(self, m):
        print ('this is in B.__init__, and m is ', m)

# class B(A):
#     def __new__(cls, z):
#         print 'this is in B.__new__, and z is ', z
#         return object.__new__(cls)
#     def __init__(self, m):
#         print 'this is ni B.__init__, and m is ', m

if __name__ == '__main__':
    a = A(100)
    print ('=' * 20)
    b = B(200)
    print (type(b))

this is in A.new, and x is 100
this is in A.init, and y is 100

====================

this is in B.new, and z is 200
this is in A.new, and x is 200
this is in B.init, and m is 200
<class ‘main.B’>

__call__方法

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

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

而对于,__call__方法的执行时由对象加括号触发的,即对象()或者类()

class A(object):
    def __call__(self,x):
        print('call',x)
a = A()
a('123')

__doc__方法

该属性无法继承给子类

class Foo:
    """这是一段说明"""
    pass
class Bar(Foo):
    pass
print(Foo.__doc__)
print(Bar.__doc__)

这是一段说明

None

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值