欢迎来到Louis的博客

人生三从境界:昨夜西风凋碧树,独上高楼,望尽天涯路。 衣带渐宽终不悔,为伊消得人憔悴。 众里寻他千百度,蓦然回首,那人却在灯火阑珊处。
扩大
缩小

面向对象 2

类的成员

变量

实例变量(字段)

类变量(静态字段)

class Foo(object):
    country = 'china'        #类变量

    def __init__(self, name):       
        self.name = name        #实例变量
        self.age = 30          

    def func(self):
        print(Foo.country)
        print(self.name)


obj1 = Foo('zhangsan')
obj2 = Foo('lisi')
print(Foo.country)          #类变量可以直接使用类名进行调用,无需实例化对象 obj1.func() obj2.func()

类变量和实例变量的区别:

1. 定义方式不同:

  类变量必须在定义类的时候创建并赋值,程序编译后就存在内存当中了。

  实例变量必须定义在__init__构造函数中,可以通过构造函数的参数进行传参赋值,也可以直接进行赋值,定义实例变量需要在变量前加self,只有实例化对象后,实例变量才会在内存中被创建。

2.调用方式不同:

  类变量可以不用实例化对象,直接通过类名进行调用,也可以通过实例化后的对象进行调用。(在调用类变量时尽量使用类名去调用)

  实例变量必须实例化对象后,通过对象进行调用

class Foo(object):
    country = 'china'

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

    def func(self):
        print(Foo.country)
        print(self.name)


obj1 = Foo('zhangsan')
obj2 = Foo('lisi')

print(Foo.country)
print(obj1.country)      
print(obj2.country)

obj1.country = 'USK'

print(Foo.country)
print(obj1.country)
print(obj2.country)

Foo.country = 'UK'
print(Foo.country)
print(obj1.country)
print(obj2.country)

#china
#china
#china
#china
#USA
#china
#UK
#USA
#UK

这里我们说下为什么类变量也可以被对象调用,要知道无论是实例变量还是类变量都是变量,当使用对象去调用类变量时其实有一个隐式的值传递的过程,要知道实例变量在定义的时候都是前面有self的,当对象调用类变量时,然而这个对象的初始化的数据中是没有这个类变量的,那为什么还是可以成功调用呢?所以这里的调用可以理解成有一个隐式的obj.country = Foo.country 的过程,而这里的 obj.country = 'USA',相当于给obj1.country赋予了新的值,不在执行Foo.country了,下次在调用country时就优先到自己的对象中去取值,所以这就是为什么当Foo.country = 'UK'时,obj1.country的值还是USA,由于obj2.country还是引用的类变量,所以会跟着Foo.country变。

总结:

1.准则:

  实例变量(字段)访问时,使用对象访问,即: obj1.name

  类变量(静态字段)访问时,使用类方法,即: Foo.country (实在不方便时,才使用对象)

2.什么时候使用类变量

  当所有对象中有共同的字段时且要改都改要删都删时,可以将 实例变量(字段) 提取到 类变量(静态字段)

 

方法

实例方法

静态方法

类方法

class Foo(object):
    # 构造方法
    def __init__(self, name):
        self.name = name

    # 实例方法
    def func1(self):
        print(self.name)

    # 静态方法
    @staticmethod
    def func2(a, b):
        return a + b

    # 类方法
    @classmethod
    def func3(cls, a, b):
        print(cls)
        return a + b


obj = Foo('小明')
obj.func1()
print(Foo.func2(10, 20))
print(Foo.func3(100, 200))

区别:

1.定义方式:

  实例方法定义时,最少有一个参数,第一个参数必须时self,而且方法内部需要使用对象封装的值。

  静态方法定义时,方法使用@staticmethod装饰,参数可有可无,当方法内部无需使用对象封装的值的时候,就应该定义为静态方法。

  类方法定义时,方法使用@classmethod装饰,最少又一个参数,第一个参数必须是cls,属于静态方法的升级版,在需要在方法中使用到当前类的情况下定义。

2.调用方式:

  实例方法必须在对象实例化后,使用对象名进行调用。

  静态方法和类方法可以直接使用类名进行调用(建议方式),也可以使用对象名进行调用。

属性

class Foo(object):
    def __init__(self, a, b):
        self.a = a
        self.b = b

    @property
    def add(self):
        return self.a + self.b

    @property
    def mul(self):
        return self.a * self.b


obj = Foo(10, 20)
print(obj.add)
print(obj.mul)

当实例方法只有一个self参数(不需要传入其他参数),可以使用@property装饰器将该方法变成一个属性,在调用可以不在需要括号,结果为方法的返回值。

使用场景:对于简单的方法,当无需传参且有返回值时,可以使用 @property

class Show(object):
    def __init__(self, page, data_list, per_page_num=10):
        self.page = page
        self.per_page_num = per_page_num
        self.data_list = data_list

    @property
    def start(self):
        return (self.page - 1) * self.per_page_num

    @property
    def end(self):
        return (self.page - 1) * self.per_page_num + self.per_page_num

    def show_paeg(self):
        for item in self.data_list[self.start:self.end]:
            print(item)


data_list = ['alex_%s' % i for i in range(1, 901)]
while True:
    page = int(input('请输入要查看的页码:'))
    obj = Show(page, data_list)
    obj.show_paeg()
    if page == 1000:
        break
模拟分页

成员修饰符

class Foo(object):
    city = '杭州'      #公有类变量
    __country = '中国'   #私有类编
    
    def __init__(self, name, age, salary):  
        self.name = name
        self.age = age
        self.__salary = salary

    def func1(self):      #公有实例方法
        print(self.name)
        print(self.__salary)

    def __func2(self):      #私有实例方法
        print(self.name)

    @staticmethod        #公有静态方法
    def func3():
        print('python')
    
    @staticmethod        #私有静态方法
    def __func4():
        print('python')
    
    @classmethod        #公有类方法
    def func5(cls):
        print(cls)
        print('python')
    
    @classmethod        #私有类方法
    def __func6(cls):
        print(cls)
        print('python')
    
    @property          #公有属性
    def func7(self):
        return self.__salary
    
    @property          #私有属性
    def __func8(self):
        return self.name

类的所有成员在名称前面加上"__"就变成了私有成员,私有成员无法直接被外界访问,无法被子类继承。

 

类的组合/建模(嵌套)

class Collage(object):
    def __init__(self, name, addr):
        self.name = name
        self.addr = addr

    @staticmethod
    def teach():
        print('讲课')


obj1 = Collage('北大', '北京')
obj2 = Collage('浙大', '杭州')
obj3 = Collage('武大', '武汉')


class Teacher(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.school = None


t1 = Teacher('张三', 50)
t2 = Teacher('李四', 60)
t1.school = obj1
t2.school = obj2

print(t1.school.name)
print(t2.school.name)
print(t1.school.addr)
print(t2.school.addr)

当两个类之间在逻辑上有一定联系,又不是继承关系时,可以使用嵌套的方式建立两个类之间的联系。

在类中主动调用其他类的成员

在某些特定的环境下,可能有这样一种情况,需要在自己的类中调用其他类的方法,有以下两种方式

class Foo(object):
    country = '中国'

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

    def f1(self):
        print(self.name)

class Foo3(object):
    def __init__(self, name):
        self.name = name

    def f1(self):
        obj_foo = Foo(self.name)
        obj_foo.f1() 

在自己类中创建一个其他类的对象,通过这个对象来调用其类中的方法,这种适用与两个类之间没有任何联系(继承关系)时使用

还有一种情况时,子类重写父类中的方法,也就是在子类中创建和父类同名的方法时,想调用父类中的同名方法,可以用super关键字进行调用。

class Foo(object):
    country = '中国'

    def __init__(self, name, age, salary, address):
        self.name = name
        self.age = age
        self.salary = salary
        self.address = address


class Foo4(Foo):

    def f1(self):
        super().f1()
        print(self.salary)
        print(self.address)

这种情况适用子类觉得父类中的方法无法满足自己的需求时,重写父类的这个方法(定义一个跟父类同名的方法),但是父类中存在的代码又不想再写一遍了,由于继承的特性,默认是只能执行自己的方法的,如果想也执行父类中的方法,就可以用super来调用父类中的同名方法。

类中的特殊成员

class SpecialMember(object):
    country = '中国'
    """
    此类说明类中的特殊成员,下面方法中obj为类的实例化对象
    """

    def __init__(self, name):
        '''
        初始化方法,在创建对象时会执行
        :param name:
        '''
        self.name = name
        self.dic = {}

    def __call__(self, *args, **kwargs):
        '''
        obj(1,2,3,a=4,b=5)会触发此方法
        :param args:
        :param kwargs:
        :return:
        '''
        return args, kwargs

    def __getitem__(self, item):
        '''
        obj[123] 会触发此方法
        :param item:
        :return:
        '''
        return item

    def __setitem__(self, key, value):
        '''
        obj['key'] = value 会触发此方法
        :param key:
        :param value:
        :return:
        '''
        self.dic[key] = value

    def __delitem__(self, key):
        '''
        del obj[key] 会触发此方法
        :param key:
        :return:
        '''
        del self.dic[key]

    def __add__(self, other):
        '''
        obj1+obj2 会触发此方法
        :param other:
        :return:
        '''
        return self.name + other.name

    def __enter__(self):
        '''
        with obj as f: f接收此方法的返回值,会触发此方法,需要和exit一起使用。
        :return:
        '''
        print('with一个对象时会触发')
        return self.name

    def __exit__(self, exc_type, exc_val, exc_tb):
        '''
        :param exc_type:
        :param exc_val:
        :param exc_tb:
        :return:
        '''
        print('配合__enter__使用')

    def __new__(cls, *args, **kwargs):
        '''
        构造方法
        在创建类时默认继承object中的该方法,该方法会创建一个新的空对象
        :param args:
        :param kwargs:
        :return:
        '''
        return object.__new__(cls)

    def __str__(self):
        '''
        不写的话,默认是继承object中的__str__方法
        :return:
        '''
        return '123'

    def __iter__(self):
        '''
        将对象变成一个可迭代对象
        :return:
        '''
        # return iter('python')
        yield 1
        yield 1
        yield 1
        yield 1


obj1 = SpecialMember('alex')
obj2 = SpecialMember('wusir')

print(obj1(1, 2, 3, 4, 5, a=1, b=2))  # __init__ __new__

print(obj2['__getitem__'])  # __getitem__

obj1['name'] = 'alex'  # __setitem__
print(obj1.dic)
del obj1['name']  # __delitem__
print(obj1.dic)

print(obj1 + obj2)  # __add__

with obj1 as f:  # __enter__ __exit__
    print(123)
print(f)

print(obj1)  # __str__

print(obj1.__doc__)  # __doc__   不属于类特殊方法

for item in obj1:  # __iter__
    print(item)

print(obj1.__dict__)  # __dict__   获取对象所有实例变量的值

 

posted on 2018-08-28 16:36  Louiszj  阅读(123)  评论(0编辑  收藏  举报

导航