Python学习_11_类和实例

类和实例

类是对象创建实例的模板,而实例则是对象的实体。类使用class关键字定义:

class MyClass:
? ? pass

python中创建实例直接使用工厂函数(类名加上一对括号),和其他的语言使用new关键字有所不同:

my_obj = MyClass()

一般来说,类名以大写字母开头,而对象名则以小写字母或者下划线开头。

实例化对象时,会执行类定义中的__init__()方法,该方法执行时包含实例的各种初始化操作。

方法和函数的区别:方法由对象调用,在方法定义中,第一个参数必须是显示的self,表示当前对象,而函数则不传入当前对象self,可以说方法是特殊的函数,他指定了调用对象,并且可以获得调用对象的属性。函数和方法都是function类的实例:

class MyClass(object):
? ? def __init__(self):
? ? ? ? pass
? ? def method1(a,b):
? ? ? ? print(a+b)
? ? def method2(self,a,b):
? ? ? ? print(a+b)
obj = MyClass()
MyClass.method1(1,2)
obj.method2(1,2)
print(type(MyClass.method1))
print(type(MyClass.method2))

上述代码中,obj.method2就是方法,而MyClass.method1是一个普通的函数,为什么要使用MyClass.method1是因为method1的命名空间包含在MyClass中,而使用obj.method2的原因是因为method2是obj所在类的一个方法,并obj作为method1调用的对象。

从上述代码还可以延生出以下结论:

1. MyClass.method2(1,2)将会产生错误:TypeError: method2() takes exactly 3 arguments (2 given)。 而MyClass也是一个对象,执行MyClass.method2()时,并不能将MyClass作为self代表的当前对象,这是因为实例的方法必须存在于类中,而实例的属性则存在于实例本身,MyClass调用method2不成功是因为MyClass所在的类:type并没有该方法,所以MyClass.method2()仅仅是执行MyClass命名空间中的一个函数,而该函数要求传入一个对象,所以导致了TypeError错误。

2. obj.method1(1,2)将会产生错误:TypeError: method1() takes exactly 2 positional arguments (3 given)。虽然调用报错,但是报错的原因仅仅是因为参数数量不匹配,由此可见,一个对象调用方法时,该方法必须要显式的第一个对象为self。并且,obj调用时,并没有使用MyClass命名空间,因为obj是MyClass的实例,将会集成MyClass的命名空间。

对象的属性

在python中,实例可以在任何时刻添加对象,即使在类中并没有定义该属性,但是该语句并不会有任何错误,并且在之后一样可以调用该属性,这样的特性可能非常的方便,但是也隐藏了很多弊端,容易对已知的对象传入不必要的属性,从而搞得一团糟:

class MyClass:
? ? def __init__(self,a,b):
? ? ? ? self.a = a
? ? ? ? self.b = b
obj = MyClass(1,2)
print(obj.a)
obj.a = 3
print(obj.a)
def a_method(self,c):
? ? self.c = c
from types import MethodType
obj.a_method = MethodType(a_method,obj)
obj.a_method(4)
print(obj.c)

上述通过类定义之外的途径和对象添加方法和属性,在其他的同类的对象中是不具有的,可以看成是ruby中单件类类似的技巧,通过上述代码给obj添加的方法,实际上存在于obj的单件类中。

通过__slots__可以限制类的属性,以防止对实例添加不必要的变量:

class MyClass:
? ? __slots___ = (‘a’,’b‘)
? ? ...

此时,如果再给obj添加其他的属性将会告知MyClass中没有该属性的错误,从而限制了对象的属性。

对象的属性是不再能被任意添加了,但是仍然可以在外部可以被外部代码轻松访问,通过在变量前添加两个下划线来表示私有变量:

class Student:
? ? __slots__ = (‘score‘,‘grade‘)
? ? def __init__(self,score):
? ? ? ? self.score = score
? ? def getScore(self):
? ? ? ? if self.score >= 90:
? ? ? ? ? ? ?self.grade = ‘A‘
? ? ? ? elif self.score >= 60:
? ? ? ? ? ? self.grade = ‘B‘
? ? ? ? elif self.score < 60:
? ? ? ? ? ? self.grade = ‘C‘
? ? ? ? return self.grade
xiaoming = Student(47)
xiaoming.score = 90
print(xiaoming.getScore())

在上述代码中,虽然在初始化小明的成绩的时候输入了47分,但是仍然可以在外部对该成绩进行修改,由于小明懂了一点python,瞬间就从差等生变成优等生,这样的结果是不希望被看到的。将score改为__score后:

class Student:
? ? __slots__ = (‘__score‘,‘grade‘)
? ? def __init__(self,score):
? ? ? ? self.__score = score
? ? def getGrade(self):
? ? ? ? if self.__score >= 90:
? ? ? ? ? ? self.grade = ‘A‘
? ? ? ? elif self.__score >= 60:
? ? ? ? ? ? self.grade = ‘B‘
? ? ? ? elif self.__score < 60:
? ? ? ? ? ? self.grade = ‘C‘
? ? ? ? return self.grade

此时,小明的投机取巧修改自己分数的手段就不再生效。访问xiaoming.__score时,将出现以下错误:AttributeError: ‘Student‘ object has no attribute ‘__score‘

尽管如此,其实小明还是可以这样做:

xiaoming._Student__score = 100

因为在使用双下划线时,python只不过是讲变量的名字之前加入了_Classname前缀以避免被直接访问到(不同版本的解释器会有所不同),而不是真正的不可访问,python中并没有真正不可操作的机制,而类似于_Student这些单下划线开头的变量名,虽然可以被外部访问到,但是最好不要这样做,单下划线的意思就是,虽然我不是私有变量,但是请你把我当成私有变量,这或许是对python中没有私有变量的一种妥协吧。

此时,我也没有办法来对付小明了。这是很有意思的故事,在Ruby中,任何实例变量在设置set方法和get方法之前,都是不能被外部访问到的,只有通过给私有变量设置setter方法或者getter方法,该变量才真正的成为属性,总之为了实例变量成为属性要做一些必要工作。而python中,几乎不能阻止一个对象访问在类中定义的变量,甚至如果你不用__slots__,都无法阻止添加各种属性到对象中,我们要做的工作反而变成想方设法让属性不能被访问到。

使用真正的属性

python也可以和其他语言一样,通过@property修饰器,实现getter、setter方法从而访问和设置的属性,从而可以“掩耳盗铃”地说,你不能设置该属性:

class Student:
? ? __slots__ = (‘_score‘,‘_grade‘)
? ? def __init__(self,score):
? ? ? ? self._score = score
? ? @property
? ? def score(self):
? ? ? ? return _score
? ? @property
? ? def grade(self):
? ? ? ? if self._score >= 90:
? ? ? ? ? ? self._grade = ‘A‘
? ? ? ? elif self._score >= 60:
? ? ? ? ? ? self._grade = ‘B‘
? ? ? ? elif self._score < 60:
? ? ? ? ? ? self._grade = ‘C‘
? ? ? ? return self._grade

当使用了@property修饰器之后,其实就是实现了getter方法,使外部可以被看到,如果想要设置getter方法,则再添加:

? ? @score.setter
? ? def score(self,value):
? ? ? ? score._score = value

和其他语言一样,方法名字就是属性名字,小明可以通过xiaoming.score来看到自己的成绩,当没有定义setter方法时,小明是不能通过xiaoming.score来修改自己的成绩的,但是这是不是就意味着小明真的不能改了呢?其实通过上面的代码已经可以看到,python内部的变量名字并不是score,而是_score,这就是为什么我说“掩耳盗铃”的原因,小明依然可以通过xiaoming._score来修改自己的成绩。总之,python中是不会真正阻止一个对象访问类定义中的变量的,这实在有点令人苦恼。?

今天是不完整的一天

时间: 2024-10-10 03:04:52

Python学习_11_类和实例的相关文章

Python面试题之Python中的类和实例

0x00 前言 类,在学习面向对象我们可以把类当成一种规范,这个思想就我个人的体会,感觉很重要,除了封装的功能外,类作为一种规范,我们自己可以定制的规范,从这个角度来看,在以后我们学习设计模式的时候,对设计模式的理解会很有帮助.其次,语言中类是抽象的模板,用来描述具有相同属性和方法的对象的集合,比如Animal类.而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同. Python使用class关键字来定义类,其基本结构如下: class 类名(父类列表)

python学习笔记-类的descriptor

descriptor应用背景 所谓描述器,是实现了描述符协议,即get, set, 和 delete方法的对象. 简单说,描述符就是可以重复使用的属性. 比如以下代码: f = Foo() b = f.bar f.bar = c del f.bar 在解释器执行上述代码时,当发现你试图访问属性(b = f.bar).对属性赋值(f.bar = c)或者删除一个实例变量的属性(del f.bar)时,就会去调用自定义的方法. 为什么把对函数的调用伪装成对属性的访问?有什么好处? 从property

python :理解类与实例

面向对象最重要的概念就是类(Class)和实例(Instance),必须牢记类是抽象的模板,比如Student类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同. 仍以Student类为例,在Python中,定义类是通过class关键字: class Student(object): pass class后面紧接着是类名,即Student,类名通常是大写开头的单词,紧接着是(object),表示该类是从哪个类继承下来的,继承的概念我们后面再讲,通常,

Python 面向对象编程——类和实例

1        面向对象编程 面向对象编程: 面向对象编程--Object OrientedProgramming OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数. 面向过程的程序设计把计算机程序视为一系列的命令集合,即一组函数的顺序执行.为了简化程序设计,面向过程把函数继续切分为子函数,即把大块函数通过切割成小块函数来降低系统的复杂度. 面向对象的程序设计把计算机程序视为一组对象的集合,而每个对象都可以接收其他对象发过来的消息,并处理这些消息,计算机程序的执行就是一系列消

python学习——定制类

看到类似__slots__这种形如__xxx__的变量或者函数名就要注意,这些在Python中是有特殊用途的. __slots__我们已经知道怎么用了,__len__()方法我们也知道是为了能让class作用于len()函数. 除此之外,Python的class中还有许多这样有特殊用途的函数,可以帮助我们定制类. __str__ 我们先定义一个Student类,打印一个实例: >>> class Student(object): ... def __init__(self, name):

python之定义类创建实例

https://www.cnblogs.com/evablogs/p/6688938.html 类的定义 在Python中,类通过class关键字定义,类名以大写字母开头 1 2 >>>class Person(object):           #所有的类都是从object类继承               pass                 #pass先不做任何处理,先跳过,为了防止语法错误 创建类的属性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 &g

python “类变量”和“类的实例变量” 区别

1 class Count(): 2 count=0 3 def __init__(self,count): 4 self.count=count 5 self.__class__.count+=1 运行结果>>> >>>ct1=Count(3) >>>print ct1.count,Count.count 3 1 >>>ct2=Count(-1) >>>print ct2.count,Count.count -1

python学习12类

'''''''''类:具有相同特性和行为的对象抽象为类特性——>属性Property行为——>方法class:关键字'''class Boxes():#类的第一行格式 '''立方体类''' #文档说明 def __init__(self,lengthx,widthx,heightx):#传递类参数的保留函数__init__ self.length=lengthx #self代表实例对象,在实例调用时传递实例对象 self.width=widthx self.height=heightx def

python学习19类5之多态与鸭子模型

'''''''''一.多态1.Python中多态是指一类事物有多种形态.''' class Animal: def run(self): raise AttributeError('子类必须实现这个方法') #抛出异常 class People(Animal): def run(self): print('人正在走') class Pig(Animal): def run(self): print('pig is walking') class Dog(Animal): def run(self