Python面向对象之成员相关知识总结


Posted in Python onJune 24, 2021

1、成员

 1.1 变量

  • 实例变量,属于对象,每个对象中各自维护自己的数据。
  • 类变量,属于类,可以被所有对象共享,一般用于给对象提供公共数据(类似于全局变量)。
class Person(object):
    country = "中国"
 
    def __init__(self, name, age):
        self.name = name
        self.age = age
 
    def show(self):
        # message = "{}-{}-{}".format(Person.country, self.name, self.age)
        message = "{}-{}-{}".format(self.country, self.name, self.age)
        print(message)
 
print(Person.country) # 中国
 
 
p1 = Person("华青水上",20)
print(p1.name)
print(p1.age)
print(p1.country) # 中国
 
p1.show() # 中国-华青水上-20

提示:当把每个对象中都存在的相同的示例变量时,可以选择把它放在类变量中,这样就可以避免对象中维护多个相同数据。

易错点

  • 注意读和写的区别。
class Person(object):
    country = "中国"
 
    def __init__(self, name, age):
        self.name = name
        self.age = age
 
    def show(self):
        message = "{}-{}-{}".format(self.country, self.name, self.age)
        print(message)
 
print(Person.country) # 中国
 
p1 = Person("华青水上",20)
print(p1.name) # 华青水上
print(p1.age) # 20
print(p1.country) # 中国
p1.show() # 中国-华青水上-20
 
p1.name = "root"     # 在对象p1中讲name重置为root
p1.num = 19          # 在对象p1中新增实例变量 num=19
p1.country = "china" # 在对象p1中新增实例变量 country="china"
 
print(p1.country)   # china
print(Person.country) # 中国
class Person(object):
    country = "中国"
 
    def __init__(self, name, age):
        self.name = name
        self.age = age
 
    def show(self):
        message = "{}-{}-{}".format(self.country, self.name, self.age)
        print(message)
 
print(Person.country) # 中国
 
Person.country = "美国"
 
 
p1 = Person("华青水上",20)
print(p1.name) # 华青水上
print(p1.age) # 20
print(p1.country) # 美国
  • 继承关系中的读写
class Base(object):
    country = "中国"
 
 
class Person(Base):
 
    def __init__(self, name, age):
        self.name = name
        self.age = age
 
    def show(self):
        message = "{}-{}-{}".format(Person.country, self.name, self.age)
        # message = "{}-{}-{}".format(self.country, self.name, self.age)
        print(message)
 
 
# 读
print(Base.country) # 中国
print(Person.country) # 中国
 
obj = Person("华青水上",19)
print(obj.country) # 中国
 
# 写
Base.country = "china"
Person.country = "泰国"
obj.country = "日本"

1.2 方法

  • 绑定方法,默认有一个self参数,由对象进行调用(此时self就等于调用方法的这个对象)【对象&类均可调用】
  • 类方法,默认有一个cls参数,用类或对象都可以调用(此时cls就等于调用方法的这个类)【对象&类均可调用】
  • 静态方法,无默认参数,用类和对象都可以调用。【对象&类均可调用】
class Foo(object):
 
    def __init__(self, name,age):
        self.name = name
        self.age = age
 
    def f1(self):
        print("绑定方法", self.name)
 
    @classmethod
    def f2(cls):
        print("类方法", cls)
 
    @staticmethod
    def f3():
        print("静态方法")
        
# 绑定方法(对象)
obj = Foo("武沛齐",20)
obj.f1() # Foo.f1(obj)
 
 
# 类方法
Foo.f2()  # cls就是当前调用这个方法的类。(类)
obj.f2()  # cls就是当前调用这个方法的对象的类。
 
 
# 静态方法
Foo.f3()  # 类执行执行方法(类)
obj.f3()  # 对象执行执行方法

在Python中比较灵活,方法都可以通过对象和类进行调用;而在java、c#等语言中,绑定方法只能由对象调用;类方法或静态方法只能由类调用。

import os
import requests
 
 
class Download(object):
 
    def __init__(self, folder_path):
        self.folder_path = folder_path
 
    @staticmethod
    def download_dou_yin():
        # 下载抖音
        res = requests.get('.....')
 
        with open("xxx.mp4", mode='wb') as f:
            f.write(res.content)
 
    def download_dou_yin_2(self):
        # 下载抖音
        res = requests.get('.....')
        path = os.path.join(self.folder_path, 'xxx.mp4')
        with open(path, mode='wb') as f:
            f.write(res.content)
 
 
obj = Download("video")
obj.download_dou_yin()

1.3 属性

属性其实是由绑定方法 + 特殊装饰器 组合创造出来的,让我们以后在调用方法时可以不加括号。

class Foo(object):
 
    def __init__(self, name):
        self.name = name
 
    def f1(self):
        return 123
 
    @property
    def f2(self):
        return 123
 
 
obj = Foo("华青水上")
 
v1 = obj.f1()
print(v1)
 
v2 = obj.f2
print(v2)
class Pagination:
    def __init__(self, current_page, per_page_num=10):
        self.per_page_num = per_page_num
        
        if not current_page.isdecimal():
            self.current_page = 1
            return
        current_page = int(current_page)
        if current_page < 1:
            self.current_page = 1
            return
        self.current_page = current_page
	
    def start(self):
        return (self.current_page - 1) * self.per_page_num
	
    def end(self):
        return self.current_page * self.per_page_num
 
 
user_list = ["用户-{}".format(i) for i in range(1, 3000)]
 
# 分页显示,每页显示10条
while True:
    page = input("请输入页码:")
	
    # page,当前访问的页码
    # 10,每页显示10条数据
	# 内部执行Pagination类的init方法。
    pg_object = Pagination(page, 20)
    
    page_data_list = user_list[ pg_object.start() : pg_object.end() ]
    for item in page_data_list:
        print(item)
class Pagination:
    def __init__(self, current_page, per_page_num=10):
        self.per_page_num = per_page_num
 
        if not current_page.isdecimal():
            self.current_page = 1
            return
        current_page = int(current_page)
        if current_page < 1:
            self.current_page = 1
            return
        self.current_page = current_page
 
    @property
    def start(self):
        return (self.current_page - 1) * self.per_page_num
 
    @property
    def end(self):
        return self.current_page * self.per_page_num
 
 
user_list = ["用户-{}".format(i) for i in range(1, 3000)]
 
# 分页显示,每页显示10条
while True:
    page = input("请输入页码:")
 
    pg_object = Pagination(page, 20)
    page_data_list = user_list[ pg_object.start : pg_object.end ]
    
    for item in page_data_list:
        print(item)

关于属性的编写有两种方式:

  • 方式一,基于装饰器
class C(object):
    
    @property
    def x(self):
        pass
    
    @x.setter
    def x(self, value):
        pass
    
    @x.deleter
    def x(self):
		pass
        
obj = C()
 
obj.x
obj.x = 123
del obj.x
  • 方式二,基于定义变量
class C(object):
    
    def getx(self): 
		pass
    
    def setx(self, value): 
		pass
        
    def delx(self): 
		pass
        
    x = property(getx, setx, delx, "I'm the 'x' property.")
    
obj = C()
 
obj.x
obj.x = 123
del obj.x

注意:由于属性和实例变量的调用方式相同,所以在编写时需要注意:属性名称 不要 实例变量 重名。

class Foo(object):
 
    def __init__(self, name, age):
        self.name = name
        self.age = age
 
    @property
    def func(self):
        return 123
 
 
obj = Foo("华青水上", 123)
print(obj.name)

一旦重名,可能就会有报错。

class Foo(object):
 
    def __init__(self, name, age):
        self.name = name  # 报错,错认为你想要调用 @name.setter 装饰的方法。
        self.age = age
 
    @property
    def name(self):
        return "{}-{}".format(self.name, self.age)
 
 
obj = Foo("华青水上", 123)
class Foo(object):
 
    def __init__(self, name, age):
        self.name = name 
        self.age = age
 
    @property
    def name(self):
        return "{}-{}".format(self.name, self.age) # 报错,循环调用自己(直到层级太深报错)
 
    @name.setter
    def name(self, value):
        print(value)
 
 
obj = Foo("华青水上", 123)
print(obj.name)

如果真的想要在名称上创建一些关系,可以让实例变量加上一个下划线。

class Foo(object):
 
    def __init__(self, name, age):
        self._name = name
        self.age = age
 
    @property
    def name(self):
        return "{}-{}".format(self._name, self.age)
 
 
obj = Foo("华青水上", 123)
print(obj._name)
print(obj.name)

2.成员修饰符

Python中成员的修饰符就是指的是:公有、私有。

  • 公有,在任何地方都可以调用这个成员。
  • 私有,只有在类的内部才可以调用改成员(成员是以两个下划线开头,则表示该成员为私有)。
class Foo(object):
 
    def __init__(self, name, age):
        self.__name = name
        self.age = age
 
    def get_data(self):
        return self.__name
 
    def get_age(self):
        return self.age
 
 
obj = Foo("华青水上", 123)
 
 
# 公有成员
print(obj.age)
v1 = self.get_age()
print(v1)
 
# 私有成员
# print(obj.__name) # 错误,由于是私有成员,只能在类中进行使用。
v2 = obj.get_data()
print(v2)

特别提醒:父类中的私有成员,子类无法继承。

class Base(object):
 
    def __data(self):
        print("base.__data")
 
    def num(self):
        print("base.num")
 
 
class Foo(Base):
 
    def func(self):
        self.num()
        self.__data() # # 不允许执行父类中的私有方法
 
 
obj = Foo()
obj.func()
class Base(object):
 
    def __data(self):
        print("base.__data")
 
    def num(self):
        print("base.num")
        self.__data()  # 不允许执行父类中的私有方法
 
 
class Foo(Base):
 
    def func(self):
        self.num()
 
 
obj = Foo()
obj.func()

按理说私有成员是无法被外部调用,但如果用一些特殊的语法也可以(Flask源码中有这种写法,大家写代码不推荐这样写)。

class Foo(object):
 
    def __init__(self):
        self.__num = 123
        self.age = 19
 
    def __msg(self):
        print(1234)
 
 
obj = Foo()
print(obj.age)
print(obj._Foo__num)
obj._Foo__msg()

成员是否可以作为独立的功能暴露给外部,让外部调用并使用。

  • 可以,公有。
  • 不可以,内部其他放的一个辅助,私有。

3.对象嵌套

在基于面向对象进行编程时,对象之间可以存在各种各样的关系,例如:组合、关联、依赖等(Java中的称呼),用大白话来说就是各种嵌套。

情景一:

class Student(object):
    """ 学生类 """
 
    def __init__(self, name, age):
        self.name = name
        self.age = age
 
    def message(self):
        data = "我是一名学生,我叫:{},我今年{}岁".format(self.name, self.age)
        print(data)
 
s1 = Student("华青水上", 19)
s2 = Student("殊途同归", 19)
s3 = Student("春花秋月", 19)
 
 
 
class Classes(object):
    """ 班级类 """
 
    def __init__(self, title):
        self.title = title
        self.student_list = []
 
    def add_student(self, stu_object):
        self.student_list.append(stu_object)
 
    def add_students(self, stu_object_list):
        for stu in stu_object_list:
            self.add_student(stu)
 
    def show_members(self):
        for item in self.student_list:
            # print(item)
            item.message()
 
c1 = Classes("三年二班")
c1.add_student(s1)
c1.add_students([s2, s3])
 
print(c1.title)
print(c1.student_list)

情景二:

class Student(object):
    """ 学生类 """
 
    def __init__(self, name, age, class_object):
        self.name = name
        self.age = age
        self.class_object = class_object
 
    def message(self):
        data = "我是一名{}班的学生,我叫:{},我今年{}岁".format(self.class_object.title, self.name, self.age)
        print(data)
 
 
class Classes(object):
    """ 班级类 """
 
    def __init__(self, title):
        self.title = title
 
 
c1 = Classes("Python全栈")
c2 = Classes("Linux云计算")
 
 
user_object_list = [
    Student("华青水上", 19, c1),
    Student("殊途同归", 19, c1),
    Student("春花秋月", 19, c2)
]
 
for obj in user_object_list:
    print(obj.name,obj.age, obj.class_object.title)

情景三:

class Student(object):
    """ 学生类 """
 
    def __init__(self, name, age, class_object):
        self.name = name
        self.age = age
        self.class_object = class_object
 
    def message(self):
        data = "我是一名{}班的学生,我叫:{},我今年{}岁".format(self.class_object.title, self.name, self.age)
        print(data)
 
 
class Classes(object):
    """ 班级类 """
 
    def __init__(self, title, school_object):
        self.title = title
        self.school_object = school_object
 
 
class School(object):
    """ 学校类 """
 
    def __init__(self, name):
        self.name = name
 
 
s1 = School("北京校区")
s2 = School("上海校区")
 
c1 = Classes("Python全栈", s1)
c2 = Classes("Linux云计算", s2)
 
user_object_list = [
    Student("华青水上", 19, c1),
    Student("殊途同归", 19, c1),
    Student("春花秋月", 19, c2)
]
for obj in user_object_list:
    print(obj.name, obj.class_object.title ,  obj.class_object.school_object.name)

4.特殊成员

在Python的类中存在一些特殊的方法,这些方法都是 __方法__ 格式,这种方法在内部均有特殊的含义,接下来我们来讲一些常见的特殊成员:

  • __init__,初始化方法
class Foo(object):
    def __init__(self, name):
        self.name = name
 
 
obj = Foo("华青水上")
  • __new__,构造方法
class Foo(object):
    def __init__(self, name):
        print("第二步:初始化对象,在空对象中创建数据")
        self.name = name
 
    def __new__(cls, *args, **kwargs):
        print("第一步:先创建空对象并返回")
        return object.__new__(cls)
 
 
obj = Foo("华青水上")
  • __call__
class Foo(object):
    def __call__(self, *args, **kwargs):
        print("执行call方法")
 
 
obj = Foo()
obj()
  • __str__
class Foo(object):
 
    def __str__(self):
        return "哈哈哈哈"
 
 
obj = Foo()
data = str(obj)
print(data)
  • __dict__
class Foo(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
 
 
obj = Foo("华青水上",19)
print(obj.__dict__)
  • __getitem____setitem____delitem__
class Foo(object):
 
    def __getitem__(self, item):
        pass
 
    def __setitem__(self, key, value):
        pass
 
    def __delitem__(self, key):
        pass
 
 
obj = Foo("华青水上", 19)
 
obj["x1"]
obj['x2'] = 123
del obj['x3']
  • __enter____exit__
class Foo(object):
 
    def __enter__(self):
        print("进入了")
        return 666
 
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("出去了")
 
 
obj = Foo()
with obj as data:
    print(data)

# 面试题(补充代码,实现如下功能)

class Context:
 
    def __enter__(self):
        return self        
 
    def __exit__(self, exc_type, exc_val, exc_tb):
        pass
 
    def do_something(self):      # __enter__返回self才可以调用执行do_something方法
        pass
 
 
with Context() as ctx:
    ctx.do_something()

上述面试题属于上下文管理的语法

  • __add__
class Foo(object):
    def __init__(self, name):
        self.name = name
 
    def __add__(self, other):
        return "{}-{}".format(self.name, other.name)
 
 
v1 = Foo("alex")
v2 = Foo("sb")
 
# 对象+值,内部会去执行 对象.__add__方法,并将+后面的值当做参数传递过去。
v3 = v1 + v2
print(v3)
  • __iter__

迭代器

# 迭代器类型的定义:
    1.当类中定义了 __iter__ 和 __next__ 两个方法。
    2.__iter__ 方法需要返回对象本身,即:self
    3. __next__ 方法,返回下一个数据,如果没有数据了,则需要抛出一个StopIteration的异常。
	官方文档:https://docs.python.org/3/library/stdtypes.html#iterator-types
        
# 创建 迭代器类型 :
	class IT(object):
        def __init__(self):
            self.counter = 0
 
        def __iter__(self):
            return self
 
        def __next__(self):
            self.counter += 1
            if self.counter == 3:
                raise StopIteration()
            return self.counter
 
# 根据类实例化创建一个迭代器对象:
    obj1 = IT()
    
    # v1 = obj1.__next__()
    # v2 = obj1.__next__()
    # v3 = obj1.__next__() # 抛出异常
    
    v1 = next(obj1) # obj1.__next__()
    print(v1)
 
    v2 = next(obj1)
    print(v2)
 
    v3 = next(obj1)
    print(v3)
 
 
    obj2 = IT()
    for item in obj2:  # 首先会执行迭代器对象的__iter__方法并获取返回值,一直去反复的执行 next(对象) 
        print(item)

迭代器对象支持通过next取值,如果取值结束则自动抛出StopIteration。

for循环内部在循环时,先执行__iter__方法,获取一个迭代器对象,然后不断执行的next取值(有异常StopIteration则终止循环)。

生成器

# 创建生成器函数
    def func():
        yield 1
        yield 2
    
# 创建生成器对象(内部是根据生成器类generator创建的对象),生成器类的内部也声明了:__iter__、__next__ 方法。
    obj1 = func()
    
    v1 = next(obj1)
    print(v1)
 
    v2 = next(obj1)
    print(v2)
 
    v3 = next(obj1)
    print(v3)
 
 
    obj2 = func()
    for item in obj2:
        print(item)

如果按照迭代器的规定来看,其实生成器类也是一种特殊的迭代器类(生成器也是一个中特殊的迭代器)。

可迭代对象

# 如果一个类中有__iter__方法且返回一个迭代器对象 ;则我们称以这个类创建的对象为可迭代对象。
 
class Foo(object):
    
    def __iter__(self):
        return 迭代器对象(生成器对象)
    
obj = Foo() # obj是 可迭代对象。
 
# 可迭代对象是可以使用for来进行循环,在循环的内部其实是先执行 __iter__ 方法,获取其迭代器对象,然后再在内部执行这个迭代器对象的next功能,逐步取值。
for item in obj:
    pass

可迭代对象是可以使用for来进行循环,在循环的内部其实是先执行 __iter__ 方法,获取其迭代器对象,然后再在内部执行这个迭代器对象的next功能,逐步取值。

class IT(object):
    def __init__(self):
        self.counter = 0
 
    def __iter__(self):
        return self
 
    def __next__(self):
        self.counter += 1
        if self.counter == 3:
            raise StopIteration()
        return self.counter
 
 
class Foo(object):
    def __iter__(self):
        return IT()
 
 
obj = Foo() # 可迭代对象
 
 
for item in obj: # 循环可迭代对象时,内部先执行obj.__iter__并获取迭代器对象;不断地执行迭代器对象的next方法。
    print(item)
# 基于可迭代对象&迭代器实现:自定义range
class IterRange(object):
    def __init__(self, num):
        self.num = num
        self.counter = -1
 
    def __iter__(self):
        return self
 
    def __next__(self):
        self.counter += 1
        if self.counter == self.num:
            raise StopIteration()
        return self.counter
 
 
class Xrange(object):
    def __init__(self, max_num):
        self.max_num = max_num
 
    def __iter__(self):
        return IterRange(self.max_num)
 
 
obj = Xrange(100)
 
for item in obj:
    print(item)
class Foo(object):
    def __iter__(self):
        yield 1
        yield 2
 
 
obj = Foo()
for item in obj:
    print(item)
# 基于可迭代对象&生成器 实现:自定义range
 
class Xrange(object):
    def __init__(self, max_num):
        self.max_num = max_num
 
    def __iter__(self):
        counter = 0
        while counter < self.max_num:
            yield counter
            counter += 1
 
 
obj = Xrange(100)
for item in obj:
    print(item)

常见的数据类型:

from collections.abc import Iterator, Iterable
 
v1 = [11, 22, 33]
print( isinstance(v1, Iterator) )  # false,判断是否是迭代器;判断依据是__iter__ 和 __next__。
v2 = v1.__iter__()
print( isinstance(v2, Iterator) )  # True
 
 
 
v1 = [11, 22, 33]
print( isinstance(v1, Iterable) )  # True,判断依据是是否有 __iter__且返回迭代器对象。
 
v2 = v1.__iter__()
print( isinstance(v2, Iterable) )  # True,判断依据是是否有 __iter__且返回迭代器对象。

至此,Python进阶面向对象之成员总结完毕,如有不当之处欢迎指正。

到此这篇关于Python面向对象之成员相关知识总结的文章就介绍到这了,更多相关Python成员内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Python中函数的多种格式和使用实例及小技巧
Apr 13 Python
Python3中编码与解码之Unicode与bytes的讲解
Feb 28 Python
Python+threading模块对单个接口进行并发测试
Jun 25 Python
numpy求平均值的维度设定的例子
Aug 24 Python
Python实现随机生成任意数量车牌号
Jan 21 Python
pycharm 中mark directory as exclude的用法详解
Feb 14 Python
浅析python标准库中的glob
Mar 13 Python
基于Tensorflow一维卷积用法详解
May 22 Python
Python网络爬虫四大选择器用法原理总结
Jun 01 Python
浅析Python requests 模块
Oct 09 Python
Django中和时区相关的安全问题详解
Oct 12 Python
Pytorch自定义Dataset和DataLoader去除不存在和空数据的操作
Mar 03 Python
Python面向对象之内置函数相关知识总结
Jun 24 #Python
python面向对象版学生信息管理系统
Python实现学生管理系统(面向对象版)
Jun 24 #Python
Pycharm连接远程服务器并远程调试的全过程
Python函数中的不定长参数相关知识总结
Jun 24 #Python
Django REST framework 限流功能的使用
Jun 24 #Python
Python 发送SMTP邮件的简单教程
You might like
PHP中路径问题的解决方案
2006/10/09 PHP
PHP VS ASP
2006/10/09 PHP
用PHP+java实现自动新闻滚动窗口
2006/10/09 PHP
用PHP实现浏览器点击下载TXT文档的方法详解
2013/06/02 PHP
30个php操作redis常用方法代码例子
2014/07/05 PHP
Parse正式发布开源PHP SDK
2014/08/11 PHP
php实现的pdo公共类定义与用法示例
2017/07/19 PHP
Laravel框架实现的批量删除功能示例
2019/01/16 PHP
Laravel 实现Eloquent模型分组查询并返回每个分组的数量 groupBy()
2019/10/23 PHP
基于PHP实现用户登录注册功能的详细教程
2020/08/04 PHP
通过event对象的fromElement属性解决热区设置主实体的一个bug
2008/12/22 Javascript
基于jquery的cookie的用法
2011/01/10 Javascript
js汉字转拼音实现代码
2013/02/06 Javascript
javascript setinterval 的正确语法如何书写
2014/06/17 Javascript
jQuery插件制作之全局函数用法实例
2015/06/01 Javascript
javascript中SetInterval与setTimeout的定时器用法
2015/08/24 Javascript
input file上传 图片预览功能实例代码
2016/10/25 Javascript
详解Vuex中mapState的具体用法
2017/09/28 Javascript
vue组件(全局,局部,动态加载组件)
2018/09/02 Javascript
extract-text-webpack-plugin用法详解
2019/02/14 Javascript
VueCli4项目配置反向代理proxy的方法步骤
2020/05/17 Javascript
vue相关配置文件详解及多环境配置详细步骤
2020/05/19 Javascript
ES6函数和数组用法实例分析
2020/05/23 Javascript
python一键升级所有pip package的方法
2017/01/16 Python
Django学习笔记之Class-Based-View
2017/02/15 Python
Python简单操作sqlite3的方法示例
2017/03/22 Python
使用python绘制3维正态分布图的方法
2018/12/29 Python
对python numpy.array插入一行或一列的方法详解
2019/01/29 Python
利用python中的matplotlib打印混淆矩阵实例
2020/06/16 Python
python实现批量命名照片
2020/06/18 Python
用python对oracle进行简单性能测试
2020/12/05 Python
草莓巧克力:Shari’s Berries
2017/02/07 全球购物
西班牙最大的在线滑板和街头服饰商店:Fillow.net
2019/04/15 全球购物
中层竞聘演讲稿
2014/01/09 职场文书
新店开张活动方案
2014/08/24 职场文书
老人节标语大全
2014/10/08 职场文书