面向对象,类中的各种方法

面向对象+

静态方法和类方法

静态方法
导入

通过装饰器@staticmethod来进行装饰。静态方法既不需要传递类对象也不需要传递实例对象

静态方法也可以通过实例对象和类对象去访问

class Dog:
    type='狗'
    def __init__(self):
        name=None
    #静态方法
    @staticmethod
    def introduce():#静态方法不会自动传递实例对象和类对象
        print('犬科哺乳动物')
dog=Dog()#实例化
Dog.introduce()
dog.introduce()
#结果
犬科哺乳动物
犬科哺乳动物

如果不添加@staticmethod,由于introduce没有传入self,会报错。所有静态方法是类中的函数,不需要实例。

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

不会涉及类中属性和方法的操作。

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

使用场景
  • 当方法中 既不需要使用实例对象(如实例对象,实例属性),也不需要使用类对象 (如类属性、类方法、创建实例等)时,定义静态方法
  • 取消不需要的参数传递,有利于 减少不必要的内存占用和性能消耗
  • 如果在类外面写一个同样的函数来做这些事,打乱了逻辑关系,导致代码维护困难,使用静态方法。
类方法
解释
  • 类对象所拥有的方法
  • 需要用修饰器@classmethod来标识其为类方法
  • 对于类方法,第一个参数必须是类对象,一般以cls作为第一个参数
class Dog:
    __type='狗'
    #类方法,用class来进行修饰
    @classmethod
    def get_type(cls):
        return cls.__type
print(Dog.get_type())
#结果
使用场景

当方法中需要使用类对象(如访问私有类属性),定义类方法

类方法一般如类属性配合使用

注意

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

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()
#结果
静态方法
静态方法

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.__money=money
    def get_name(self):
        return self.__name
    def set_balance(self,money):
        self.__money=money
    def get_balance(self):
        return self.__money

改进3:保证数据的有效性

如果self.__money输入不合法(如输入一个字符串abc)

class Account(object):
    def __init__(self,name,money):
        self.__name=name
        self.__money=money
    def get_name(self):
        return self.__name
    def set_balance(self,money):
        if isinstance(money,int):
            if money>0 :
                self.__money=money
            else:
                raise ValueError('输入金额不正确')
        else:
            raise ValueError('输入的数据类型不对')
    def get_balance(self):
        return self.__money

经过几次更改,程序更加实用,安全性也越来越高,但是复杂度也在增加

实例

在python中,提供一个property类,通过对创建这个类的对象的设置,在使用对象的私有属性时,可以

不再使用属性的函数的调用方式,而是像普通的公有属性一样取使用,方便开发人员使用。

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

  • fget:属性的获取方法
  • fset: 属性的设置方法
  • fdel:属性的删除方法
  • doc:属性描述

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

class Account(object):
    def __init__(self,name,money):
        self.__name=name
        self.__money=money
    def __get_name(self):
        return self.__name
    def set_balance(self,money):
        if isinstance(money,int):
            if money>0 :
                self.__money=money
            else:
                raise ValueError('输入金额不正确')
        else:
            raise ValueError('输入的数据类型不对')
    def get_balance(self):
        return self.__money
    #设置property类来为属性设置便利的访问方式
    name=property(__get_name)
    balance=property(get_balance,set_balance)
ac=Account('bob',18000)
print(ac.name)
print(ac.balance)
ac.balance=28000
print(ac.balance)
#结果:
bob
18000
28000
基本形式
class C:
    def __init__(self):
        self._x = None

    def getx(self):
        return self._x

    def setx(self, value):
        self._x = value

    def delx(self):
        del self._x

    x = property(getx, setx, delx, "I'm the 'x' property.")
c=C()
print(c.x)
c.x=1    
print(c.x)
del c.x
print(c.x)
#结果
None #未设置值,直接读取初始值为None
Traceback (most recent call last):
1    #完成赋值,读取新的值为1
  File "D:/text.py", line 46, in <module> #删除后该值不存在,报错
    print(c.x)
  File "D:/text.py", line 32, in getx
    return self._x
AttributeError: 'C' object has no attribute '_x'
使用装饰器
class C:
    def __init__(self):
        self._x = None
    @property
    def x(self):
        """I'm the 'x' property."""
        return self._x
    @x.setter
    def x(self, value):
        self._x = value
    @x.deleter
    def x(self):
        del self._x
c=C()
print(c.x)
c.x=1
print(c.x)
del c.x
print(c.x)      
#结果与上面的完全相同
总结

property最大的好处就是在类中把一个方法变成属性调用,起到既能检查属性,还能用属性的方式来访问该属性的作用。进行不同的操作(删改查)我们可以不需要记相应的方法的名称,而是直接对x进行操作

self

引入

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

关键字self主要用于对象方法中,表示调用该方法的对象。

在方法中使用self,可以获取到调用当前方法的对象,进而获取该对象的属性和方法。

调用对象的方法时,某个对象调用其方法时,python解释器会把这个对象作为第一个参数传递给方法,所有,开发者只需要在定义的时候预留第一个参数self即可。

class Cat:
    #方法
    def introduce(self):
        print('aaa')
cat=Cat()			#实例化
cat.introduce()		#能够输出	
Cat.introduce()		#self未捕捉,将其视为普通的函数,直接报错没有传入位置参数

使用self操作属性和对象的变量名在效果上类似。如果属性在赋值时还没有被定义。就会自动定义一个属性并赋值。

补充三种方法

__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
cat=Cat('猫')
print(cat)
#结果:
创建对象
对象初始化
猫
实例
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 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)
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'>

注释

1.定义A类作为下面类的父类,A类继承object类,因为需要重写A类的__new__()函数,所以需要继承object基类,成为新式类,经典类没有__new__()函数;

2.子类在重写__new__()函数时,写return时必须返回有继承关系的类的__new__()函数调用,即上面代码中的B类继承自A类,则重写B类的__new__()函数,写return时,只能返回A.__new__(cls)或者object.__new__(cls),不能返回C类的;

3.由注释掉的代码执行结果可以看出,B类虽然继承自A类,但是如果没有重写B类的__new__()函数,则默认继承的仍是object基类的__new__(),而不是A的;

4.B类的__new__()函数会在B类实例化时被调用,自动执行其中的代码语句,但是重写__new__()函数不会影响类的实例化结果,也就是说不管写return时返回的是A的还是object的,B类的实例化对象就是B类的,而不会成为A类的实例化对象;只是在实例化时,如果返回的是A.__new__(cls),则会执行A类中定义的__new__()函数;

5.new()函数确定了类的参数的个数,object类默认定义的__new__()函数的参数为(cls, *args),但如果在子类中重写了__new__(cls, x), 则实例化类时,需要传入一个x参数,而__init__()函数接受到的有两个参数,一个是实例化生成的实例对象self代替,一个是传入的实参x的值;

特性

__new__()方法是在类准备将自身实例化时调用。__new__()方法始终都是类的静态方法,即使没有被加上静态方法装饰器。是因为无论怎样重写类的__new__()函数,追溯到源头都是继承自object的__new__()函数,而object类中定义的__new__()函数就被定义成了静态函数,被@stacitmethod修饰

__call__方法

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

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

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

class A(object):
    def __call__(self, x):
        print ('__call__ called, print x: ', x)    
a = A()   #与__init__不同,在实例化时不需要传参
a('123')  #此时直接给实例对象a传参

__call__ called, print x:  123

看a(‘123’)这是函数的调用方法,这里a实际上是类对象A的实例对象,实例对象能想函数一样传参并被调用,就是__call__()方法的功能;

__doc__方法

类的注释,无法继承给子类的

class foo():
    '''这是一个类:foo'''
    pass
class bar(foo):
    pass
print(foo.__doc__)
print(bar.__doc__)
#结果
这是一个类:foo
None
综合上述方法实例
class A(object):
    def __init__(self, x):
        print('x in __init__', x)
    def __new__(cls, y):
        print('y in __new__', y)
        return super(A, cls).__new__(cls)
    def __call__(self, z):
        print('z in __call__', z)
A('123')('abc')
#结果
y in __new__ 123 	 #new中获取传入的参数
x in __init__ 123	 #init构造传入的参数形成实例	
z in __call__ abc    #A('123')现当于一个实例a,a将abc传给call
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值