Python面向对象编程

面向对象编程

类和实例

和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__方法,在创建实例的时候,就把namescore等属性绑上去:

注:__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'

这个属性,所有的对象都可以访问。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值