美文网首页
(十二)类<2>一些讨论

(十二)类<2>一些讨论

作者: 费云帆 | 来源:发表于2019-01-07 09:08 被阅读0次

1."init"方法不能return,或者说,return None:

class Foo:
    def __init__(self):
        print("I'm in init()...")
        return 200
Foo()
>>>
I'm in init()...
Traceback (most recent call last):
  File "C:\Users\wcw\Desktop\Testing.py", line 5, in <module>
    foo()
TypeError: __init__() should return None, not 'int'

2."类属性"一般不要随意修改
"实例属性"可以随意修改

>>> class AA:
    x=7

    
>>> aa=AA()
>>> aa.x
7
# 重新赋值,原来的aa.x被遮盖
>>> aa.x=100
# 实例属性变了
>>> aa.x
100
# 类属性依然没变
>>> AA.x
7
# 这里删除的指向100的指针
>>> del aa.x
# 原来的指针又还原了
>>> aa.x
7
# 类属性变了,实例变量跟着改变,前提是类属性指向的是"不可变"的值
>>> AA.x+=1
>>> aa.x
8
# 如果指向的是可变的"值",结果就是互相影响:
>>> class B:
    y=[1,2,3]

    
>>> bar=B()
>>> bar.y
[1, 2, 3]
>>> bar.y.append(4)
>>> bar.y
[1, 2, 3, 4]
>>> B.y
[1, 2, 3, 4]
>>> B.y.append(5)
>>> B.y
[1, 2, 3, 4, 5]
>>> bar.y
[1, 2, 3, 4, 5]
# 新增类属性,那么实例也会有相应的属性,反过来就不行
>>> B.x="Hello"
>>> bar.x
'Hello'
>>> bar.z="World"
>>> bar.z
'World'
>>> B.z
Traceback (most recent call last):
  File "<pyshell#15>", line 1, in <module>
    B.z
AttributeError: type object 'B' has no attribute 'z'
>>> class AA:
    x=7

# 返回的结果虽然一样,但是所代表的不一样   
>>> AA.x
7
>>> AA().x
7
>>> type(AA)
<class 'type'>
>>> type(AA())
<class '__main__.AA'>

3."self"---代表实例,与"实例对象"区别在于,self主内,实例主外
self实际就是实例对象,二者相等,只不过self放在类里面代表实例对象.为什么不直接把实例对象放入类里面?因为self具有独立性,有self的类可以创建无数模板(实例),而如果放入实例对象,那么该类模板,只能为一个实例对象服务.

>>> class Girl:
    def __init__(self,name):
        self.name=name
        print(self)
        print(type(self))
# self的反馈和实例对象cang一模一样
>>> cang=Girl('teacher')
<__main__.Girl object at 0x00000000030A8B38>
<class '__main__.Girl'>
>>> cang
<__main__.Girl object at 0x00000000030A8B38>
>>> type(cang)
<class '__main__.Girl'>
  • 实例
class Person:
    def __init__(self,name):
        self.name=name

    def getName(self):
        return self.name

    def breast(self,n):
        self.breast=n
        
    def color(self,color):
        print("{0} is {1}".format(self.name,color))

    def how(self):
        print('{0} breast is {1}'.format(self.name,self.breast))

girl=Person('canglaoshi')
girl.breast(90)
girl.color('white')
girl.how()
>>>
canglaoshi is white
canglaoshi breast is 90
  • 实例变量替换self,只是用来理解,不要这么写,因为没有独立性:
class Person:
    #这么写也可以
    # def __init__(girl,name):
    #   girl.name=name
    def __init__(self,name):
        self.name=name
    # 这么做也可以
    # def get_name(girl):
    def get_name(self):
        # 使用实例变量替换self
        return girl.name
girl=Person('canglaoshi')
print(girl.get_name())
>>>
canglaoshi
  • 进一步的讨论:
class Foo:
    def bar(self):
        print(' This is a normal method of bar')
# 通常的做法,用实例去调用类方法
f=Foo()
f.bar()
>>>
 This is a normal method of bar
# 直接用类调用
Foo.bar(f)
#Foo.bar(Foo())
>>>
 This is a normal method of bar
  • 通过类(获取的是非绑定的方法)和实例(获取的是绑定的方法)获取函数对象:
class Foo:
    def bar(self):
        print(' This is a normal method of bar')
f=Foo()
f.bar()

Foo.bar(f)
Foo.bar(Foo())

print(Foo.bar)
print(f.bar)
print(Foo.__dict__['bar'])
>>>
 This is a normal method of bar
 This is a normal method of bar
 This is a normal method of bar
<function Foo.bar at 0x00000000005B7F28>
<bound method Foo.bar of <__main__.Foo object at 0x00000000030F8B70>>
<function Foo.bar at 0x00000000005B7F28>

4.描述器
什么是描述器?
Python中有几个特殊方法比较特殊,它们分别是:

__get__() 、 __set__() 和 __delete__()

简单地说,有这些方法的对象叫做描述器。(实质就是对象调用这些方法,就称描述器)
描述器是属性、实例方法、静态方法、类方法和继承中使用的 super 的背后实现机制,它在Python中使用广泛。这句话中的那些生疏的名词,以后都会用到,稍安勿躁。如何使用?
上述三个特殊方法,可以用下面的方式来使用——所谓的描述器协议。

descr.__get__(self, obj, type=None) --> value
descr.__set__(self, obj, value) --> None
descr.__delete__(self, obj) --> None

关于描述器的内容,本节不重点阐述,这里提及它,目的是要解决“绑定方法”和“非绑定方法”的问题,所以,读者如果有兴趣深入了解描述器,可以去google。
弱水三千,只取一瓢。我们在这里也只看 get() 。

# Foo.__dict__['bar']是函数对象
# 实例为None,obj=Foo
>>> Foo.__dict__['bar'].__get__(None, Foo)

<unbound method Foo.bar> #Python 3显示结果:<function Foo.bar at 0x00000000006AAC
80>

对照描述器协议,我将 self 赋以了 None ,其返回结果和 Foo.bar 的返回结果是一样的。
让 self 为 None 的意思就是没有给定的实例,因此该方法被认为非绑定方法(unbound method)。
如果给定一个实例呢?

>>> Foo.__dict__['bar'].__get__(f, Foo)
<bound method Foo.bar of <__main__.Foo object at 0x02A9BFB0>>

这时候的显示结果和 f.bar 是相同的。
综上所述,可以认为:

  • 当通过类来获取方法的时候,得到的是非绑定方法对象。
  • 当通过实例获取方法的时候,得到的是绑定方法对象。
    所以,通常用实例调用的方法,都是绑定方法。那么非绑定方法在哪里会用到呢?当学习“继承”相关内容的时候,它会再次登场。

小结:用类去调用方法和用实例去调用方法,实质上还是有区别的...

5.类方法---@classmethod

class Foo:
    one=0
    def __init__(self):
        Foo.one+=1
    # 修饰符
    @classmethod
    # 类方法第一个参数不是self,而是表示类对象
    def get_class_attr(cls):
        return cls.one

if __name__=='__main__':
    f1=Foo()
    print("f1:",Foo.one)# 1
    f2=Foo()
    print("f2",Foo.one)# 2
    print(f1.get_class_attr())# 2
    print("f1.one",f1.one)# 2
    print(Foo.get_class_attr())# 2

    print("*"*10)
    f1.one=8
    Foo.one=9
    print(f1.one)# 8
    # 实例调用的是"类方法",而不是调用实例的类的普通方法
    print(f1.get_class_attr())# 9
    print(Foo.get_class_attr())# 9

6.静态方法---@staticmethod:当类对象想调用外部函数时,可以把外部函数写到类里面,变成静态方法去调用,写法上更简洁.这里如果把外部函数写成普通方法,类对象去调用的时候,还需要传入实例.而静态方法是不需要传入self的,所以代码会更简洁
引言实例

def check_t():
    T=3
    return T

class Foo:
    def __init__(self,name):
        self.name=name

    def get_name(self):
        # 方法里面调用外部的函数
        if check_t():
            return self.name
        else:
            return "no person"

if __name__=='__main__':
    f=Foo('Teacher Cang')
    name=f.get_name()
    print(name) # Teacher Cang
    # 会报错,提示没有该属性
    # 显然,类对象调用外部函数是失败的
    print(Foo.check_t())
  • 使用静态方法,类对象也可以调用
class Foo():
    
    def __init__(self,name):
        self.name=name
    # 静态方法,用修饰符修饰
    @staticmethod
    # 静态方法是独立的,不需要self
    def check_t():
        T=3
        return T

    def get_name(self):
        # 这么写也可以
        # if Person.check_t():
        # 实例方法
        if self.check_t():
            return self.name
        else:
            return "No person."

f=Foo('Jim Green')
# 实例调用完全没问题
print(f.get_name())# Jim Green
# 类对象调用也没问题
print(Foo.check_t()) # 3

相关文章

  • (十二)类<2>一些讨论

    1."init"方法不能return,或者说,return None: 2."类属性"一般不要随意修改"实例属性"...

  • iOSBasicClassType

    iOS中有很多类,今天我们来讨论一些基本的类,以及他们的子类,相信NSString,NSArray,NSDicti...

  • iOS开发之类的本质

      我们这里讨论类的结构,我们先定义2个类Strudent和Person,Strudent继承自Person,Pe...

  • 真⇝讨论角色类

    在游戏中,无论是AI也好,是主角控制的角色也好,那都是游戏的必要组成部分,而他们有着相似的行为,若果是公平的,那就...

  • 讨论2

    为什么有的人难以改变? 人只有认识到自己的不足的时候才有可能发生改变。而要能看到自己的不足,必须通过学习,使自己的...

  • 一些讨论

    多人群聊里,做主动退出还是管理员移除,还是两个都做 移除正方:需要删掉某人,某人不在线无法自己主动退出怎么办场景是...

  • 群面

    A. 优先级讨论 1. 抠关键词 2. 根据关键词分类讨论 B. 情节方案类 1. 确定应用场景、确定需求 2. ...

  • java初始化顺序

    本文讨论Java中(静态)变量、(静态)代码块的执行顺序 首先创建3个类: 1、Foo类,用于打印变量 2、Par...

  • Android-绘制简单的几何图形

    android.graphics为我们提供了一些列的类,我们可以应用这些类来绘制2D向量图形。一些常见的类如下: ...

  • 自定义View项目实战(二):Canvas绘制几何图形

    android.graphics为我们提供了一些列的类,我们可以应用这些类来绘制2D向量图形。一些常见的类如下: ...

网友评论

      本文标题:(十二)类<2>一些讨论

      本文链接:https://www.haomeiwen.com/subject/hlyyrqtx.html