文章目录
面向对象编程
类和实例
和Java一样,把类作为编程的基本单位。
以Class为基本单位,里面包括属性和方法。
例如,学生类:
class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
def print_score(self):
print('%s: %s' % (self.name, self.score))
括号中的(Object)指的是继承下来的类。
bart = Student('Bart Simpson', 59)
lisa = Student('Lisa Simpson', 87)
bart.print_score()
lisa.print_score()
此处的bart是类的一个实例化,也就是通过类创造了对象。
通过定义一个特殊的__init__
方法,在创建实例的时候,就把name
,score
等属性绑上去:
注:__init__
方法的第一个参数永远是self
,表示创建的实例本身,因此,在__init__
方法内部,就可以把各种属性绑定到self
,因为self
就指向创建的实例本身。(类似于java的this)
无论是什么方法,第一个参数都得是self
访问限制
如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__
,在Python中,实例的变量名如果以__
开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问
注:在Python中,变量名类似__xxx__
的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以,不能用__name__
、__score__
这样的变量名。
继承和多态
继承:直接获取父类的属性和变量
多态:子类方法可以覆盖父类同名方法,同时,父类作为参数的函数或者方法都可以不加修改地正常运行,原因就在于多态。
动态语言的鸭子类型特点决定了继承不像静态语言那样是必须的。
鸭子类型
调用对象不看类型,只看方法。
比如:
function calculate(a, b, c) => return (a+b)*c
example1 = calculate (1, 2, 3)
example2 = calculate ([1, 2, 3], [4, 5, 6], 2)
example3 = calculate ('apples ', 'and oranges, ', 3)
print to_string example1
print to_string example2
print to_string example3
其中的example3其实是不合理的,因为对于calculate函数所针对的对象应当是一个数。但是,因为str类型支持‘+’,因此这个函数可以执行。
运行结果:
9
[1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6]
apples and oranges, apples and oranges, apples and oranges,
那么,不要求str继承int或者float类型,只要支持*和+两个方法就可以了。
再例如:
class Duck:
def quack(self):
print("这鸭子在呱呱叫")
def feathers(self):
print("这鸭子拥有白色与灰色羽毛")
class Person:
def quack(self):
print("这人正在模仿鸭子")
def feathers(self):
print("这人在地上拿起1根羽毛然後给其他人看")
def in_the_forest(duck):
duck.quack()
duck.feathers()
def game():
donald = Duck()
john = Person()
in_the_forest(donald)
in_the_forest(john) # 此处的代码在java中无法运行,in_the_forset的参数是duck,但是john是个人。但是在python中这句代码可以运行。python只访问需要的方法,所以只要函数中调用的方法在参数中存在就可以执行
game()
鸭子类型,让python在不继承的情况下,也可以使用多态的特性。
获取对象信息
使用type()判断
用法:
>>> type(123)
<class 'int'>
>>> type(str)
<class 'type'>
>>> type('str')
<class 'str'>
要判断一个对象是否是函数怎么办?可以使用types
模块中定义的常量:
>>> import types
>>> def fn():
... pass
...
>>> type(fn)==types.FunctionType # 函数类型
True
>>> type(abs)==types.BuiltinFunctionType
True
>>> type(lambda x: x)==types.LambdaType # lambdaType类型
True
>>> type((x for x in range(10)))==types.GeneratorType # 生成器类型
True
使用isinstance
insinstance()可以用来判断实例和类之间的关系。
用法:isinstance(对象,类),如果对象属于该类就是True,不属于就是False
如果:
object -> Animal -> Dog -> Husky
则
>>> class Animal(object):
... pass
...
>>> class Dog(Animal):
... pass
...
>>> class Baby(Dog):
... pass
...
>>> MT = Baby()
>>> isinstance(MT, Dog)
True
使用dir()
使用dir()可以获取一个对象所有的属性和方法
>>> dir('abc')
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__ge
tnewargs__', '__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', 'isdigi
t', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition'
, 'removeprefix', 'removesuffix', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip',
'swapcase', 'title', 'translate', 'upper', 'zfill']
我们自己写的类,也可以加一些常用方法,比如__len__
方法返回长度。在Python中,如果你调用len()
函数试图获取一个对象的长度,实际上,在len()
函数内部,它自动去调用该对象的__len__()
方法,所以,下面的代码是等价的。我们自己写的类,如果也想用len(myObj)
的话,就自己写一个__len__()
方法:
>>> class MyDog(object):
... def __len__(self):
... return 100
...
>>> dog = MyDog()
>>> len(dog)
100
getattr()、
setattr()以及
hasattr()
用法:getattr(类对象,属性)
getattr()返回某个属性的值,如果试图获取不存在的属性,会抛出AttributeError的错误。
如果不想抛出错误,可以传入一个default参数,如果属性不存在,就返回默认值。
setattr(对象,属性,值)
添加一个属性并设置他的值
hasattr()
判断某对象是否存在一个属性
例如,对于类Myobject:
>>> class MyObject(object):
... def __init__(self):
... self.x = 9
... def power(self):
... return self.x * self.x
...
>>> obj = MyObject()
>>> hasattr(obj, 'x') # 有属性'x'吗?
True
>>> obj.x
9
>>> hasattr(obj, 'y') # 有属性'y'吗?
False
>>> setattr(obj, 'y', 19) # 设置一个属性'y'
>>> hasattr(obj, 'y') # 有属性'y'吗?
True
>>> getattr(obj, 'y') # 获取属性'y'
19
>>> obj.y # 获取属性'y'
19
>>> getattr(obj, 'z', 404) # 获取属性'z',如果不存在,返回默认值404
404
实例属性和类属性
就类似Iava的静态属性。属于类的属性。
给实例绑定属性的方法是通过实例变量,或者通过self
变量:
class Student(object):
def __init__(self, name):# 通过self变量
self.name = name
s = Student('Bob')
s.score = 90 # 通过实例变量
同时,也可以给实例绑定一个方法。
>>> def set_age(self, age): # 定义一个函数作为实例方法
... self.age = age
...
>>> from types import MethodType # 这个类型是Python自带的方法
>>> s.set_age = MethodType(set_age, s) # 给实例绑定一个方法
>>> s.set_age(25) # 调用实例方法
>>> s.age # 测试结果
25
通过Python自带的方法进行绑定。
如果Student
类本身需要绑定一个属性呢?可以直接在class中定义属性,这种属性是类属性,归Student
类所有:
class Student(object):
name = 'Student'
这个属性,所有的对象都可以访问。