Python 之面向对象
私有属性和方法
Python没有像C++语言或者Java语言中private 和public的语法来声明私有属性和共有属性。
默认,在Class内部,可以有属性和方法,而外部代码可以通过直接调用实例变量的方法来操作数据,也就是默认的属性和方法都是共有的。
如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线
private
protected _
不能修改继承的私有属性
示例:
class Student:
name = ""
__pid = ""
def __init__(self, name, pid):
self.name = name
self.__pid = pid
def display(self):
print(f"name: {self.name}\npid: {self.__pid}")
class PresidentStudent(Student):
def set_pid(self, pid):
self.__pid = pid
ps.display()
ps.set_pid("123")
# 实际上pid并不对发生变化
ps.display()
实例属性和类属性
Python 是动态语言( 通过代码修改源程序 ),可以对类创建的实例绑定任意的属性。
一般方法有两种:
(1)直接在类中声明
下面例子中的books,这个变量会被所有实例共享。所以在第一个实例tom中修改了books属性,同时也会修改bob的books属性
tips:注意 python 命名变量名 set(), list(), dictionary -> books NOT book_list
class Student:
books = [] # 这些类共有的东西
tom = Student()
tom.books.append("Maching leading")
bob = Student()
print(bob.books)
# re = ['Maching leading']
# tom 的书会跑到 bob 里面
(2)在的类方法中间动态绑定
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
s = Student('Gao', 30)
s.name = 'Mike'
s.ranking = 1
s.ranking
# 增加一个没有的属性
属性限制 slots
当我们定义了一个class,创建了一个class的实例后,我们可以给该实例绑定任何属性和方法,这就是动态语言的灵活性。
但是有时候我们希望我们定义的类,在后续不能随心所欲的绑定属性。这时需要定义 slots 方法
class Student:
__slots__ = ['name', 'age', 'school']
tom = Student()
tom.ranking = 0
# AttributeError: 'Student' object has no attribute 'ranking'
加保险实例:
class ProdAgent:
__slots__ = ['length', 'height', 'weight']
def __init__(self, length, height, weight):
self.length = length
self.height = height
self.weight = weight
def product(self):
_product = 1
for attr in self.__dir__():
if attr.startswith('__'):
continue
if attr == "product":
continue
_product *= getattr(self, attr, 1)
return _product
agent = ProdAgent(12, 1700, 6500)
agent.product()
# 如果不加入属性限制,增加 agent.color = 'red', 执行这句 _product *= getattr(self, attr, 1) 会得到好多 red
# redredredredredredredredredredredredredredredredredredredredredredredredredredredredredredredredredred
属性装饰器 @property @classmethod @staticmethod
property 是个神奇的装饰器,它可以用来保护一个属性,不被外部任意地修改;还可以用来作为动态的属性方法
# 保护属性
class Student:
def __init__(self, name, age):
self.name = name
self._age = age
@property
def age(self):
return self._age
tom = Student("tom", 20)
tom.name = "tom_modified"
print(tom.age) # 你可以读
# property的属性是不允许被直接修改的
tom.age = 21 # 但是你不能直接修改
# AttributeError: can't set attribute
使用 setter 修改
# 但是可以通过定义 setter 方法来允许属性被修改
class Student2():
def __init__(self, name, age):
self.name = name
self._age = age
self._age_modified_time = 0
@property
def age(self):
return self._age
@age.setter
def age(self, a):
self._age = a # how to assign this variable
self._age_modified_time += 1 # 修改的次数
tom = Student2("tom", 20)
tom.name = "tom_modified"
print(tom.age)
# ----------- #
tom.age = 21
print(tom.age)
# 20
# 21
调用 class 对象的时候,见过很多,if name == ‘main‘ 这是必须的么?
主函数调用执行语句
self == object this
classmethod 是用来指定一个类的方法为类方法,一般要调用一个类定义的方法需要通过实例化出一个实例来进行调用,但是 classmethod 允许类的某个方法直接被调用,常用与工厂模式。
class Student:
name = ""
class Agent:
@classmethod # first usage
def modify_name(cls, obj):
obj.name += "(modified)"
tom = Student()
tom.name = "tom"
print(tom.name)
# 直接调用类,不需要进行实例化
Agent.modify_name(tom)
print(tom.name)
class Student:
initialed_num = 0
def __init__(self, name, age):
self.name = name
self.age = age
self.initialed_num = 1
Student.initialed_num += 1
def say(self):
print('I am {}'.format(self.name))
@classmethod
def say_we_have(cls):
print('I am {}'.format(str(cls)))
print('We have {} people'.format(cls.initialed_num))
# self.initial -> Student.initial
# 增删改查 不用类本身的属性 staticmethod 声明为普通方法
@staticmethod
def check(something):
print('checking', something)
mike = Student('Mike', 20)
jhon = Student('Jhon', 30)
mike.say_we_have()
# I am <class '__main__.Student'>
# We have 2 people
多重继承
除了从一个父类继承外,Python允许从多个父类继承,称为多重继承。
举个简单的例子,如示例代码1,C同时继承了A,和B的属性。示例2中优先继承了A的属性。
这种方法也常用在工厂模式中。
class A:
def a(self):
print("a of a")
class B:
def b(self):
print("b of b")
class C(A,B):
pass
c = C()
c.a()
c.b()
# res
# a of a
# b of b
例题:假设在处理数据流程中,一般的处理流程为:数据清洗 -> 去重 -> 计算 -> 入库
但是对于不同的数据源可能数据清晰和去重不一样,如A数据源需要清晰方法A,去重方法A;B数据源需要清洗方法B,去重方法B;C数据源需要清洗方法A,去重方法B;
对于这样的流程我们可以抽象成这样的结构
class CleanerA:
def clean(self):
print("clean by A")
class CleanerB:
def clean(self):
print("clean by B")
class DropDuplicatesA:
def drop(self):
print("drop by A")
class DropDuplicatesB:
def drop(self):
print("drop by B")
class ProcessAgent():
def clean(self):
pass
def drop(self):
pass
def process(self):
print("processing")
def run(self):
self.clean()
self.drop()
self.process()
class ProcessorA(CleanerA, DropDuplicatesA, ProcessAgent):
pass
class ProcessorB(CleanerB, DropDuplicatesB, ProcessAgent):
pass
class ProcessorC(CleanerA, DropDuplicatesB, ProcessAgent):
pass
a = ProcessorA()
a.run()
print('*'*8)
b = ProcessorB()
b.run()
print('*'*8)
c = ProcessorC()
c.run()
# res
# clean by A
# drop by A
# processing
# ********
# clean by B
# drop by B
# processing
# ********
# clean by A
# drop by B
# processing
类装饰器、属性装饰器
装饰器有好多种写法,一般常用的三种:函数装饰器、类装饰器、属性装饰器。
假设在做测试的时候需要汇报不同的bug,于是不同的Bug有对应不同的类。 但是需要在每个Bug类初始化时候做一些事情,这里就可以用到类的装饰器
类的装饰器其实与普通的装饰器也很类似,不同在于返回的是类对象
同样属性装饰器与一般装饰器类似,只是要主要的是参数需要多加一个实例
同样我们用Bug的例子,我们需要在装饰的方法上都打印个 “Wraning!”
def bug_warpper(func):
def func_warp(instance, *args, **kwargs):
print("waring!!! connect to host server!")
return func(instance, *args, **kwargs)
return func_warp
class Bug:
@bug_warpper
def __init__(self):
pass
@bug_warpper
def output(self):
return "output"
bug = Bug()
bug.output()
# res
# waring!!! connect to host server!
# waring!!! connect to host server!
# 'output'
重载运算符
class Hero:
def __init__(self, name, age, attact):
self.name = name
self.age = age
self.attact = attact
def __add__(self, another_hero):
new_name = '-'.join([self.name, another_hero.name])
new_age = max(self.age, another_hero.age)
new_attact = self.attact + another_hero.attact
new_hero = Hero(new_name, new_age, new_attact)
return new_hero
def __repr__(self):
return 'I am: {}, with age: {}, attact-> {}'.format(self.name, self.age, self.attact)
def __len__(self):
return len(self.name)
请多多指教。
文章标题:Python 之面向对象
本文作者:顺强
发布时间:2019-09-04, 23:59:00
原始链接:http://shunqiang.ml/python-python-object/版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。