5

【Python】【面向对象】字段&方法

 3 years ago
source link: https://www.guofei.site/2017/10/08/field&method.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

【Python】【面向对象】字段&方法

2017年10月08日

Author: Guofei

文章归类: 设计模式 ,文章编号: 1002


版权声明:本文作者是郭飞。转载随意,但需要标明原文链接,并通知本人
原文链接:https://www.guofei.site/2017/10/08/field&method.html

Edit

字段

普通字段&静态字段

字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同,

  • 普通字段属于对象
  • 静态字段属于类
class Province:

    # 静态字段
    country='中国'

    def __init__(self, name):

        # 普通字段
        self.name = name

# 直接访问普通字段
obj = Province('河北省')
print(obj.name)

# 静态字段属于类
Province.country
obj.country # 静态字段也可以通过对象来访问
obj.country='美国' # 会创建一个新指针,因此只影响obj,不影响Province
obj2=Province()
Province.country='德国' # obj2.country会变,而obj.country不会变,因为obj已经指向一个新变量了

pythonoop1.jpg

  • 静态字段在内存中只保存一份
  • 普通字段在每个对象中都要保存一份

公有字段&私有字段

class C:
    PublicStatic = "公有静态字段"
    __PrivateStatic = "私有静态字段"

    def __init__(self):
        self.PublicDynamic = "公有动态字段"
        self.__PrivateDynamic = "私有动态字段"

    def func(self):
        print(self.PublicStatic)
        print(self.__PrivateStatic)
        print(self.PublicDynamic)
        print(self.__PrivateDynamic)


class D(C):

    def show(self):
        print(self.PublicStatic)
        # print(self.__PrivateStatic)  # 报错,子类不能访问父类的私有字段
        print(self.PublicDynamic)
        # print(self.__PrivateDynamic)  # 报错,之类不能访问父类的私有字段


C.PublicStatic  # 类可以访问公有字段
# C.__PrivateStatic  # 报错,只有类内可以访问私有字段,
# C.PublicDynamic  # 报错,动态字段属于对象,而不是类

obj = C()
obj.func()  # 类内部可以访问
obj.PublicStatic  # 静态字段属于类,对象也可以访问
obj.PublicDynamic  # 动态字段属于对象,对象可以访问,但类不能
# obj.__PrivateStatic  # 报错,只有类内可以访问
# obj.__PrivateDynamic  # 报错,只有类内可以访问

obj_son = D()
obj_son.show()  # 派生类中可以访问
obj_son.func()
  • 只有类内才能访问私有字段和私有方法
  • 子类、类外部都不能访问私有方法
  • 如果想要强制访问私有字段,可以通过 【对象._类名__私有字段明 】强制访问(如:obj._C__foo),但非常不建议这么干。

方法

类方法和静态方法

  • 普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self;
  • 类方法:由类调用; 至少一个cls参数;执行类方法时,自动将调用该方法的类复制给cls;
  • 静态方法:由类调用;无默认参数;

后两种用法,见于下面的注释

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

    def ord_func(self):
        """ 定义普通方法,至少有一个self参数 """
        print('普通方法')

    @classmethod
    def class_func(cls):
        """ 定义类方法,至少有一个cls参数
        另外,如果被继承,那么传入的cls是子类
        配合类的静态字段,可以做一些奇技淫巧
        """
        print('类方法', cls)

    @staticmethod
    def static_func():
        """ 定义静态方法 ,无默认参数
        很多时候,静态方法与独立的一个函数没什么区别
        静态方法常常用来把代码组织起来,提高可读性、可维护性
        """
        print('静态方法')


f = Foo('abc')

# 调用普通方法
f.ord_func()

# 调用类方法
Foo.class_func() # 打印了 <Foo>
f.class_func() # 打印了 <Foo>

# 调用静态方法
Foo.static_func()
f.static_func()

动态地添加方法

# operator_wapper 是一个普通的函数,在类里面这么写,可以把普通函数做成一个类方法
def operator_wapper(*wrapper_args):
    return operator(*(wrapper_args + args), **kwargs)
setattr(self, operator_name, types.MethodType(operator_wapper, self))

直接等号,缺点是不能传入self

def my_func1():
    print('my_func1')


class FOO(object):
    def func1(self):
        print(self)


foo = FOO()
foo.func1 = my_func1

类中间等号,需要传入self

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


class FOO(object):
    func1 = my_func1


foo = FOO()
foo.func1()

描述符

class FOO:
    a = 1

    def __init__(self):
        self.b = 2


FOO.__dict__  # 所有属性,包括a不包括b

foo = FOO()
foo.__dict__  # 包括b,不包括a

用点的时候,先从实例中找,如果找不到会从类属性中找。换句话说,操作符 . 封装了两种不同属性进行查找的细节。

装饰器型属性

# ############### 定义 ###############
class Goods(object):

    @property
    def price(self):
        print ('@property')

    @price.setter
    def price(self, value):
        print('@price.setter')

    @price.deleter
    def price(self):
        print('@price.deleter')

# ############### 调用 ###############
obj = Goods()

obj.price          # 会执行 @property 修饰的 price 方法,并获取此方法的返回值

obj.price = 123    # 会执行 @price.setter 修饰的 price 方法,并将  123 赋值给方法的入参

del obj.price      # 会执行 @price.deleter 修饰的 price 方法
  • 可以用来做 只读/只写特性
  • 旧版本的经典类和新式类功能有区别,新版本已经无区别。

另一种写法(不推荐)

class Foo:

    def get_bar(self):
        return 'wupeiqi'

    # *必须两个参数
    def set_bar(self, value):
        return 'set value'+value

    def del_bar(self):
        return 'wupeiqi'

    BAR = property(get_bar, set_bar,del_bar,'description...')
    #第一个参数是方法名,调用 对象.属性 时自动触发执行方法
    #第二个参数是方法名,调用 对象.属性 = XXX 时自动触发执行方法
    #第三个参数是方法名,调用 del 对象.属性 时自动触发执行方法
    #第四个参数是字符串,调用 对象.属性.__doc__ ,此参数是该属性的描述信息

obj = Foo()

obj.BAR              # 自动调用第一个参数中定义的方法:get_bar
obj.BAR = "alex"     # 自动调用第二个参数中定义的方法:set_bar方法,并将“alex”当作参数传入
del Foo.BAR          # 自动调用第三个参数中定义的方法:del_bar方法
obj.BAR.__doc__      # 自动获取第四个参数中设置的值:description...

修饰器

class Foo:
    def __get__(self,instance,owner):
        print("触发 Foo.__get__",instance,owner)
        return instance.__dict__['x']
    def __set__(self,instance,value):
        print("触发 Foo.__set__ ",instance, value)
        instance.__dict__['x'] = value
    def __delete__(self,instance):
        print("触发 Foo.__delete__ ",instance)

class Bar:
    x = Foo() # 描述符,对x对象属性的调用去找Foo对象
    def __init__(self,n):
        self.x = n

b1 = Bar(10) # 首先触发Bar的__init__函数。然后 self.x = n 触发Foo的x方法,触发Foo的set方法
print(b1.__dict__) # {'x': 10}
print(Bar.__dict__) # 类的字段,没有 {'x': 10}
b1.x = 11111111 # 触发 Foo.__set__
b1.x   # 触发 Foo.__get__
del b1.x # 触发 Foo.__delete__

参考文献

http://python.jobbole.com/82023/

http://python.jobbole.com/83747/


您的支持将鼓励我继续创作!

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK