温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

26面向对象1_类方法-静态方法-访问控制-猴子补丁

发布时间:2020-07-14 19:03:58 来源:网络 阅读:150 作者:chaijowin 栏目:编程语言

 

目录

面向对象三要素:... 3

类对象及类属性:... 4

实例化:... 6

instance实例对象:... 10

装饰一个类:... 13

类方法、静态方法:... 14

访问控制:... 16

猴子补丁:... 19

 

 

 

面向对象

 

语言的分类:

面向机器:

抽象成机器的指令,机器容易理解;

代表:汇编语言;

 

面向过程:

流程式,第1步,第2...

问题规模小,可以步骤化,按部就班处理;

代表:C语言;

 

面向对象:

随着计算机需要解决的问题的规模扩大,情况越来越复杂,需要很多人、很多部门协作,面向过程编程不太适合了;

代表:C++javapython

 

什么是面向对象?

一种认识世界,分析世界的方法论,将万事万物抽象为类;

 

class类,是抽象的概念,是万事万物的抽象,是一类事物的共同特征的集合;

用计算机语言来描述类,就是属性和方法的集合;

 

instance实例,或,object对象,是类的具象,是一个实体;

对于我们每个人这个个体,都是抽象概念人类的不同的实体;

例:

你吃鱼:

你,就是对象;

鱼,也是对象;

吃,就是动作;

你是具体的人,是具体的对象,你属于人类,人类是个抽象的概念,是无数具体的个体的抽象;

鱼也是具体的对象,就是你吃的这一条具体的鱼,这条鱼属于鱼类,是无数的鱼抽象出来的概念;

 

注:

数据<-->属性;

动作<-->方法;

属性和方法的集合体;

python中函数和方法要加以区分;

属性也决定着方法的多少,有一些方法是为内部属性作操作的,有一些方法是对外的;

项目有多复杂,数据结构就有多复杂;

类是数据和动作,即属性和方法的集合;

抽象?(数据和动作的集合);

具象?

吃,是动作,是操作,也是方法,这个吃是你的动作,也就是人类具有的方法;如果反过来,鱼吃人,吃就是鱼类的动作了;

吃,这个动作,很多动物都具有,人类和鱼类都属于动物类,而动物类是抽象的概念,是动物都有吃的动作,但吃法不同而已;

你驾驶车,这个车是车类的具体的对象(实例),驾驶这个动作是鱼类不具有的,是人类具有的方法;

 

属性,是对象状态的抽象,用数据结构来描述;

操作(方法),是对象行为的抽象,用操作名和实现该操作的方法来描述;

 

每个人都有名字、身高、体重等信息,这些信息是个人的属性,但这些信息不能保存在人类中,因为人类是抽象的概念,不能保留具体的值;

而人类的实例,是具体的人,他可以存储这些具体的属性,而且不同人有不同的属性;

 

哲学:

一切皆对象;

对象是数据(属性)和操作(方法)的封装;

对象是独立的,但对象之间可相互作用;

目前,面向对象是最接近人类认知的编程范式;

 

UMLunified modeling language,统一建模语言;

 

 

 

面向对象三要素:

1、封装:

组装:将数据和操作组装到一起;

隐藏数据:对外只暴露一些接口,通过接口访问对象;(如驾驶员使用汽车,不需要了解汽车的构造细节,只需要知道使用什么部件怎么驾驶就行,踩了油门就能跑,可以不了解背后的机动原理);

 

encapsulation封装:

面向对象的三要素之一;

将数据和操作组织到类中,即属性和方法;

将数据隐藏起来,给使用者提供操作,使用者通过操作就可获取或修改数据,gettersetter

通过访问控制,暴露适当的数据和操作给用户,该隐藏的隐藏起来,保护成员或私有成员;

 

 

2、继承:

多复用,继承是为了复用,继承来的就不需要自己写了;

多继承少修改,ocpopen-closed-principle开闭原则,使用继承来改变,来体现个性;

多继承慎用,问题失控,计算机所用技术,简单就是美的;

 

注:

函数复用,如yield from

 

3、多态:

面向对象编程最灵活的地方,动态绑定;

python运行时才绑定(知道)类型;

 

人类就是封装;

人类继承自动物类,孩子继承父母的特征,分为单一继承、多继承;

多态,继承自动物类的人类,猫类的操作“吃”不同;

其它语言的继承、多态与python不一样,仅封装一样;

 

在面向对象中,父类、子类通过继承联系在一起,如果可通过一套方法,就可实现不同表现,就是多态;

一个类继承自多个类,就是多继承,它将具有多个类的特征;

 

 

 

python的类:

定义:

class ClassName:

         语句块

必须使用class关键字;

类名必须用大驼峰(首字母大写)命名,习惯,不是语法强制;

类定义完成后,就产生了一个类对象,绑定到了ClassName上;

 

注:

区分:类对象和类的对象;

 

例:

class MyClass:

    '''a example class'''

    x = 'abc'   #类属性,另有对象属性(类的实例的属性)

    def foo(self):   #类属性foo(单从标识符讲,foo是类属性),同时也是方法,self必须作为第1个参数

        print(self.x)

        return 'My class'

 

print(MyClass)

print(type(MyClass))

print(MyClass.__name__)

print(MyClass.x)   #不是内存地址,高级语言对能简化的就简化了

print(MyClass.foo)   #内存地址

print(MyClass().foo())

print(MyClass.__doc__)

输出:

<class '__main__.MyClass'>

<class 'type'>

MyClass

abc

<function MyClass.foo at 0x7f05be5370d0>

abc

My class

a example class

 

 

 

类对象及类属性:

类对象,类的定义就会生成一个类对象;

 

类的标识符:

类的属性,类中定义的变量和类中定义的方法都是类的属性;

类变量,上例中xMyClass的变量;

 

MyClass中,xfoo都是类的属性,__doc__也是类的属性

foo方法是类的属性,如同吃是人类的方法,但是每一个具体的人才能吃东西,也就是说吃是人类的实例才能调用的方法;

foomethod方法对象,不是普通的function函数对象,它必须至少有一个参数,且第一个参数必须是selfself可换名字),这个参数位置就留给了self

 

self指代当前实例本身,self这个名字只是一个惯例,它可以修改,但请不要修改,否则影响代码的可读性;

 

注:

inspect中,isfunction()ismethod()

 

def bar():

class MyClass:

         example = bar   #语法虽允许,但不要这样写,破坏了封装,不符合编程规范,方法就写在类内部

 

例:

class MyClass:

    '''a example class'''

    x = 'abc'

    def foo(self):

        # print(self.x)

        print(self)

        # return 'My class'

 

# print(MyClass)

# print(type(MyClass))

# print(MyClass.__name__)

# print(MyClass.x)

# print(MyClass.foo)

print(MyClass().foo())

# print(MyClass.__doc__)

print(MyClass.foo(1))   #不判断self的类型,1None

 

mycls = MyClass()   #实例化、初始化

print(mycls.foo())   #对象调用方法,相当于悄悄的把mycls放入foo(mycls)

print(mycls.x)   #实例可拿走类属性

print(mycls.foo)   #对象绑定方法

输出:

<__main__.MyClass object at 0x7f338d4ff438>

None

1

None

<__main__.MyClass object at 0x7f338d4ff438>

None

abc

<bound method MyClass.foo of <__main__.MyClass object at 0x7f338d4ff438>>

 

例:

class MyClass:

    '''a example class'''

    x = 'abc'

    def foo(self):   #self可改名

        # print(self.x)

        # print(self)

        print(id(self))

        # return 'My class'

        # return self

 

mycls = MyClass()

print(mycls.foo())

# print(mycls.x)

# print(mycls.foo)

print(id(mycls))

输出:

140426199077888

None

140426199077888

 

常用:

print(MyClass.x)

mycls = MyClass()

print(mycls.x)

print(mycls.foo())

 

 

 

实例化:

mycls = MyClass()

在类对象名称后面加(),就调用类的实例化方法,完成实例化;

实例化,就真正创建一个该类的对象(实例),如人类的实例tom,jerry

实例化后,获得的实例,是不同的实例,即使是使用同样的参数实例化,也得到不一样的对象;

python类实例化后,会自动调用__init__(self)方法,这个方法第一个参数必须留给self,其它参数随意;

 

__init__(self)方法:

MyClass实际上调用的是__init__(self)方法,可以不定义,如果没有定义会在实例化后隐式调用;

作用:对实例进行初始化;

__init__(self)方法与其它方法不一样,返回值只能是None,一般不写返回值,如果写return只能两种:returnreturn None,其它形式一律报错;

初始化函数可以多个参数,第一个参数必须self

初始化函数也称构造器,构造方法,仅初始化,构造实例是__new__方法;

 

另,__new__(cls,*args,**kwargs),用于构建实例,极少用,类方法;

 

__init__(self)方法,默认的语句是:

def __init__(self):

         pass

 

例:

class MyClass:

    '''this is a example class'''

    x = 123

    def __init__(self):

        print('init')   #自定义初始化

 

    def foo(self):

        return 'foo = {}'.format(self.x)

 

a = MyClass()

print(a.foo())

输出:

init

foo = 123

 

例:

class MyClass:

    '''this is a example class'''

    def __init__(self):

        print('self in init = {}'.format(id(self)))   #self就是调用者,即实例对象c

c = MyClass()

print('c = {}'.format(id(c)))

输出:

self in init = 140190037407448

c = 140190037407448

 

例:

class Person:

    x = 'abc'

    def __init__(self,name,age=18):

        self.name = name   #实例属性,对象的属性

        self.age = age

 

    def showage(self):

        print('{} is {}'.format(self.name,self.age))

 

tom = Person('tom')

jerry = Person('jerry',20)

print(tom.name,tom.age)

print(jerry.name,jerry.age)

print(tom.x,jerry.x)

输出:

tom 18

jerry 20

abc abc

 

例:

class Person:

    x = 'abc'

    def __init__(self,name,age=18):

        self.name = name

        self.age = age

 

    def showage(self):

        print('{} is {}'.format(self.name,self.age))

 

tom = Person('tom')

# jerry = Person('jerry',20)

# print(tom.name,tom.age)

# print(jerry.name,jerry.age)

# print(tom.x,jerry.x)

# print(tom == jerry)

jerry = Person('tom')

print(tom.name,tom.age)

print(jerry.name,jerry.age)

print(tom == jerry)   #tomjerry是不同的个体,尽管初始化时参数一样

print(tom is jerry)

输出:

tom 18

tom 18

False

False

 

例:

class Person:

    x = 'abc'

    def __init__(self,name,age=18):

        self.name = name

        # self.age = age

        self.y = age

 

    def showage(self,x,y):   #showage中的形参yself.y不一样,self.y是实例在外部使用时用的,y是形参

        print('{} is {}. {} {}'.format(self.name,self.y,x,y))

        self.y = x

        Person.x = x   #类中的所有方法,包括特殊__init__(self)方法,都可对类属性或实例属性进行修改

 

tom = Person('tom')

jerry = Person('jerry',20)

# print(tom.name,tom.age)

# print(jerry.name,jerry.age)

# print(tom.x,jerry.x)

# print(tom == jerry)

# jerry = Person('tom')

# print(tom.name,tom.age)

# print(jerry.name,jerry.age)

# print(tom == jerry)

# print(tom is jerry)

print(tom.y,jerry.y)

tom.showage(100,'a')

jerry.showage(200,'b')

print(tom.y,jerry.y)

print(Person.x)

print(x)   #当前作用域中没有x,也说明xPerson类中封装着,要访问x前面要加限定,如Person.x

输出:

18 20

Traceback (most recent call last):

tom is 18. 100 a

jerry is 20. 200 b

100 200

200

  File "/home/python/magedu/projects/cmdb/example_class_Person.py", line 29, in <module>

    print(x)

NameError: name 'x' is not defined

 

 

 

instance实例对象:

类初始化后一定会获得一个对象,就是实例对象;

tomjerry就是Person类的实例;

__init__方法的第一个参数self,就是指代某一个实例;

类实例化出一个实例对象,实例对象会绑定方法,调用方法时采用jerry.showage()的方式;

在定义showage(self)时,不能少了self,这个self就是jerrypython会把方法的调用者作为第一个参数self的实参传入;

self.name就是jerry对象的namename是保存在了jerry对象上,而不是Person类上,所以称为实例变量

 

实例变量是每一个实例自己的变量,是自己独有的;

类变量是类的变量,是类的所有实例共享的属性和方法;

 

类属性保存在类的__dict__中;

实例属性保存在实例的__dict__中;

如果从实例访问类的属性,需要借助__class__找到所属的类;

 

特殊属性:

__name__,对象名;

__class__,对象的类型,python3__class__type()结果一样;

__dict__,对象的属性的字典;

__qualname__,类的限定名;

 

总结:

是类的,也是这个类所有实例的,其实例都可以访问到类中定义的属性和方法;是类的,就是大家的

是实例的,就是这个实例自己的,通过类访问不到;是实例的,就是个体的

类变量,是属于类的变量,这个类的所有实例可以共享这个变量;

实例可以动态的给自己添加或删除一个属性,实例.__dict__['变量名']实例.变量名都可访问到;也可动态添加类方法,这些会破坏封装,不要这么做,虽语法允许,但从设计角度不好;

实例的变量会隐藏与其同名的类的变量(遮盖),或者说是覆盖了类变量;

 

实例属性的查找顺序:

实例使用.点来访问属性,会先找自己的__dict__

如果没有,然后通过属性__class__找到自己的类,再去类的__dict__中找;

如果实例使用__dict__['变量名']来访问(直接翻字典),将不会按照上面的查找顺序找变量;

 

一般类变量使用全大写来命名;

tom.__class__.__dict__等价于Person.__dict__

 

例:

class Person:

    age = 18   #类变量,通常是一常量,很少用

    def __init__(self,name):

        self.name = name   #编程中,大量用的是实例变量,而不是类变量

 

# tom = Person('tom',20)   #X

tom = Person('tom')   #初始化、实例化

jerry = Person('jerry')

print(tom.name,tom.age)

print(jerry.name,jerry.age)

print(Person.age)

# print(Person.name)   #X

Person.age = 30   #在外部修改类属性

print(tom.age,jerry.age,Person.age)

 

print(Person.__dict__)   #__weakref__弱引用,用.点查找属性

print(tom.__dict__)   #每个对象保存着自己的属性,所有对象的操作方法是一样的,无非是数据不一样(传入的参数不一样)

print(jerry.__dict__)

print(tom.__dict__['name'])

 

print(sorted(Person.__dict__.items()),end='\n')

print(sorted(tom.__dict__.items()),end='\n')

 

# print(tom.__qualname__)   #某一对象并不拥有所有特殊属性

print(tom.__class__.__qualname__,jerry.__class__.__qualname__)

print(isinstance(jerry,tom.__class__))

print(int.__class__)

print(Person.__class__)

print(isinstance(tom,int.__class__))

输出:

tom 18

jerry 18

18

30 30 30

{'__module__': '__main__', 'age': 30, '__init__': <function Person.__init__ at 0x7f7b63da20d0>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}

{'name': 'tom'}

{'name': 'jerry'}

tom

[('__dict__', <attribute '__dict__' of 'Person' objects>), ('__doc__', None), ('__init__', <function Person.__init__ at 0x7f7b63da20d0>), ('__module__', '__main__'), ('__weakref__', <attribute '__weakref__' of 'Person' objects>), ('age', 30)]

[('name', 'tom')]

Person Person

True

<class 'type'>

<class 'type'>

False

 

例:

class Person:

    age = 3

    height = 170

    def __init__(self,name,age=18):   #方法中的第一个参数self,表示bound了对象(实例)

        self.name = name

        self.age = age

 

tom = Person('tom')

jerry = Person('jerry',20)

 

Person.age = 30

print(Person.age,tom.age,jerry.age)

print(Person.__dict__,tom.__dict__,jerry.__dict__,sep='\n')

print(Person.height,tom.height,jerry.height)

Person.height += 20

print(Person.height,tom.height,jerry.height)

print(Person.__dict__,tom.__dict__,jerry.__dict__,sep='\n')

 

tom.height = 168

print(Person.height,tom.height,jerry.height)

print(Person.__dict__,tom.__dict__,jerry.__dict__,sep='\n')

 

jerry.height += 20

print(Person.height,tom.height,jerry.height)

print(Person.__dict__,tom.__dict__,jerry.__dict__,sep='\n')

 

Person.weight = 70   #动态添加(删除)属性,灵活之处,也可动态添加方法,这些会破坏封装,不要这么做

print(Person.weight,tom.weight,jerry.weight)   #先找自己的__dict__,找不到再通过__class__找类中的__dict__,类中也没有抛异常KeyError

print(tom.__dict__['weight'])   #XKeyError

输出:

30 18 20

{'__module__': '__main__', 'age': 30, 'height': 170, '__init__': <function Person.__init__ at 0x7f9f7aad40d0>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}

{'name': 'tom', 'age': 18}

{'name': 'jerry', 'age': 20}

170 170 170

190 190 190

{'__module__': '__main__', 'age': 30, 'height': 190, '__init__': <function Person.__init__ at 0x7f9f7aad40d0>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}

{'name': 'tom', 'age': 18}

{'name': 'jerry', 'age': 20}

190 168 190

{'__module__': '__main__', 'age': 30, 'height': 190, '__init__': <function Person.__init__ at 0x7f9f7aad40d0>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}

{'name': 'tom', 'age': 18, 'height': 168}

{'name': 'jerry', 'age': 20}

190 168 210

{'__module__': '__main__', 'age': 30, 'height': 190, '__init__': <function Person.__init__ at 0x7f9f7aad40d0>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}

{'name': 'tom', 'age': 18, 'height': 168}

{'name': 'jerry', 'age': 20, 'height': 210}

70 70 70

Traceback (most recent call last):

  File "/home/python/magedu/projects/cmdb/example_class_var.py", line 29, in <module>

    print(tom.__dict__['weight'])

KeyError: 'weight'

 

 

 

装饰一个类:

不是类装饰器;

需求:为一个类通过装饰,增加一些类属性;

用于老项目,不动类定义,通过装饰器动态的添加类属性;

 

def setnameproperty(name):

    def wrapper(cls):

        cls.NAME = name

        return cls

    return wrapper

 

@setnameproperty('MYCLASS')   #MyClass = setnameproperty('MYCLASS')(MyClass)

class MyClass:

    pass

 

print(MyClass.__dict__)

输出:

{'__module__': '__main__', '__dict__': <attribute '__dict__' of 'MyClass' objects>, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>, '__doc__': None, 'NAME': 'MYCLASS'}

 

 

 

类方法、静态方法:

类方法,用装饰器@classmethod,在定义时,第1个参数留给类本身,如def clsmtd(cls),与类bound(类似对象方法,第1个参数self,与实例bound);

类中普通方法,def bar(),虽语法允许,不推荐使用,若非要不带参数,用静态方法替代;

静态方法,用装饰器@staticmethod

 

python中类方法,相当于其它语言的静态方法;javac++中的静态方法指的是python中的类方法;

 

类方法,如datetime.datetime(...)创建时间对象;

静态方法,从概念上归类管辖,实际使用可以与类没有关系,很少用;

 

__init__()等方法,这些本身都是类的属性,第一个参数必须是self,而self必须指向一个对象,即类必须实例化后,由实例来调用这个方法;

 

普通方法:

MyClass.bar(),先查看MyClass.__dict__,这个方法只是被MyClass这个名词空间管理的一个普通的方法,barMyClass的一个属性而已,由于bar在定义时没有指定self,这样即没有完成与实例对象的绑定,不能用a.bar()MyClass().bar()调用,这种虽语法对,但没人这么用,禁止这样定义def bar()

 

类方法:

在类定义中,用@classmethod装饰器修饰的方法;

pycharm中,定义时会自动补全cls参数,必须至少有一个参数,且第一个参数留给了clscls指代调用者即对象自身;

cls这个标识符可以是任意合法名称,但是为了易读,请不要修改;

通过cls可直接操作类的属性,无法通过cls操作类的实例;

类方法,类似c++java中的静态方法;

 

静态方法:

在类定义中用@staticmethod装饰器修饰的方法;

调用时,不会隐式的传入参数

静态方法,只是表明这个方法属于类这个名词空间,函数归在一起,方便组织管理;

 

注:

实例可调用类中定义的方法(包括类方法、静态方法),静态方法和类方法需要找到实例的类;

实例不可调用类中的普通方法,如a.bar(),解释器会自动将a传到bar(a)内,而bar在定义时没有self,即没有绑定实例;

 

例:

class MyClass:

    XXX = 'xxx'

    def __init__(self):

        print('init')

 

    def foo(self):

        print('foo')

 

    def bar():

        print('bar')

 

    @classmethod

    def clsmtd(cls):   #类方法,cls为类本身,或是实例的类

        print('{},xxx={}'.format(cls.__name__,cls.XXX))

 

    @staticmethod

    def staticmtd():

    # def staticmtd(x):

        print('static')

 

a = MyClass()

a.foo()

MyClass.bar()   #V,可以这样用,bar是在MyClass类下定义的

# a.bar()   #Xfoobar都是functionbar中形参没有self,为类中的普通函数,这样调用会自动把a作为形参传入到bar(a)会出错

print(MyClass.__dict__)

 

MyClass.clsmtd()   #a.foo(),会将类本身MyClass传入clsmtd(MyClass)类方法的第一个参数

a.clsmtd()   #是类的,就是大家的,所以实例可以用,相当于a.__class__.clsmtd()

 

MyClass.staticmtd()   #V

a.staticmtd()   #是类的,就是大家的

# a.staticmtd(4)

 

输出:

init

foo

bar

{'__module__': '__main__', 'XXX': 'xxx', '__init__': <function MyClass.__init__ at 0x7f97c11f30d0>, 'foo': <function MyClass.foo at 0x7f97c11f3158>, 'bar': <function MyClass.bar at 0x7f97c11f3488>, 'clsmtd': <classmethod object at 0x7f97c11f5c18>, '__dict__': <attribute '__dict__' of 'MyClass' objects>, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>, '__doc__': None}

MyClass,xxx=xxx

MyClass,xxx=xxx

static

static

 

例:

class Person:

    @classmethod

    def cls_method(cls):

        print('class = {0.__name__} ({0})'.format(cls))

        cls.HEIGHT = 170   #可操作类的属性,不能操作实例的属性

 

    @staticmethod

    def static_method():

        print(Person.HEIGHT)

 

Person.cls_method()

print(Person.__dict__)

Person.static_method()

输出:

class = Person (<class '__main__.Person'>)

{'__module__': '__main__', 'cls_method': <classmethod object at 0x7fdfe7ec4710>, 'static_method': <staticmethod object at 0x7fdfe7ec9400>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None, 'HEIGHT': 170}

170

 

 

 

访问控制:

private,私有属性,双下划线开头的属性名;

私有变量的本质:类定义的时候,如果声明一个实例变量使用双下划线开头,python解释器会将其改名,转换名称为_类名__变更名,所以在外部用原来的名字(__age)访问不到了,但仍可通过__dict__访问或修改;其它语言不是这样,是确确实实看不到,python中仍然可在外部通过_Person__age访问或修改;

 

保护变量

在变更名前加一个下划线,查看__dict__,解释器不做任何特殊处理,这只是开发者共同的约定,看见这种变量,就如同私有变量,不要直接使用;

 

私有方法

双下划线开头的方法,解释器会改名,改名策略和私有变量相同,_类名__方法名;

单下划线的方法,只是开发者之间的约定,解释器不作任何改变;

方法变量都在类的__dict__中可找到;

 

私有成员的总结:

python中使用___来标识一个成员被保护或被私有化隐藏起来,但是不管使用什么样的访问控制,都不能真正的阻止用户修改类的成员,python中没有绝对的安全的保护成员或私有成员;

因此前导的下划线只是一种警告或提醒,请遵守这个约定,除非真有必要,不要修改或者使用保护成员或私有成员;

以上是在类中使用___,如果是在函数中使用则不起作用;

 

publicprotectprivate,其它语言的访问控制,而python中的访问控制只是假象;

 

例:

class Person:

    def __init__(self,name,age=18):

        self.name = name

        self.age = age

 

    def growup(self,incr):

        if 0 < incr < 150:   #控制逻辑

            self.age += incr

 

tom = Person('tom')

tom.growup(20)

tom.age = 160   #未用私有属性,会绕过控制逻辑,外部可见,外部可定义和修改,越过我们定义的范围

print(tom.age)

输出:

160

 

例:

class Person:

    def __init__(self,name,age=18):

        # self.name = name

        self._name = name

        # self.age = age

        self.__age = age   #对象字典中的key表现为_Person__age,自动对应的

 

    def growup(self,incr):

        if 0 < incr < 150:

            # self.age += incr

            self.__age += incr

 

    def getage(self):

        return self.__age

 

tom = Person('tom')

tom.growup(2)

# tom.age = 160

# print(tom.age)

# print(tom.__age)   #X,不能直接访问私有属性,报AttributeError: 'Person' object has no attribute '__age'

print(tom.getage())   #通过方法访问私有属性,没多大用处

 

print(Person.__dict__)

print(tom.__dict__)

 

tom._Person__age = 200   #破坏封装

print(tom.getage())

 

tom.__age = 300   #破坏封装,重新定义的__age,与对象字典的_Person__age不是同一个key,不会被覆盖

print(tom.getage())

print(tom.__dict__)

print(tom.__age)

 

输出:

20

{'__module__': '__main__', '__init__': <function Person.__init__ at 0x7fde68b150d0>, 'growup': <function Person.growup at 0x7fde68b15158>, 'getage': <function Person.getage at 0x7fde68b15488>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}

{'_name': 'tom', '_Person__age': 20}

200

200

{'_name': 'tom', '_Person__age': 200, '__age': 300}

300

tom

{'_name': 'tom', '_Person__age': 200, '__age': 300}

 

 

 

猴子补丁:

可通过修改或者替换类的成员;

使用者调用的方式没有改变,但类提供的功能可能已经改变了;

适用于上线后的紧急或临时修复上,一般下次变更时会合并到代码中;

 

monkey patch,猴子补丁,在运行时对属性进行动态替换;

黑魔法,慎用;

 

类方法中的名字,get*读,set*写,惯例;

 

例:

使用monkey patch,替换getscore方法,返回模拟的数据;

 

test2.py

class Person:

    def __init__(self,chinese,english,history):

        self.chinese = chinese

        self.english = english

        self.history = history

 

    def getscore(self):

        return self.chinese,self.english,self.history

 

test3.py

def getscore(self):

    return dict(chinese=self.chinese,english=self.english,history=self.history)

 

test1.py

from test2 import Person

from test3 import getscore

 

def monkeypatch5Person():

    Person.getscore = getscore

 

stu1 = Person(80,90,88)

print(stu1.getscore())

 

monkeypatch5Person()

 

stu2 = Person(70,80,90)

print(stu2.getscore())

输出:

(80, 90, 88)

{'chinese': 70, 'english': 80, 'history': 90}

 

 

 


向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI