在python中,所有的数据类型都被视为对象,也可以自定义对象。自定义对象数据类型就是面向对象中的类(Class)的概念。
类的定义
概念:
1、类:用来描述具有相同属性和方法的对象的集合。类定义了集合中每个对象共有的属性和方法。对象是类的实例。
2、类变量(属性):类变量在整个实例化的对象中是公用的。类变量定义在类中,且在方法之外。类变量通常不作为实例变量使用。类变量也叫属性。
3、数据成员:类变量或实例变量用于处理类及实例对象的相关数据。
4、方法重写:如果从父类继承的方法不能满足子类的需求,就可以对其进行修改,这个过程为方法的覆盖,也叫方法的重写。
5、实例变量:定义在方法中的变量只作用于当前实例的类。
6、多态:对不同类的对象使用相同的操作。
7、封装:对外部世界隐藏对象的工作细节。
8、继承:
9、实例化:创建一个类的实例、类的具体对象。
10、方法:类中定义的函数。
11、对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
>>> class MyClass(object): #类名:MyClass ,object表示如果没有父类就写object
i=12 # 属性:i
def f(self): # 方法:f
return 'hello world'
类定义的语法格式:
class ClassName(object):
。。。。。。
类名通常都是大写开头的单词,(object)表示该类是从哪个类继承下来的,通常如果没有合适的继承类,就使用object类,只是所有类最终都会继承的类。
类的使用
>>> class MyClass(object):
i=123
def f(self):
return 'hello world'
>>> use_class=MyClass()
>>> print('')
>>> print(f"调用类的属性:{use_class.i}")
调用类的属性:123
>>> print(f"调用类的方法:{use_class.f()}")
调用类的方法:hello world
对于类中定义方法的要求:在类中定义方法时,第一个参数必须是self。除第一个参数外,类的方法和普通函数没有差别,
类中调用方法的要求:实例变量上调用即可,除了self不用传外,其他参数均正常传入。
类对象支持两种操作,属性引用和实例化。
属性引用: obj.name obj代表类对象,name代表属性
实例化: obj=ClassName()
类的构造方法
>>> class MyClass(object):
i=123
def __init__(self ,name):
self.name=name
def f(self):
return 'hello '+self.name
>>> use_class=MyClass()
Traceback (most recent call last):
File "<pyshell#19>", line 1, in <module>
use_class=MyClass()
TypeError: __init__() missing 1 required positional argument: 'name'
>>> use_class=MyClass('zhangsan')
>>> print(f"调用类的属性:{use_class.i}")
调用类的属性:123
>>> print(f"调用类的方法:{use_class.f()}")
调用类的方法:hello zhangsan
在Python中,init()方法是一个特殊方法,在对象实例化时会被调用。init()的意思是初始化,是initialization的简写。在定义类时,若不显式的定义一个__init__()方法,则程序默认调用一个无参的__init__()方法。比如下面两段代码的使用效果时一样的。
代码一:
>>> class DefaultInit(object):
def __init__(self):
print('类实例化时执行我,我是__init__()方法。')
def show(self):
print("我是类中定义的方法,需要通过实例化对象调用。")
>>>
>>> test=DefaultInit()
类实例化时执行我,我是__init__()方法。
>>> print('类实例化结束')
类实例化结束
>>> test.show()
我是类中定义的方法,需要通过实例化对象调用。
代码二:
>>> class DefaultInit(object):
def show(self):
print('我是类中定义的方法,需要通过实例化对象调用。')
>>> test=DefaultInit()
>>> print('类实例化结束')
类实例化结束
>>> test.show()
我是类中定义的方法,需要通过实例化对象调用。
总结:一个类中可定义多个构造方法,但实例化类时只实例化最后的构造方法,即最后的构造方法会覆盖前面的构造方法。并且需要根据最后一个构造方法的形式进行实例化。建议一个类中只定义一个构造方法。
类的访问权限
>>> class Student(object):
def __init__(self,name,score):
self.name=name
self.score=score
def info(self):
print(f'学生:{self.name} 分数:{self.score}')
>>> stu=Student("zhangsan",90)
>>> stu()
Traceback (most recent call last):
File "<pyshell#12>", line 1, in <module>
stu()
TypeError: 'Student' object is not callable
>>> stu.info() #访问类实例化后的方法
学生:zhangsan 分数:90
>>> stu.name="李四" #修改类中的属性
>>> stu.score=86
>>> stu.info()
学生:李四 分数:86
如上所示,类中定义的非构造方法可以调用构造方法实例变量的属性,调用的方法为self.实例变量属性名,如代码中的self.name和self.score,可以在类的外部修改类的内部属性(相当于变量赋值)。
要让内部属性不被外部访问,可以在属性名称前加两个下划线__.在python中,实例的变量名如果以__开头,就会变成私有变量,只能内部访问,外部不能访问。例如:
>>> class Student(object):
def __init__(self,name,score):
self.__name=name
self.__score=score
def info(self):
print(f'学生:{self.__name} 分数:{self.__score}')
>>> stu=Student('小名',60)
>>> print(f"修改前的分数:{stu.__score}")
Traceback (most recent call last):
File "<pyshell#20>", line 1, in <module>
print(f"修改前的分数:{stu.__score}")
AttributeError: 'Student' object has no attribute '__score'
从示例中我们可以看出已经无法从外部访问实例变量的属性__score了,这样可以确保外部代码不能随意修改对象内部的状态,通过访问限制的保护,代码更加安全。
私有变量的访问,可以通过get_attrs()方法。
私有变量的修改,可以通过set_attrs()方法。
class Student(object):
def __init__(self,name,score):
self.__name=name #定义私有属性
self.__score=score #定义私有属性
def info(self):
print(f"学生:{self.__name};分数:{self.__score}")
def get_score(self): #访问私有变量
return self.__score
def set_score(self,score): #修改私有变量,变量检查,避免传入无效参数
if score in range(0,100):
self.__score=score
else:
print("请输入0到100之内的数字")
stu=Student("张三",98)
stu.info()
print(f'修改前的分数:{stu.get_score()}')
stu.set_score(70)
print(f'修改后的分数:{stu.get_score()}')
stu.info()
stu.set_score(-50)
stu.info()
>>>
RESTART: C:/Users/86186/AppData/Local/Programs/Python/Python37/siyoubianliang.py
学生:张三;分数:98
修改前的分数:98
修改后的分数:70
学生:张三;分数:70
请输入0到100之内的数字
学生:张三;分数:70
>>>
通过私有变量和对应的set方法可以帮助我们参数检查,避免传入无效的参数。
私有方法:以两个下划线开头的方法即为私有方法,该方法不能在类外使用。
私有方法的调用:self.private_methods
继承
继承是实现方法重用的方法之一。
子类继承基类(父类、超类)。
继承的定义如下:
class DerivedClassName(BaseClassName):
.
.
python 中,继承有以下特点:
(1)继承中,基类的构造方法__init__()方法不会被自动调用,需要在子类的构造方法中专门调用。
(2)在调用基类的方法时需要加上基类的类名前缀,并带上self参数变量。区别于在类中调用普通函数时不需要带self参数。
(3)在python中,首先查找对应类型的方法,如果在子类中找不到对应的方法,才到基类中挨个查找。
>>> class Animal(object): #定义父类、基类、超类
def run(self): #父类中的方法
print("Animal is running...")
>>> class Dog(Animal): #定义子类Dog继承父类Animal
pass
>>> class Cat(Animal): #定义子类Cat继承父类Animal
pass
>>> dog=Dog() #实例化类
>>> dog.run() #通过子类的继承调用
Animal is running...
>>> cat=Cat()
>>> cat.run()
Animal is running...
子类不能继承父类的私有方法,也不能调用父类的私有方法。
class Homan(object):
def __init__(self,name,sex):
print("人类是从猿类进化而来。")
self.__name=name
self.__sex=sex
def dingyi(self):
print(f'人类有个共同的名字:{self.__name}')
print(f"人类的性别是:{self.__sex}")
class Man(Homan):
def first(self):
print("男人有jj")
class WoMan(Homan):
def first(self):
print("女人有长腿")
Ren=Homan("未来战士","男或女")
Ren.dingyi() #调用父类的私有方法
print("*"*30)
s2=Man(2,3)
s2.first() #调用子类的方法,父类定义的私有变量不能调用,也不能继承
人类是从猿类进化而来。
人类有个共同的名字:未来战士
人类的性别是:男或女
******************************
人类是从猿类进化而来。
男人有jj
继承可以一级一级的继承下来,就好比从爷爷到爸爸再到儿子的关系,所有的类最终都可以追溯到根部object,这些继承关系看上去就像一颗倒着的树。
多重继承
一个子类可以有多个父类,同时获得多个父类的所有非私有功能。
格式:
class DeribedClassName(Base1,Base2,Base3…)
.
.
多态
当子类和父类拥有同名的方法时,子类的方法会覆盖父类的方法,在代码运行是总是会调用子类的方法,称为多态。
多态即根据对象(或类)的不同而表现出不同的行为。
唯一可以毁掉多态的是使用函数显式的检查类型,如tpye()、isinstance()等函数。如果有可能,就尽量避免使用这些毁掉多态的方法。
封装
封装是全局作用域中其他区域影藏多余信息的原则。
封装并不等同于多态,多态可以让用户对不知道类(或对象类型)的对象进行方法调用,而封装可以不用关心对象是如何构建的,直接使用即可。
>>> class Student(object):
def __init__(self,name,score):
self.name=name
self.score=score
>>> std=Student('xiaozhi',90)
>>> def info(std):
print(f"学生:{std.name}分数:{std.score}")
>>> info(std)
学生:xiaozhi分数:90
由输出结果看,可以通过函数调用类并得到结果。
>>> class Student(object):
def __init__(self,name,score):
self.name=name
self.score=score
def info(self):
print(f"学生:{std.name}分数:{std.score}")
>>> std=Student('xiaozhi',90)
>>> std.info()
学生:xiaozhi分数:90
直接将方法info()封装在了Student()类中。
这样一来,我们从外部看Student类,只需要知道创建实例需要给出name和score,如何输出是在Student类的内部定义实现,这些数据和逻辑被“封装”起来了,调用很容易,但却不知道内部细节的实现。
封装的另一个好处是可以给Student类增加新方法,比如我们在类的访问权限中所讲述的get_score()方法和set_score()方法。使用这些方法时,无须知道内部实现细节,直接调用既可以。
获取对象信息
type()函数
用type()基本类型都可以判断。
>>> type(123)
<class 'int'>
>>> type(None)
<class 'NoneType'>
>>> type(abs)
<class 'builtin_function_or_method'>
isinstance()函数
通过isinstance()判断class的数据类型确定class的继承关系。
>>> isinstance([1,2,3],(list,tuple))
True
dir()
dir()可以活的一个对象的所有属性和方法。dir()函数返回一个字符串的list。
>>> dir(123)
['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']
>>> dir("abc")
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
类的专有方法
str()
>>> class Student(object):
def __init__(self,name):
self.name=name
def info(self):
return(f"学生:{std.name}")
>>> print(Student('xiaoli'))
<__main__.Student object at 0x0000011A1B1BBF48>
>>> class Student(object):
def __init__(self,name):
self.name=name
def __str__(self):
return(f"学生:{std.name}")
>>> print(Student('xiaoli'))
学生:xiaozhi