1

python中的类和对象

python类定义

python类的定义

  • 使用class关键字定义一个类,并且类名的首字母要大写
  • 当创建的类型不能用简单类型表示时就需要创建类
  • 类把需要的变量和函数组合在一起,即为“封装”

python类的结构

class 类名(遵循大驼峰语法规则->首字母大写):
    成员变量
    成员函数

实例1:

class Money: # 创建一个类
    pass


print(Money)  # 类
print(Money.__name__) # 类名
one = Money()  # 对象实例化
print(one)   # Money的对象
print(one.__class__) # 对象的类

结果输出:

<class '__main__.Money'>
Money
<__main__.Money object at 0x0000020572266FD0>
<class '__main__.Money'>

实例2:

# 1. 定义一个类
class Person:
    pass

# 2. 根据类,创建一个对象
p = Person()

# 3. 给p对象,增加一些属性
p.age = 10  # 新增一个属性
p.height = "120"
p.age = 15  # 修改一个属性
p.pets = ['xiaomao', 'xiaogou']

# 4. 验证是否添加成功
print(p.__dict__)  # 类属性
print(p.__class__)  # 类属性
print(p.age)        # 对象属性
print(p.pets, id(p.pets))

# 5. 修改属性
p.pets = [1, 2]   # 修改属性
print(p.pets, id(p.pets))
# 6. 访问属性
p.pets.append(3)   # 访问属性,id不会
print(p.pets, id(p.pets))
# 7. 删除属性
del p.age
print(p.age)

结果输出:

{'age': 15, 'height': '120', 'pets': ['xiaomao', 'xiaogou']}
<class '__main__.Person'>
15
['xiaomao', 'xiaogou'] 2478101597248
[1, 2] 2478111267584
[1, 2, 3] 2478111267584
Traceback (most recent call last):
  File "D:\public\python_exam\hello.py", line 1481, in <module>
    print(p.age)
AttributeError: 'Person' object has no attribute 'age'

实例3:# 类属性-增加(方式1)

class Person:  # 类也是对象
    pass

Person.num = 1  # 增加属性
print(Person.num)
print(Person.__dict__) 

结果输出:

1
{'__module__': '__main__', '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None, 'num': 1}

实例4: # 类属性-增加(方式2)

class Person:  # 类也是对象
    age = 10  # 增加属性
    height = 120 # 增加属性
    number = 9527 # 增加属性


print(Person.age)
print(Person.height)
print(Person.number)
print(Person.__dict__)

结果输出:

10
120
9527
{'__module__': '__main__', 'age': 10, 'height': 120, 'number': 9527, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}

实例5:# 类属性-查询属性

class Person:  # 类也是对象
    age = 10
    height = 120
    number = 9527


jack = Person()  # 类的实例化
print(jack.__class__)
print(jack.age)

结果输出:

<class '__main__.Person'>
10

对象查询属性的过程:首先先看对象自身有没有属性,如果有直接输出,如果没有,则通过__class__访问到类对象,如果有则输出,如果没有则报错

实例6:

class Person:  # 类也是对象
    age = 10
    height = 120
    number = 9527


jack = Person()  # 类的实例化
jack.sex = 'female'
print(jack.__class__)
print(jack.age)
print(jack.sex)
print(Person.sex)  

结果输出:

<class '__main__.Person'>
10
female
Traceback (most recent call last):
  File "D:\public\python_exam\hello.py", line 1494, in <module>
    print(Person.sex)
AttributeError: type object 'Person' has no attribute 'sex'

类对象不能访问实例化对象的属性

实例7:# 类属性-修改属性

class Person:  # 类也是对象
    age = 10
    height = 120
    number = 9527


jack = Person()
jack.age = 12
print(jack.age)
print(Person.age)  # 对象改变属性,类对象的属性不变
Person.age = 14
print(jack.age)   
print(Person.age) # 修改类属性,则类属性改变

结果输出:

12
10
12
14

类属性修改只能通过类修改,而查询对象属性,首先要在对象里查找,查找不到则会去类对象查找,修改对象属性,则只有对象属性改变,类对象属性不变

实例8:# 类属性-删除属性

class Person:  # 类也是对象
    age = 10
    height = 120
    number = 9527

one = Person()
print(one.age)
print(Person.age)

del Person.age  # 删除类属性
print(one.age)
print(Person.age)

结果输出:

10
10
Traceback (most recent call last):
  File "D:\public\python_exam\hello.py", line 1493, in <module>
    print(one.age)
AttributeError: 'Person' object has no attribute 'age'   # 类属性删除后不再有age属性

看是否能不能通过对象删除类属性呢?

class Person:  # 类也是对象
    age = 10
    height = 120
    number = 9527

one = Person()
print(one.age)
print(Person.age)

del one.age  # 删除类属性
print(one.age)
print(Person.age)

结果输出:

10
10
Traceback (most recent call last):
  File "D:\public\python_exam\hello.py", line 1492, in <module>
    del one.age  # 删除类属性
AttributeError: age   # 对象本身就没有age属性,因此报AttributeError,与上面案例的报错不同

实例9:# 类属性-更改

class Person:  # 类也是对象
    age = 10
    height = 120
    number = 9527


Person.__dict__ = {'sex': 'female'}  # 类属性都存在`__dict__`里,看是否可以通过更改`__dict__`来更改类属性

结果输出:

Traceback (most recent call last):
  File "D:\public\python_exam\hello.py", line 1489, in <module>
    Person.__dict__ = {'sex': 'female'}
AttributeError: attribute '__dict__' of 'type' objects is not writable  # 类属性是只读不可写的
class Person:  # 类也是对象
    age = 10
    height = 120
    number = 9527


one = Person()
one.__dict__["age"] = 12 
print(one.age)

一般情况下,属性存储在__dict__字典中,类对象的__dict__为只读,但是一般对象可以直接修改__dict__

实例10:# 类属性-查询、新增、修改

class Person:  # 类也是对象
    age = 10
    height = 120
    number = 9527


jack = Person()
jack.age = jack.age + 5  
print(Person.age)
print(jack.age)

结果输出:

10
15

jack.age首先查看jack对象里有没有age,没有,那么去Person里查询age,得到age之后又把age + 5 赋值给jack.age。因此等号右jack.age是查询Personage
等号左jack.age是对jack新增age属性。总结:对jack而言是新增age属性,对Person不变。(新增和修改的判断依据是看原对象里有没有,如果有则是修改,如果没有则是新增)

实例11:# 类属性-限定新增属性
__slots__实现限定新增属性功能

class Person:  # 类也是对象
    __slots__ = ['age']
    pass


p1 = Person()
p1.age = 10
print(p1)
p1.num = 9527

结果:

<__main__.Person object at 0x000001A37B755FD0>
Traceback (most recent call last):
  File "D:\public\python_exam\hello.py", line 1491, in <module>
    p1.num = 9527
AttributeError: 'Person' object has no attribute 'num'

__slots__已经限定了类属性,再增加其他属性则会报错

python面向对象-方法

class Person: # 创建类
    def eat(self):
        print('eat rice')

p = Person() # 创建对象
p.eat()

结果输出:

eat rice

类方法的作用是实现目标动作

方法的划分

class Person:  # 创建类
    def eat(self):  # 实例方法
        print('这是一个实例方法', self)

    @classmethod
    def leifangfa(cls):  # 类方法
        print('这是一个类方法', cls)

    @staticmethod
    def jingtaifangfa():  # 静态方法
        print('这是一个静态方法')


p = Person()  # 创建对象
print(p)
p.eat()
print('*'*20)
Person.leifangfa()
print('*'*20)
Person.jingtaifangfa()

结果输出:

<__main__.Person object at 0x000001A6ED0C5F70>
这是一个实例方法 <__main__.Person object at 0x000001A6ED0C5F70>
********************
这是一个类方法 <class '__main__.Person'>
********************
这是一个静态方法

实例方法、类方法、静态方法的存储位置在哪?是在类对象里还是在实例对象中呢?

class Person:  # 创建类
    def eat(self):  # 实例方法
        print('这是一个实例方法', self)

    @classmethod
    def leifangfa(cls):  # 类方法
        print('这是一个类方法', cls)

    @staticmethod
    def jingtaifangfa():  # 静态方法
        print('这是一个静态方法')


p = Person()  # 创建对象
print(p.__dict__)
print(Person.__dict__)

结果输出:

{}   # 说明不在实例对象里
{'__module__': '__main__', 'eat': <function Person.eat at 0x00000273F5C1C4C0>, 'leifangfa': <classmethod object at 0x000002738F286FD0>, 'jingtaifangfa': <staticmethod object at 0x000002738F286FA0>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None} # 在类对象里

万物皆对象,int、str、甚至函数也都是对象

class Person:  # 创建类
    def eat(self):  # 实例方法
        print('这是一个实例方法', self)

    @classmethod
    def leifangfa(cls):  # 类方法
        print('这是一个类方法', cls)

    @staticmethod
    def jingtaifangfa():  # 静态方法
        print('这是一个静态方法')


def run():
    print('run')

p = Person()  # 创建对象
p.age = 10
print(p.__dict__)
p.age = run
print(p.__dict__)

结果输出:

{'age': 10}
{'age': <function run at 0x000001F545BFF1F0>}

小结:

  • 实例方法:默认第一个参数需要接收到一个实例
  • 类方法:默认第一个参数需要接收到一个类
  • 静态方法:第一个参数啥也不用接收
    划分的依据: 方法的第一个参数必须要要接收的数据类型,不管是哪一种类型的方法,都是存储在类当中,没有在实例当中的,不同类型方法的调用方式不同
  • 万物皆对象,数字、字符串、函数都是对象,都可以赋给实例对象属性

python面向对象-方法

a) 实例方法

class Person:
    def eat(self, food):
        print("在吃饭, 吃", self, food)

p = Person()
print(p) # 无需传递第一个参数self, self相当于p
p.eat("米饭")

结果输出:

<__main__.Person object at 0x000001F54FB75FD0>
在吃饭, 吃 <__main__.Person object at 0x000001F54FB75FD0> 米饭

实例1

class Person:
    def eat(self, food):
        print("在吃饭, 吃", food)


p = Person()  # ()代表创建实例
p.eat("大米")

结果输出:

在吃饭, 吃 大米

b) 类方法

class Person:
    @classmethod
    def leifangfa(cls, a):
        print('这是一个类方法', cls, a)


Person.leifangfa(123)
p = Person()
p.leifangfa(666)

func = Person.leifangfa
func(111)

结果输出:

这是一个类方法 <class '__main__.Person'> 123
这是一个类方法 <class '__main__.Person'> 666
这是一个类方法 <class '__main__.Person'> 111

c) 静态方法
Convert a function to be a static method.
A static method does not receive an implicit first argument. To declare a static method

class Person:
    @staticmethod
    def jingtaifangfa():
        print('这是一个静态方法')


Person.jingtaifangfa()
p = Person()
p.jingtaifangfa()

func = Person.jingtaifangfa  # 注意这里没有括号
func()

结果输出:

这是一个静态方法
这是一个静态方法
这是一个静态方法

实例1:类属性和实例属性

class Person:
    age = 0


p = Person()
p.num = 10
# 类属性
print(Person.age)
print(p.age)
# 实例属性
print(p.num)

结果输出:

0
0
10

实例2:

class Person:
    age = 0
    def shilifanfga(self):
        print(self)
        print(self.age)
        print(self.num)

    # @classmethod
    # def leifangfa(cls):
    #     print(cls)
    #     print(cls.age)
    #     print(cls.num)
    #
    # @staticmethod
    # def jingtaifangfa():
    #     print(Person.age)
    #     print(Person.num)


p = Person()
p.num = 10
p.shilifanfga()
# p.leifangfa()
# p.jingtaifangfa()

结果输出:

<__main__.Person object at 0x0000029AE7D35FD0>
0
10  # 能访问

说明实例方法能够访问实例对象属性

实例3:

class Person:
    age = 0
    def shilifanfga(self):
        print(self)
        print(self.age)
        print(self.num)

    @classmethod
    def leifangfa(cls):
        print(cls)
        print(cls.age)
        print(cls.num)
    #
    # @staticmethod
    # def jingtaifangfa():
    #     print(Person.age)
    #     print(Person.num)


p = Person()
p.num = 10
# p.shilifanfga()
p.leifangfa()
# p.jingtaifangfa()

结果输出

<class '__main__.Person'>
0
Traceback (most recent call last):
  File "D:\public\python_exam\hello.py", line 1540, in <module>
    p.leifangfa()
  File "D:\public\python_exam\hello.py", line 1529, in leifangfa
    print(cls.num)
AttributeError: type object 'Person' has no attribute 'num'

说明类方法不能访问实例对象属性

实例4:

class Person:
    age = 0
    def shilifanfga(self):
        print(self)
        print(self.age)
        print(self.num)

    @classmethod
    def leifangfa(cls):
        print(cls)
        print(cls.age)
        print(cls.num)
    #
    @staticmethod
    def jingtaifangfa():
        print(Person.age)
        print(Person.num)


p = Person()
p.num = 10
# p.shilifanfga()
# p.leifangfa()
p.jingtaifangfa()

结果输出:

0
Traceback (most recent call last):
  File "D:\public\python_exam\hello.py", line 1541, in <module>
    p.jingtaifangfa()
  File "D:\public\python_exam\hello.py", line 1534, in jingtaifangfa
    print(Person.num)
AttributeError: type object 'Person' has no attribute 'num'

静态方法也不能访问实例对象属性

实例5: 万物皆对象

num = 10
print(num.__class__)

s = 'abc'
print(s.__class__)

结果输出:

<class 'int'>
<class 'str'>

实例6: 万物皆对象(类的原始-元类)

num = 10
print(num.__class__)

s = 'abc'
print(s.__class__)

class Person:
    pass

p = Person() # 对象实例化
print(p.__class__)

print(int.__class__.__class__)

print(s.__class__.__class__)

结果输出:

<class 'int'>
<class 'str'>
<class '__main__.Person'>
<class 'type'>  # 元类
<class 'type'>  # 元类

解释: 10的类对象是intint的类对象是type(元类),再向上还是type,已经到头了,同理,abc的类对象是strstr的类对象是type

实例7 元类type的使用

num = 10
print(type(num))  # 第一种用法


def run(self):
    print(self, 'run')


x = type('Dog', (), {'count': 0, 'run': run})  # 第二种使用type创建类对象的方法
print(x)
print(x.__dict__)
d = x()
print(d.count)
print(d.run)

结果输出:

<class 'int'>
<class '__main__.Dog'>
{'count': 0, 'run': <function run at 0x0000023ADC7FF1F0>, '__module__': '__main__', '__dict__': <attribute '__dict__' of 'Dog' objects>, '__weakref__': <attribute '__weakref__' of 'Dog' objects>, '__doc__': None}
0
<bound method run of <__main__.Dog object at 0x0000023AF5F95FD0>>

type第一种使用方式,直接获取实例对象的类对象,第二种使用方式,创建类对象

python面向对象-类的创建流程

  • 步骤1. 检测类对象中是否有明确__metaclass__属性
  • 步骤2. 检测父类中是否存在__metaclass__属性
  • 步骤3. 检测模块中是否存在————metadata__属性
  • 步骤4. 通过内置的type元类来创建类对象

python面向对象-类的描述

写注释的目的有1)逻辑清晰;2)利于多人开发;3)方便生成项目文档

class Person:
    """
    关于这个类的描述,类的作用,类的构造函数等等;类属性的描述
    Attributes:
        count: int 代表人的个数
    """
    # 表示人的个数
    count = 1

    def run(self, distance, step):
        """
        这个方法的作用效果
        :param distance: 参数含义,参数的类型,是否有默认值
        :param step:
        :return: 返回结果含义,返回数据的类型
        """
        print('开始跑!')
        return distance/step

help(Person)  # 查看注释文档

结果输出:

Help on class Person in module __main__:

class Person(builtins.object)
 |  关于这个类的描述,类的作用,类的构造函数等等;类属性的描述
 |  Attributes:
 |      count: int 代表人的个数
 |  
 |  Methods defined here:
 |  
 |  run(self, distance, step)
 |      这个方法的作用效果
 |      :param distance: 参数含义,参数的类型,是否有默认值
 |      :param step:
 |      :return: 返回结果含义,返回数据的类型
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |  
 |  count = 1

生成项目文档- 使用内置模块pydoc
步骤1: 打开cmd
步骤2: 进入python文件路径
步骤3: 使用python内置函数 python -m pydoc -p 1234 # 使用内置函数pydoc 打开端口1234
步骤4: 打开浏览器 http://localhost:1234/hello.html
以上步骤就可以看到生成项目文档
将项目文档写入html
在文件目录cmd下执行python -m pydoc -w 文件.py
会自动生成文件.html,可以通过浏览器打开

python面向对象-私有化属性

a) 公有属性

class Animal:
    x = 10  # 公有属性

    def test(self):
        print(Animal.x)  # 类方法可以访问公有属性
        print(self.x)    # 类方法可以访问公有属性

    pass


class Dog(Animal):  # 继承Animal
    def test2(self):
        print(Dog.x)  # 衍生类也可以访问公有属性
        print(self.x)  # 衍生类也可以访问公有属性
    pass


# 测试代码
a = Animal()
a.test()
print('*'*20)
d = Dog()
d.test2()
print('*'*20)
print(Animal.x)
print(Dog.x)
print(a.x)
print(d.x)

结果输出:

10
10
********************
10
10
********************
10
10
10
10

模块导入私有化属性
使用方法1:

import 模块
print(模块.func)

使用方法2:

from 模块 import func
print(func)

b) 受保护属性 _属性

#
class Animal:
    _x = 10  # 受保护属性

    def test(self):
        print(Animal._x)
        print(self._x)

    pass


a = Animal()
a.test()


class Dog(Animal):  # 继承Animal
    def test2(self):
        print(Dog._x)  # 衍生类也可以访问公有属性
        print(self._x)  # 衍生类也可以访问公有属性

    pass


d = Dog()
d.test2()

print(Animal._x)  # 强行访问没问题,但是不建议这样访问
print(Dog._x)  # 强行访问没问题,但是不建议这样访问
print(a._x)   # 强行访问没问题,但是不建议这样访问
print(d._x)  # 强行访问没问题,但是不建议这样访问

结果输出:

10
10
10
10
10
10

受保护类属性,不管是自己类内部还是衍生类内部都可以访问

受保护变量跨模块访问则出现问题
如果

from 模块 import _func
print(_func) # 不报错

但是

from 模块 import *
print(_func) # 报错,没有_func变量

_属性即受保护属性,类内部访问不报错,子类内部访问不报错,模块内其他位置访问如类访问(包含父类和派生类)会出现警告不报错;实例访问(父类实例和派生类实例)会出现警告不报错,而跨模块访问的时候,import形式导入则警告不报错,from module import *的形式导入,如果有__all__(all = ["受保护变量属性"])指明对应变量则警告不报错,没有__all__指明对应变量则报错

c) 受保护属性
实例1

class Animal:
    __x = 10  # 受保护属性

    def test(self):
        print(Animal.__x)
        print(self.__x)

    pass


a = Animal()  # 类里面方法可以访问受保护属性
a.test()


class Dog(Animal):  # 继承Animal
    def test2(self):
        print(Dog.__x) 
        print(self.__x)
    pass


d = Dog()
d.test2()

结果输出:

10
10
Traceback (most recent call last):
  File "D:\public\python_exam\hello.py", line 1617, in <module>
    d.test2()
  File "D:\public\python_exam\hello.py", line 1611, in test2
    print(Dog.__x)
AttributeError: type object 'Dog' has no attribute '_Dog__x'

类里面方法可以访问受保护属性,而子类不能访问父类受保护属性

实例2

class Animal:
    __x = 10  # 受保护属性

    def test(self):
        print(Animal.__x)
        print(self.__x)

    pass


a = Animal()
print(Animal.__x)   # 双下划线的受保护属性,类不能被访问,
print(a.__x)        # 类实例对象不能访问


class Dog(Animal):  # 继承Animal
    def test2(self):
        print(Dog.__x)
        print(self.__x)
    pass


d = Dog()
print(Dog.__x)  # 双下划线的受保护属性,子类不能被访问
print(d.__x)    # 双下划线的受保护属性,子类实例对象不能被访问

结果输出:

Traceback (most recent call last):
  File "D:\public\python_exam\hello.py", line 1606, in <module>
    print(Animal.__x)
AttributeError: type object 'Animal' has no attribute '__x'

双下划线的受保护属性,在本模块都不能被访问,无论是类还是子类,类实例对象还是子类实例对象均不能访问

实例3 跨模块访问
方式1:

在原模块中
__x = 10
在新模块中
from 原模块 imort *
print(__x)  #结果报错

方式2:

在原模块中
__all__ = ["__x"]
__x = 10
在新模块中
from 原模块 imort *
print(__x)  #结果不报错

双下划线的受保护属性的跨模块访问,参照单下划线开头变量的访问原则

d) 私有属性的实现机制
主要通过名字重整(Name Mangling),重名__x为另外一个名词,如_类名__x,目的是访问外界直接访问,防止被子类同名称属性覆盖

class Animal:
    __x = 10  # 受保护属性

    def test(self):
        print(Animal.__x)
        print(self.__x)

    pass


a = Animal()
print(Animal.__dict__)
print(Animal._Animal__x) # 如果想访问x,这样访问

结果输出:

{'__module__': '__main__', '_Animal__x': 10, 'test': <function Animal.test at 0x00000229FB1CC4C0>, '__dict__': <attribute '__dict__' of 'Animal' objects>, '__weakref__': <attribute '__weakref__' of 'Animal' objects>, '__doc__': None}  # 重点看=='_Animal__x': 10==
10

e) 私有化属性的应用场景

class Person: # 属性最好设计为实例属性而非类属性,不然所有的实例对象属性都相同
    # 主要作用,当创建好一个实例对象后,会自动调用这个方法,来初始化这个对象
    def __init__(self):
        self.__age = 18  # 私有属性

    def setAge(self, value):
        if isinstance(value, int) and 0 < value < 200: # 私有属性起到数据保护和数据过滤的作用
            self.__age = value
        else:
            print('Error')

    def getAge(self):
        return self.__age


p1 = Person()
p1.setAge(220)   # 设置数值
print(p1.getAge())  # 获得数值

p2 = Person()
p2.setAge(23)
print(p2.getAge())

结果输出:

Error
18
23

注意针对私有化属性 x: 几乎在所有地方都可以访问,_y:代表受保护属性,在类的内部和子类的内部访问,__z:代表私有属性,只能在类内部访问,以上均为权限问题,还有其他的x_或__x__则是规范问题,建议与系统内置做区分

python面向对象-只读属性

  • 概念 一个属性(一般指实例属性),只能读取,不能写入
  • 应用场景 有些属性,只限在内部根据不同场景进行修改,而对外界来说,不能修改,只能读取
    实例1
class Person:
    def __init__(self):
        self.age = 18  # 这样写既可以访问又可以修改


p1 = Person()
print(p1.age)
p1.age = 10
print(p1.age)

结果输出:

18
10

实例2:

class Person:
    def __init__(self):
        self.__age = 18  # 这样写只可以访问


p1 = Person()
p1.__age = 100
print(p1.__dict__)
print(p1._Person__age)  # 可以这样访问,但不建议
print(p1.__age)  # 和类初始化属性不是一个东西

结果输出:

{'_Person__age': 18, '__age': 100}
18
100

实例3

class Person:
    def __init__(self):
        self.__age = 18  # 这样写只可以访问

    def getAge(self): # 提供公开的方法
        return self.__age  # 访问只读属性操作


p1 = Person()
print(p1.getAge())

结果输出:

18

实例4:

class Person:
    def __init__(self):
        self.__age = 18  # 这样写只可以访问

    # 主要作用,可以使用属性的方式,来使用这个方法
    @property
    def getAge(self):
        return self.__age  # 访问只读属性操作


p1 = Person()
print(p1.getAge)   # ==这里已经是返回值了==
print(p1.getAge()) # 不能加括号

结果输出:

Traceback (most recent call last):
  File "D:\public\python_exam\hello.py", line 1660, in <module>
    print(p1.getAge())
TypeError: 'int' object is not callable
18

实例5:

class Person:
    def __init__(self):
        self.__age = 18  # 这样写只可以访问

    # 主要作用,可以使用属性的方式,来使用这个方法
    @property   # 装饰器property作用限定读取
    def age(self):
        return self.__age  # 访问只读属性操作


p1 = Person()
p1.age = 10  # 已经设定为只读,不能设置
print(p1.age)

结果输出:

Traceback (most recent call last):
  File "D:\public\python_exam\hello.py", line 1659, in <module>
    p1.age = 10
AttributeError: can't set attribute

实例6

class Person:
    def __init__(self):
        self.__age = 18  # 这样写只可以访问

    # 主要作用,可以使用属性的方式,来使用这个方法
    @property
    def age(self):
        return self.__age  # 访问只读属性操作

    @age.setter  # 对只读属性修改操作
    def age(self, value):
        self.__age = value


p1 = Person()
p1.age = 10  # 可以对只读属性重新赋值
print(p1.age)

结果输出:

10

python面向对象-新式类和经典类

python 2.x,如果定义一个类,没有显示的继承自object,那么这个类是一个经典类, 必须显示继承pbject,它才是一个新式类
python 3.x如果直接定义一个类,会隐式继承object,默认情况下,就已经是一个新式类

class Person:
    pass


print(Person.__base__)

结果输出:

<class 'object'>

实例1--property在新式类中的应用

class Person(object):
    def __init__(self):
        self.__age = 10

    def get_age(self):
        print('----,get')
        return self.__age

    def set_age(self, value):
        print('----,set')
        self.__age = value

    age = property(get_age, set_age)

p = Person()
print(p.age)

p.age = 90
print(p.age)

print(p.__dict__)

结果输出:

----,get
10
----,set
----,get
90
{'_Person__age': 90}

实例2:

class Person(object):
    def __init__(self):
        self.__age = 10

    @property
    def age(self):  
        print('-----, get')
        return self.__age

    @age.setter
    def age(self, value):
        print('-----, set')
        self.__age = value



p = Person()
print(p.age)  # 读取私有属性

p1 = Person()
p1.age = 18  # 修改私有属性
print(p1.age)

结果输出:

-----, get
10
-----, set
-----, get
18

实例3:

class Person:
    def __init__(self):
        self.__age = 10  # 初始化一个私有属性

    @property  # 装饰器可以使外界访问这个只读属性的方法
    def age(self):
        return self.__age

p = Person()
print(p.age)

结果输出:

10

实例4:增加修改只读属性

class Person:
    # 当我们通过实例,属性=值,给一个实例增加一个属性,或者说,修改一下属性值的时候,都会调用这个方法
    # 在这个方法内部,才会真正的把这个属性,以及对于的数据,给存储到__dict__字典里
    def __setattr__(self, key, value):  # 增加只读属性
        print(key, value)
        if key == 'age' and key in self.__dict__.keys():
            print("这个属性是只读属性,不能设置数据")
        else:
            self.__dict__[key] = value


p = Person()
p.age = 18
print(p.__dict__)

p.height = 120
print(p.__dict__)
print(p.age)
print(p.height)
p.age = 90
print(p.age)

结果输出:

age 18
{'age': 18}
height 120
{'age': 18, 'height': 120}
18
120
age 90
这个属性是只读属性,不能设置数据
18

python面向对象-常用内置属性

内置特殊属性主要包括类属性和实例属性
类属性主要包括:

  • dict: 类属性
  • bases : 类的所有父类构成元组
  • doc : 类的文档字符串
  • name :类名
  • module : 类定义一所在的模块
    实例属性主要包括:
  • dict : 实例的属性
  • class : 实例对应的类

实例1:

class Person:
    """
    这是一个人类
    """
    age = 19

    def __init__(self):
        self.name = "sz"

    def run(self):
        print("run")


print(Person.__dict__)  # 类的属性
print(Person.__bases__)  # 类的所有父类构成元组
print(Person.__doc__)  # 类的文档字符串
help(Person)
print(Person.__name__)  # 类名
print(Person.__module__)  # 类定义所在的模块
print('*'*20)
p = Person()
print(p.__class__)  # 实例对象的类  <类型  '所在模块名称.所属类名称'>

结果输出:

{'__module__': '__main__', '__doc__': '\n    这是一个人类\n    ', 'age': 19, '__init__': <function Person.__init__ at 0x0000018D7B8AC700>, 'run': <function Person.run at 0x0000018D14660550>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>}
(<class 'object'>,)

    这是一个人类
    
Help on class Person in module __main__:

class Person(builtins.object)
 |  这是一个人类
 |  
 |  Methods defined here:
 |  
 |  __init__(self)
 |      Initialize self.  See help(type(self)) for accurate signature.
 |  
 |  run(self)
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |  
 |  age = 19

Person
__main__
********************
<class '__main__.Person'>

python面向对象-私有方法

class Person:
    __age = 18

    def __run(self): # 私有方法
        print('run')

p = Person()
print(p.__dict__)
print(p.__run())

结果输出:

Traceback (most recent call last):
  File "D:\public\python_exam\hello.py", line 1770, in <module>
    print(p.__run())
AttributeError: 'Person' object has no attribute '__run'
{}

实例1: 私有方法的调用

class Person:
    __age = 18

    def __run(self):  # 私有方法
        print('run')

    def _Person__run(self):
        print('xxx')

p = Person()
p._Person__run()
print(Person.__dict__)

结果输出:

xxx
{'__module__': '__main__', '_Person__age': 18, '_Person__run': <function Person._Person__run at 0x000002292CE0C700>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}

实例2: 内置特殊方法 __str__

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):  # 内置特殊方法
        return '这个人的姓名是%s, 这个人的年龄是%s' % (self.name, self.age)


p1 = Person('sz', 18)
print(p1.name)
print(p1.age)
print(p1)
p2 = Person('na', 10)
print(p2.name)
print(p2.age)

s = str(p1)
print(s, type(s))

结果输出:

sz
18
这个人的姓名是sz, 这个人的年龄是18
na
10
这个人的姓名是sz, 这个人的年龄是18 <class 'str'>

实例3: 内置特殊方法 __repr__

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):  # 内置特殊方法
        return '这个人的姓名是%s, 这个人的年龄是%s' % (self.name, self.age)

    def __repr__(self):  # 内置特殊方法, 重写之后输出返回值,如果没有重写则使用默认方法, 要么面向开发人员,要么面向用户
        return "reprxxxx"


p1 = Person('sz', 18)
print(repr(p1))

结果输出:

reprxxxx

实例4: __repr__

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):  # 内置特殊方法
        return '这个人的姓名是%s, 这个人的年龄是%s' % (self.name, self.age)


p1 = Person('sz', 18)
print(repr(p1))  # repr 显示实例对象的类地址信息

结果输出:

<__main__.Person object at 0x000001D655B46FD0>

实例5: __repr__ # 面向python解释器开发人员

import datetime

t = datetime.datetime.now()
print(t) # 面向用户
tmp = repr(t)
print(repr(t)) # 面向解释器开发人员
result = eval(tmp)
print(result)

结果输出:

2023-03-25 10:55:29.167351
datetime.datetime(2023, 3, 25, 10, 55, 29, 167351)
2023-03-25 10:55:29.167351

实例6:__call__ # 使对象具备被调用的能力

class Person:
    def __call__(self, *args, **kwargs): # 功能是使对象具备被调用的能力
        print('xxx', args, kwargs)
    pass


p = Person()
p(123, 456, name='sz')

结果输出:

xxx (123, 456) {'name': 'sz'}

实例7: 偏函数functools使用方法

def createPen(p_color, p_type):
    print('创建了一个%s这个类型的画笔,它是%s颜色' % (p_type, p_color))


createPen("钢笔", '红色')

import functools
gangbiFunc = functools.partial(createPen, p_type="钢笔")

gangbiFunc(p_color='红色')
gangbiFunc('蓝色')
gangbiFunc('黑色')

结果输出:

创建了一个红色这个类型的画笔,它是钢笔颜色
创建了一个钢笔这个类型的画笔,它是红色颜色
创建了一个钢笔这个类型的画笔,它是蓝色颜色
创建了一个钢笔这个类型的画笔,它是黑色颜色

实例8:__call__使用场景

class PenFactory:
    def __init__(self, p_type):
        self.p_type = p_type

    def __call__(self, p_color):
        print('创建了一个%s这个类型的画笔,它是%s颜色' % (self.p_type, p_color))


gangbiF = PenFactory("钢笔")
gangbiF("红色")
gangbiF('绿色')

qianbiF = PenFactory("铅笔")
qianbiF('蓝色')
qianbiF('黄色')

结果输出:

创建了一个钢笔这个类型的画笔,它是红色颜色
创建了一个钢笔这个类型的画笔,它是绿色颜色
创建了一个铅笔这个类型的画笔,它是蓝色颜色
创建了一个铅笔这个类型的画笔,它是黄色颜色

python面向对象-索引操作

a) 增、改、查、删

class Person:
    def __init__(self):
        self.cache = {}

    def __setitem__(self, key, value):
        self.cache[key] = value

    def __getitem__(self, item):
        return self.cache[item]

    def __delitem__(self, key):
        del self.cache[key]
    pass


p = Person()
p['name'] = 'sz'  # 增
print(p['name'])  # 查
p['name'] = 'nn'  # 改
print(p.cache)
del p['name']     # 删
print(p.cache)

结果输出:

sz
{'name': 'nn'}
{}

b) 切片操作

class Person:
    def __init__(self):
        self.items = [1, 2, 3, 4, 5, 6, 7, 8]

    def __setitem__(self, key, value):
        self.items[key] = value

    def __getitem__(self, item):
        print('getitem', item)

    def __delitem__(self, key):
        print('delitem', key)


p = Person()
p[0: 4: 2] = [1, 2] # 替换操作
print(p.items)

结果输出

[1, 2, 2, 4, 5, 6, 7, 8]

c) 比较操作
实例1

class Person:
    def __init__(self, age, height):
        self.age = age
        self.height = height

    def __eq__(self, other):  # 相等操作
        print(other)
        return self.age == other.age

    def __ne__(self, other):  # 不等操作
        print('XXX')

    def __len__(self, other):  # 小于等于
        pass

    def __ge__(self, other):  # 大于等于
        pass

    def __lt__(self, other):  # 小于
        pass

    pass


p1 = Person(18, 120)
p2 = Person(19, 110)

print(p1 == p2)
print(p1 != p2)

结果输出:

<__main__.Person object at 0x0000015A85177F70>
False
XXX   # 不等于调用 `__ne__(self, other)`
None  # 没有return

实例2:

class Person:
    def __init__(self, age, height):
        self.age = age
        self.height = height

    def __eq__(self, other):  # 相等操作
        print(other)
        return self.age == other.age

    def __ne__(self, other):  # 不等操作
        print('XXX')

    def __le__(self, other):  # 小于等于
        pass

    def __ge__(self, other):  # 大于等于
        pass

    def __lt__(self, other):  # 小于
        print('lt')
        return self.age < other.age


    pass


p1 = Person(18, 120)
p2 = Person(19, 110)

print(p1 == p2)
print(p1 < p2)

结果输出:

<__main__.Person object at 0x0000027BD22E7F70>
False
lt
True

实例3:

import functools
@functools.total_ordering  # 根据已知的内置方法,补充其他的方法
class Person:
    def __lt__(self, other):  # 小于
        print('lt')
        pass

    def __eq__(self, other):   # 等于
        print('eq')
        pass

    def __le__(self, other):  # 小于等于
        print('le')


p1 = Person()
p2 = Person()
print(p1 <= p2)
print(Person.__dict__)

结果输出:

le
None
{'__module__': '__main__', '__lt__': <function Person.__lt__ at 0x0000020E91D8C4C0>, '__eq__': <function Person.__eq__ at 0x0000020E91D8C700>, '__le__': <function Person.__le__ at 0x0000020EAAB51550>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None, '__hash__': None, '__gt__': <function _gt_from_lt at 0x0000020E91FC2160>, '__ge__': <function _ge_from_lt at 0x0000020E91FC2280>}

python面向对象-比较操作(上下文布尔值)

class Person:
    def __init__(self):
        self.age = 18

    def __bool__(self):
        return self.age >= 18
    pass


p = Person()
if p:
    print('xx')

结果输出:
xx

python面向对象-遍历操作

实例1

class Person:
    def __init__(self):
        self.result = 1

    def __iter__(self):
        print('iter')
        return self

    def __next__(self):
        self.result += 1
        if self.result >= 6:
            raise StopIteration('stop iteration')
        return self.result
    pass


p = Person()  
for i in p: # 首先用iter,再使用next获取数据,直到抛出异常为止
    print(i)

实例2

class Person:
    def __init__(self):
        self.result = 1

    # def __iter__(self):
    #     print('iter')
    #     return self

    def __next__(self):
        self.result += 1
        if self.result >= 6:
            raise StopIteration('stop iteration')
        return self.result
    pass


p = Person()

print(next(p))  #
print(next(p))
print(next(p))  #
print(next(p))
print(next(p))  #
print(next(p))

结果输出:

2
3
4
5
Traceback (most recent call last):
  File "D:\public\python_exam\hello.py", line 1985, in <module>
    print(next(p))  #
  File "D:\public\python_exam\hello.py", line 1974, in __next__
    raise StopIteration('stop iteration')
StopIteration: stop iteration
posted @ 2023-03-23 10:45  Bonne_chance  阅读(52)  评论(0编辑  收藏  举报
1