No.20类成员&修饰符

No.20

今日概要

  • 类成员
  • 成员修饰符

内容回顾和补充

三大特性

  • 封装

    • 函数封装到类

    • 数据封装到对象

      class Foo:
          def __init__(self, name, age)
          	self.name = name
          	self.age = age
      obj = Foo('alex', 18)
      
  • 继承

  • 多态

内容详细

1.成员

    • 类变量
    • 绑定方法
    • 类方法
    • 静态方法
    • 属性
  • 实例(对象)
    • 实例变量

1.1实例变量

class Foo:
    def __init__(self,name):
        self.name = name
    def info(self):
        pass
obj1 = Foo('alex')
obj2 = Foo('eric')

1.2类变量

class Foo:
    city = '北京'

    def __init__(self, name):
        self.name = name

    def func(self):
        pass


obj1 = Foo('李杰')
obj2 = Foo('女神')
print(obj1.name)
print(obj2.name)
# Python中对象可以取类的变量,其它语言是谁的变量就谁去取。
print(Foo.city)  # 其它语言只能这么取
print(obj1.city) # python可以对象取(这么写不太规范) 
print(obj2.city) # python可以对象取

  • 定义:写在类的下一级,和方法同一级。

  • 访问:

    类.类变量名称
    对象.类变量名称   # Python中可以
    
  • 面试题

    class Base:
        x = 1
        
    obj = Base()
    print(obj.x) # 先在对象中找,没有再去类中找。
    obj.y = 123 # 在对象中添加了一个y=123的变量。
    obj.x = 123 # 在对象中添加了一个y=123的变量,不能赋值类中的变量。
    Base.x = 666 # 在类中修改了变量的值。
    
    class Base:
        x = 1
    class Foo(Base):
        pass
    
    print(Base.x)
    print(Foo.x)
    
    Base.x = 666
    print(Base.x)
    print(Foo.x)
    
    Foo.x = 999
    print(Base.x)
    print(Foo.x)
    
    class Parent:
        x = 1
    class Child1(Parent):
        pass
    class Child2(Parent):
        pass
    
    print(Parent.x, Child1.x, Child2.x)
    
    Child1.x = 2
    print(Parent.x, Child1.x, Child2.x)
    
    Child2.x = 3
    print(Parent.x, Child1.x, Child2.x)
    
    # 类不能找对象的变量
    class Parent:
        x = 1
    class Child(Parent):
        pass
    
    obj = Child()
    print(obj.x)
    obj.x = 2  # Child类的obj对象中创造一个变量
    print(Child.x) # Child类中没有变量依旧去父类找
    


    总结:找变量时优先找自己,自己没有找类 或 基类;修改或赋值只能在自己的内部设置。

1.3绑定方法(普通方法)

  • 定义:至少有一个self参数。
  • 执行:先创建对象,由对象.方法调用。
class Foo:
    def func(self,a,b):
        print(a,b)
        
obj = Foo()
obj.func(1,2)
# 建议按下面格式写,不会浪费对象空间。
class Foo:
    def __init__(self):
        self.name = 666

    def func(self, a, b):
        print(self.name, a, b)

1.4静态方法

  • 定义:
    • @staticmethod 装饰器
    • 参数无限制
  • 执行:
    • 类.静态方法名()
    • 对象.静态方法名()(不推荐)
# 不需要通过类创建对象封装数据来使用的方法
class Foo:
    def __init__(self):
        self.name = 666

    def func(self, a, b):  # 绑定方法 会用到对象中封装的数据
        print(self.name,a, b)

    @staticmethod  # 静态方法 可以不用传参数
    def f1():
        print(123)

obj = Foo()
obj.func(1, 2)
Foo.f1()   # 通过类执行静态方法,可以不用创建对象。
obj.f1()   # Python中对象也可以调用静态方法,但是不推荐。

1.5类方法

  • 定义:

    • @classmethod 装饰器
    • 至少有cls参数,当前类
  • 执行:

    • 类.类方法()
    • 对象.类方法()(不推荐)
class Foo:
    def __init__(self):
        self.name = 666

    def func(self, a, b):  # 绑定方法
        print(self.name,a, b)

    @staticmethod  # 静态方法 可以不用传参数
    def f1():
        print(888)

    @classmethod  # 类方法 其它语言没有类方法 本质上和静态方法一样 无非给静态方法多传一个参数
    def f2(cls,a,b):
        print('cls是当前类',cls)
        print(a,b)

obj = Foo()
Foo.f2(1,2)
obj.f2(1,2)  # 类方法也可以通过对象调用

面试题:

# 请问 @classmethod 和 @staticmethod 的区别?

一个是类方法,一个是静态方法
定义:
类方法:用@classmethod作装饰器,且至少有一个cls参数。
静态方法:用@staticmethod作装饰器,且参数无限制。
调用:
类.方法直接调用。
对象.方法也可以调用。

1.6属性

  • 定义:
    • @property 装饰器
    • 只有一个self参数
  • 执行:
    • 对象.方法(不用加括号)
class Foo:
    def f1(self, a, b): 
        # 绑定方法
        print(a, b)

    @staticmethod              
    def f2():      '''传不传参数都无所谓'''   
        # 静态方法(参数无要求)
        print(888)

    @classmethod   '''其它语言没有类方法 本质上和静态方法一样 无非给静态方法多传一个参数'''
    def f3(cls):
        # 类方法(至少有一个cls参数)
        print('cls是当前类',cls)
        
    @property      '''变成属性被调用时不用加括号'''
    def f4(self):
    	# 属性(只能有self参数)
        print(888)
     
class Foo:
    @property      # 变成属性被调用时不用加括号 不能有其它参数
    def func(self):
        print(123)
        return 666

obj = Foo()
result = obj.func # 不用加括号
print(result)
# 属性的应用
class Page:
    def __init__(self, total_count, current_page, per_page_count=10):
        self.total_count = total_count       # 数据总个数
        self.current_page = current_page     # 查看页码
        self.per_page_count = per_page_count  # 每页数据个数
    @property
    def start_index(self):
        return (self.current_page - 1) * self.per_page_count
    @property
    def end_index(self):
    	return self.current_page * self.per_page_count
    
    
USER_LIST = []
for i in range(321):
    USER_LIST.append('alex-%s' %(i,))
    
    
# 请实现分页展示:
current_page = int(input('请输入要查看的页码:'))
p = Page(321, current_page)
data_list = USER_LIST[p.start_index:p.end_index] 
for item in data_list:
    print(item) 

2.成员修饰符

  • 公有:所有地方都能访问
  • 私有:只有自己可以访问
# 实例变量
class Foo:
    def __init__(self, name):
        #self.name = name  # 公共实例变量
        self.__name = name
    def func(self):
        print(self.__name)

obj = Foo('alex')
print(obj.__name) # 外部无法访问

obj.func()   # 内部可以访问
# 类变量
class Foo:
    __x = 1

    @staticmethod
    def fun():
        print(Foo.__x)

print(Foo.__x) # 外部无法访问
Foo.fun() # 内部可以访问
# 方法
class Foo:
    def __fun(self):
        print('msg')

    def show(self):
        self.__fun()

obj = Foo()
obj.__fun() # 外部无法访问
obj.show()  # 内部可以访问
# 继承
class Base:
    def __f1(self):
        print('Base.f1')
class Foo(Base):
    def fun(self):
        self.__f1()  # 对于父类而言子类的内部依旧还是外部

obj = Foo()
obj.__f1  # 外部无法访问
obj.fun() # 子类内部无法访问
Foo虽然是Base的子类,但是Foo内部依然无法访问Base的私有方法。

3.补充

class Foo:
    def __init__(self, num):
        self.num = num
        
lst = []
for i in range(10):
    lst.append(Foo)

for i in range(len(lst)):
    obj = lst[i](i)
    print(obj.num)

class Foo:
    def __init__(self, name):
        self.__x = name

B = Foo
obj = B('alex')
class Foo:
    def f1(self):
        print('f1')
        
    def f2(self):
        print('f2')
        
obj = Foo()
v = [obj.f1, obj.f2]
for item in v:
    item()
class Foo:
    def f1(self):
        print('f1')
        
    def f2(self):
        print('f2')
        
    def f3(self):
        v = [self.f1, self.f2]
        for item in v:
            item()
            
obj = Foo()
obj = f3()
class Account:
    def login(self):
        pass
    
    def register(self):
        pass
    
    def run(self):
        info = {'1':self.register, '2':self.login}
        choice = input('请选择')
        method = info.get(choice)
        method()
# 在Python3中这两种写法一样,因为所有的类都会默认继承object类,全部都是新式类。
class Foo:
    pass

class Foo(object):
    pass
认为object类是帮忙开辟内存的,Foo()会立即执行__init__方法,Foo类中没有此方法,系统也不报错因为object中有。

# 如果在Python2中这样定义,称其为经典类。
class Foo:
    pass

# 如果在Python2中这样定义,称其为新式类。
class Foo(object):
    pass

赠送

# 强制访问私有成员
class Foo:
    def __init__(self, name):
        self.__x = name

obj = Foo('alex')
print(obj._Foo__x) # 强制访问私有实例变量

总结

  1. 数据封装

  2. 继承关系的查找

  3. 嵌套(组合)

    class School(object):
        def __init__(self, title, addr):
            self.title = title
            self.address = addr
            
    class ClassRoom(object):
        def __init__(self, name, school_obj):
            self.name = name
            self.school = school_obj   
    s1 = School('北京', '沙河')
    s2 = School('上海', '浦东')
    s3 = School('深圳', '南山')
    
    c1 = ClassRoom('人工智能', s1)
    c1.name
    c1.school.title
    c1.school.address
    # 分割
    v = [11,22,33,{'name':'上海', 'addr':'浦东'}]
    v[0]
    v[3]['name']
    
posted @ 2020-03-19 15:25  Sco_Lunatic  阅读(106)  评论(0)    收藏  举报